1
0
mirror of https://github.com/weechat/weechat.git synced 2026-06-29 22:36:38 +02:00

relay/api: support passing auth in sub protocol header

The API for connecting to WebSockets in browsers unfortunately doesn't
support setting any Authorization header. This means that before this
commit it was impossible to connect to the API relay from a web browser.
The only thing that can be set apart from the URL is the
Sec-WebSocket-Protocol header. Therefore this allows you to send the
auth token in this header.

This is a weird way to send auth, but it seems to be the best one that
makes it possible for browsers to connect. Kubernetes also does it this
way: https://github.com/kubernetes/kubernetes/pull/47740

Here is a post describing the different ways to make it possible for a
browser to authenticate against a websocket connection, and it also
recommends doing it this way:
https://stackoverflow.com/questions/4361173/http-headers-in-websockets-client-api/77060459#77060459

Note that when this header is used to pass auth, the client also needs
to specify the `api.weechat` sub protocol. This is because the client
and server have to agree on a sub protocol when this header is
specified, and in order to not send the fake protocol used for auth back
to the client, we require specifying the protocol `api.weechat`, which
the server then returns to the client. This is only necessary when the
Sec-WebSocket-Protocol header is used. If the Authorization header is
used for auth as before, nothing changes.
This commit is contained in:
Trygve Aaberge
2024-10-30 18:57:39 +01:00
committed by Sébastien Helleu
parent eaace4acdb
commit bd7c503e7b
3 changed files with 75 additions and 13 deletions
+47 -9
View File
@@ -560,15 +560,18 @@ relay_http_add_to_body (struct t_relay_http_request *request,
int
relay_http_get_auth_status (struct t_relay_client *client)
{
const char *auth, *client_totp, *pos;
const char *auth, *sec_websocket_protocol, *client_totp, *pos;
char *relay_password, *totp_secret, *info_totp_args, *info_totp;
char *user_pass;
int rc, length, totp_ok;
char **protocol_array;
int rc, i, length, protocol_count, use_base64url, totp_ok;
rc = 0;
relay_password = NULL;
protocol_array = NULL;
totp_secret = NULL;
user_pass = NULL;
use_base64url = 0;
relay_password = weechat_string_eval_expression (
weechat_config_string (relay_config_network_password),
@@ -589,13 +592,43 @@ relay_http_get_auth_status (struct t_relay_client *client)
if (relay_password[0])
{
auth = weechat_hashtable_get (client->http_req->headers, "authorization");
if (!auth || (weechat_strncasecmp (auth, "basic ", 6) != 0))
if (auth)
{
rc = -1;
goto end;
if (weechat_strncasecmp (auth, "basic ", 6) != 0)
{
rc = -1;
goto end;
}
pos = auth + 6;
}
else
{
sec_websocket_protocol = weechat_hashtable_get (
client->http_req->headers, "sec-websocket-protocol");
protocol_array = weechat_string_split (sec_websocket_protocol,
",", " ", 0, 0, &protocol_count);
pos = NULL;
for (i = 0; i < protocol_count; i++)
{
if (strncmp (protocol_array[i],
"base64url.bearer.authorization.weechat.", 39) == 0)
{
pos = protocol_array[i] + 39;
use_base64url = 1;
break;
}
}
if (!pos)
{
rc = -1;
goto end;
}
}
pos = auth + 6;
while (pos[0] == ' ')
{
pos++;
@@ -608,7 +641,8 @@ relay_http_get_auth_status (struct t_relay_client *client)
rc = -8;
goto end;
}
length = weechat_string_base_decode ("64", pos, user_pass);
length = weechat_string_base_decode ((use_base64url) ? "64url" : "64",
pos, user_pass);
if (length < 0)
{
rc = -2;
@@ -616,7 +650,9 @@ relay_http_get_auth_status (struct t_relay_client *client)
}
if (strncmp (user_pass, "plain:", 6) == 0)
{
switch (relay_auth_check_password_plain (client, user_pass + 6, relay_password))
switch (relay_auth_check_password_plain (client,
user_pass + 6,
relay_password))
{
case 0: /* password OK */
break;
@@ -631,7 +667,8 @@ relay_http_get_auth_status (struct t_relay_client *client)
}
else if (strncmp (user_pass, "hash:", 5) == 0)
{
switch (relay_auth_password_hash (client, user_pass + 5, relay_password))
switch (relay_auth_password_hash (client, user_pass + 5,
relay_password))
{
case 0: /* password OK */
break;
@@ -692,6 +729,7 @@ relay_http_get_auth_status (struct t_relay_client *client)
}
end:
weechat_string_free_split (protocol_array);
free (relay_password);
free (totp_secret);
free (user_pass);
+26 -4
View File
@@ -400,10 +400,12 @@ relay_websocket_parse_extensions (const char *extensions,
char *
relay_websocket_build_handshake (struct t_relay_http_request *request)
{
const char *sec_websocket_key;
const char *sec_websocket_key, *sec_websocket_protocol_request;
char *key, sec_websocket_accept[128], handshake[4096], hash[160 / 8];
char **extensions, str_window_bits[128], sec_websocket_extensions[1024];
int length, hash_size;
char **extensions, **protocol_array, str_window_bits[128];
char sec_websocket_extensions[1024];
char sec_websocket_protocol[1024];
int i, length, hash_size, protocol_count;
if (!request)
return NULL;
@@ -481,6 +483,24 @@ relay_websocket_build_handshake (struct t_relay_http_request *request)
sec_websocket_extensions[0] = '\0';
}
sec_websocket_protocol_request = weechat_hashtable_get (
request->headers, "sec-websocket-protocol");
protocol_array = weechat_string_split (sec_websocket_protocol_request,
",", " ", 0, 0, &protocol_count);
sec_websocket_protocol[0] = '\0';
for (i = 0; i < protocol_count; i++)
{
if (strcmp (protocol_array[i], WEBSOCKET_SUB_PROTOCOL_API_WEECHAT) == 0)
{
snprintf (
sec_websocket_protocol, sizeof (sec_websocket_protocol),
"Sec-WebSocket-Protocol: %s\r\n",
WEBSOCKET_SUB_PROTOCOL_API_WEECHAT);
break;
}
}
/* build the handshake (it will be sent as-is to client) */
snprintf (handshake, sizeof (handshake),
"HTTP/1.1 101 Switching Protocols\r\n"
@@ -488,9 +508,11 @@ relay_websocket_build_handshake (struct t_relay_http_request *request)
"Connection: Upgrade\r\n"
"Sec-WebSocket-Accept: %s\r\n"
"%s"
"%s"
"\r\n",
sec_websocket_accept,
sec_websocket_extensions);
sec_websocket_extensions,
sec_websocket_protocol);
return strdup (handshake);
}
+2
View File
@@ -37,6 +37,8 @@
#define WEBSOCKET_FRAME_OPCODE_PING 0x09
#define WEBSOCKET_FRAME_OPCODE_PONG 0x0A
#define WEBSOCKET_SUB_PROTOCOL_API_WEECHAT "api.weechat"
struct t_relay_client;
struct t_relay_http_request;