mirror of
https://github.com/weechat/weechat.git
synced 2026-07-07 18:23:13 +02:00
relay: allow password hash authentication in api relay, add option relay.network.time_window (issue #2066)
This commit is contained in:
+1
-1
@@ -19,7 +19,7 @@ New features::
|
||||
* core: use function util_strftimeval in evaluation of expression `date:xxx`
|
||||
* api: add support of specifier `%!` for timestamp in function util_strftimeval
|
||||
* api: add support of base64url in encode/decode functions
|
||||
* relay: add "api" protocol (HTTP REST API), add option relay.look.display_clients, change option type relay.look.auto_open_buffer to string, rename option relay.weechat.commands to relay.network.commands (issue #2066)
|
||||
* relay: add "api" protocol (HTTP REST API), add option relay.look.display_clients, change option type relay.look.auto_open_buffer to string, rename option relay.weechat.commands to relay.network.commands, add option relay.network.time_window (issue #2066)
|
||||
* relay: add support of websocket extension "permessage-deflate" (issue #1549)
|
||||
|
||||
Bug fixes::
|
||||
|
||||
@@ -38,60 +38,6 @@
|
||||
#include "relay-api-protocol.h"
|
||||
|
||||
|
||||
/*
|
||||
* Checks authentication from client.
|
||||
*
|
||||
* Returns:
|
||||
* 1: OK, client authenticated
|
||||
* 0: client NOT authenticated
|
||||
*/
|
||||
|
||||
int
|
||||
relay_api_protocol_check_auth (struct t_relay_client *client,
|
||||
struct t_relay_http_request *request)
|
||||
{
|
||||
if (client->status == RELAY_STATUS_CONNECTED)
|
||||
return 1;
|
||||
|
||||
switch (relay_http_check_auth (request))
|
||||
{
|
||||
case 0: /* OK */
|
||||
return 1;
|
||||
case -1: /* missing password */
|
||||
relay_api_msg_send_error_json (client,
|
||||
RELAY_HTTP_401_UNAUTHORIZED,
|
||||
"WWW-Authenticate: Basic realm=Password",
|
||||
RELAY_HTTP_ERROR_MISSING_PASSWORD);
|
||||
break;
|
||||
case -2: /* invalid password */
|
||||
relay_api_msg_send_error_json (client,
|
||||
RELAY_HTTP_401_UNAUTHORIZED,
|
||||
NULL,
|
||||
RELAY_HTTP_ERROR_INVALID_PASSWORD);
|
||||
break;
|
||||
case -3: /* missing TOTP */
|
||||
relay_api_msg_send_error_json (client,
|
||||
RELAY_HTTP_401_UNAUTHORIZED,
|
||||
NULL,
|
||||
RELAY_HTTP_ERROR_MISSING_TOTP);
|
||||
break;
|
||||
case -4: /* invalid TOTP */
|
||||
relay_api_msg_send_error_json (client,
|
||||
RELAY_HTTP_401_UNAUTHORIZED,
|
||||
NULL,
|
||||
RELAY_HTTP_ERROR_INVALID_TOTP);
|
||||
break;
|
||||
case -5: /* out of memory */
|
||||
relay_api_msg_send_error_json (client,
|
||||
RELAY_HTTP_503_SERVICE_UNAVAILABLE,
|
||||
NULL,
|
||||
RELAY_HTTP_ERROR_OUT_OF_MEMORY);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns value of an URL parameter as boolean (0 or 1), using a default value
|
||||
* if the parameter is not set or if it's not a valid boolean.
|
||||
@@ -677,7 +623,8 @@ relay_api_protocol_recv_http (struct t_relay_client *client,
|
||||
if (!request || RELAY_CLIENT_HAS_ENDED(client))
|
||||
return;
|
||||
|
||||
if (!relay_api_protocol_check_auth (client, request))
|
||||
if ((client->status != RELAY_STATUS_CONNECTED)
|
||||
&& !relay_http_check_auth (client, request))
|
||||
{
|
||||
relay_client_set_status (client, RELAY_STATUS_AUTH_FAILED);
|
||||
return;
|
||||
|
||||
@@ -134,7 +134,7 @@ relay_api_unhook_signals (struct t_relay_client *client)
|
||||
|
||||
void
|
||||
relay_api_recv_http (struct t_relay_client *client,
|
||||
struct t_relay_http_request *request)
|
||||
struct t_relay_http_request *request)
|
||||
{
|
||||
relay_api_protocol_recv_http (client, request);
|
||||
}
|
||||
|
||||
+172
-64
@@ -22,6 +22,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <gcrypt.h>
|
||||
|
||||
#include "../weechat-plugin.h"
|
||||
@@ -103,37 +104,28 @@ relay_auth_generate_nonce (int size)
|
||||
* Checks if password received as plain text is valid.
|
||||
*
|
||||
* Returns:
|
||||
* 1: password is valid
|
||||
* 0: password is not valid
|
||||
* 0: password is valid
|
||||
* -1: (plain-text password ("plain") is not allowed
|
||||
* -2: password is not valid
|
||||
*/
|
||||
|
||||
int
|
||||
relay_auth_check_password_plain (const char *password,
|
||||
relay_auth_check_password_plain (struct t_relay_client *client,
|
||||
const char *password,
|
||||
const char *relay_password)
|
||||
{
|
||||
if (!password || !relay_password)
|
||||
return 0;
|
||||
if (!client || !password || !relay_password)
|
||||
return -2;
|
||||
|
||||
return (strcmp (password, relay_password) == 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Authenticates with password (plain text).
|
||||
*
|
||||
* Returns:
|
||||
* 1: authentication OK
|
||||
* 0: authentication failed
|
||||
*/
|
||||
|
||||
int
|
||||
relay_auth_password (struct t_relay_client *client,
|
||||
const char *password, const char *relay_password)
|
||||
{
|
||||
if (client->password_hash_algo != RELAY_AUTH_PASSWORD_HASH_PLAIN)
|
||||
return 0;
|
||||
|
||||
return relay_auth_check_password_plain (password, relay_password);
|
||||
if (!weechat_string_match_list (
|
||||
"plain",
|
||||
(const char **)relay_config_network_password_hash_algo_list,
|
||||
1))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (strcmp (password, relay_password) == 0) ? 0 : -2;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -145,6 +137,11 @@ relay_auth_password (struct t_relay_client *client,
|
||||
*
|
||||
* salt is the salt in hexadecimal
|
||||
* hash is the hashed password with the parameters above, in hexadecimal
|
||||
*
|
||||
* If salt_hexa is not NULL, it is set with salt as hexadecimal, and the parsed
|
||||
* salt is decoded and put in salt.
|
||||
* If salt_hexa is NULL, parsed salt is considered not encoded and is put
|
||||
* directly in salt.
|
||||
*/
|
||||
|
||||
void
|
||||
@@ -155,7 +152,8 @@ relay_auth_parse_sha (const char *parameters,
|
||||
char **argv;
|
||||
int argc;
|
||||
|
||||
*salt_hexa = NULL;
|
||||
if (salt_hexa)
|
||||
*salt_hexa = NULL;
|
||||
*salt = NULL;
|
||||
*salt_size = 0;
|
||||
*hash = NULL;
|
||||
@@ -174,18 +172,27 @@ relay_auth_parse_sha (const char *parameters,
|
||||
}
|
||||
|
||||
/* parameter 1: salt */
|
||||
*salt = malloc (strlen (argv[0]) + 1);
|
||||
if (*salt)
|
||||
if (salt_hexa)
|
||||
{
|
||||
*salt_size = weechat_string_base_decode ("16", argv[0], *salt);
|
||||
if (*salt_size > 0)
|
||||
*salt_hexa = strdup (argv[0]);
|
||||
else
|
||||
*salt = malloc (strlen (argv[0]) + 1);
|
||||
if (*salt)
|
||||
{
|
||||
free (*salt);
|
||||
*salt = NULL;
|
||||
*salt_size = weechat_string_base_decode ("16", argv[0], *salt);
|
||||
if (*salt_size > 0)
|
||||
*salt_hexa = strdup (argv[0]);
|
||||
else
|
||||
{
|
||||
free (*salt);
|
||||
*salt = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*salt = strdup (argv[0]);
|
||||
if (*salt)
|
||||
*salt_size = strlen (*salt);
|
||||
}
|
||||
|
||||
/* parameter 2: the SHA256 or SHA512 hash */
|
||||
*hash = strdup (argv[1]);
|
||||
@@ -203,6 +210,11 @@ relay_auth_parse_sha (const char *parameters,
|
||||
* salt is the salt in hexadecimal
|
||||
* iterations it the number of iterations (≥ 1)
|
||||
* hash is the hashed password with the parameters above, in hexadecimal
|
||||
*
|
||||
* If salt_hexa is not NULL, it is set with salt as hexadecimal, and the parsed
|
||||
* salt is decoded and put in salt.
|
||||
* If salt_hexa is NULL, parsed salt is considered not encoded and is put
|
||||
* directly in salt.
|
||||
*/
|
||||
|
||||
void
|
||||
@@ -213,7 +225,8 @@ relay_auth_parse_pbkdf2 (const char *parameters,
|
||||
char **argv, *error;
|
||||
int argc;
|
||||
|
||||
*salt_hexa = NULL;
|
||||
if (salt_hexa)
|
||||
*salt_hexa = NULL;
|
||||
*salt = NULL;
|
||||
*salt_size = 0;
|
||||
*iterations = 0;
|
||||
@@ -233,18 +246,27 @@ relay_auth_parse_pbkdf2 (const char *parameters,
|
||||
}
|
||||
|
||||
/* parameter 1: salt */
|
||||
*salt = malloc (strlen (argv[0]) + 1);
|
||||
if (*salt)
|
||||
if (salt_hexa)
|
||||
{
|
||||
*salt_size = weechat_string_base_decode ("16", argv[0], *salt);
|
||||
if (*salt_size > 0)
|
||||
*salt_hexa = strdup (argv[0]);
|
||||
else
|
||||
*salt = malloc (strlen (argv[0]) + 1);
|
||||
if (*salt)
|
||||
{
|
||||
free (*salt);
|
||||
*salt = NULL;
|
||||
*salt_size = weechat_string_base_decode ("16", argv[0], *salt);
|
||||
if (*salt_size > 0)
|
||||
*salt_hexa = strdup (argv[0]);
|
||||
else
|
||||
{
|
||||
free (*salt);
|
||||
*salt = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*salt = strdup (argv[0]);
|
||||
if (*salt)
|
||||
*salt_size = strlen (*salt);
|
||||
}
|
||||
|
||||
/* parameter 2: iterations */
|
||||
error = NULL;
|
||||
@@ -261,7 +283,12 @@ relay_auth_parse_pbkdf2 (const char *parameters,
|
||||
/*
|
||||
* Checks if the salt received from the client is valid.
|
||||
*
|
||||
* It is valid if both conditions are true:
|
||||
* For "api" protocol, it is valid if both conditions are true:
|
||||
* 1. the salt is a valid integer (unix timestamp)
|
||||
* 2. the timestamp value is current timestamp (or +/- seconds, according to
|
||||
* the option relay.network.time_window)
|
||||
*
|
||||
* For other protocols, it is valid if both conditions are true:
|
||||
* 1. the salt is longer than the server nonce, so it means it includes a
|
||||
* client nonce
|
||||
* 2. the salt begins with the server nonce (client->nonce)
|
||||
@@ -272,8 +299,31 @@ relay_auth_parse_pbkdf2 (const char *parameters,
|
||||
*/
|
||||
|
||||
int
|
||||
relay_auth_check_salt (struct t_relay_client *client, const char *salt_hexa)
|
||||
relay_auth_check_salt (struct t_relay_client *client,
|
||||
const char *salt_hexa, const char *salt, int salt_size)
|
||||
{
|
||||
long number;
|
||||
int time_window;
|
||||
char *error;
|
||||
time_t time_now;
|
||||
|
||||
if (!client)
|
||||
return 0;
|
||||
|
||||
if (client->protocol == RELAY_PROTOCOL_API)
|
||||
{
|
||||
if (!salt || (salt_size < 1))
|
||||
return 0;
|
||||
error = NULL;
|
||||
number = strtol (salt, &error, 10);
|
||||
if (!error || error[0])
|
||||
return 0;
|
||||
time_now = time (NULL);
|
||||
time_window = weechat_config_integer (relay_config_network_time_window);
|
||||
return ((number >= time_now - time_window)
|
||||
&& (number <= time_now + time_window)) ? 1 : 0;
|
||||
}
|
||||
|
||||
return (salt_hexa
|
||||
&& client->nonce
|
||||
&& (strlen (salt_hexa) > strlen (client->nonce))
|
||||
@@ -370,8 +420,11 @@ relay_auth_check_hash_pbkdf2 (const char *hash_pbkdf2_algo,
|
||||
* Authenticates with password hash.
|
||||
*
|
||||
* Returns:
|
||||
* 1: authentication OK
|
||||
* 0: authentication failed
|
||||
* 0: authentication OK
|
||||
* -1: invalid hash algorithm
|
||||
* -2: invalid salt
|
||||
* -3: invalid number of iterations
|
||||
* -4: invalid password (hash)
|
||||
*/
|
||||
|
||||
int
|
||||
@@ -387,40 +440,83 @@ relay_auth_password_hash (struct t_relay_client *client,
|
||||
|
||||
str_hash_algo = NULL;
|
||||
|
||||
/* no authentication supported at all? */
|
||||
if (client->password_hash_algo < 0)
|
||||
/* no authentication supported at all with weechat protocol? */
|
||||
if ((client->protocol == RELAY_PROTOCOL_WEECHAT)
|
||||
&& (client->password_hash_algo < 0))
|
||||
{
|
||||
rc = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!hashed_password || !relay_password)
|
||||
{
|
||||
rc = -4;
|
||||
goto end;
|
||||
}
|
||||
|
||||
pos_hash = strchr (hashed_password, ':');
|
||||
if (!pos_hash)
|
||||
{
|
||||
rc = -4;
|
||||
goto end;
|
||||
}
|
||||
|
||||
str_hash_algo = weechat_strndup (hashed_password,
|
||||
pos_hash - hashed_password);
|
||||
if (!str_hash_algo)
|
||||
{
|
||||
rc = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
pos_hash++;
|
||||
|
||||
hash_algo = relay_auth_password_hash_algo_search (str_hash_algo);
|
||||
|
||||
if (hash_algo != client->password_hash_algo)
|
||||
if (hash_algo < 0)
|
||||
{
|
||||
rc = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* only algo negotiated in handshake is allowed for protocol "weechat" */
|
||||
if ((client->protocol == RELAY_PROTOCOL_WEECHAT)
|
||||
&& (hash_algo != client->password_hash_algo))
|
||||
{
|
||||
rc = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* only algos matching allowed algos are allowed for protocol "api" */
|
||||
if ((client->protocol == RELAY_PROTOCOL_API)
|
||||
&& (!weechat_string_match_list (
|
||||
relay_auth_password_hash_algo_name[hash_algo],
|
||||
(const char **)relay_config_network_password_hash_algo_list,
|
||||
1)))
|
||||
{
|
||||
rc = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
salt_hexa = NULL;
|
||||
|
||||
switch (hash_algo)
|
||||
{
|
||||
case RELAY_AUTH_PASSWORD_HASH_SHA256:
|
||||
case RELAY_AUTH_PASSWORD_HASH_SHA512:
|
||||
relay_auth_parse_sha (pos_hash, &salt_hexa, &salt, &salt_size,
|
||||
&hash_sha);
|
||||
if (relay_auth_check_salt (client, salt_hexa)
|
||||
&& relay_auth_check_hash_sha (str_hash_algo, salt, salt_size,
|
||||
hash_sha, relay_password))
|
||||
relay_auth_parse_sha (
|
||||
pos_hash,
|
||||
(client->protocol == RELAY_PROTOCOL_API) ? NULL : &salt_hexa,
|
||||
&salt,
|
||||
&salt_size,
|
||||
&hash_sha);
|
||||
if (!relay_auth_check_salt (client, salt_hexa, salt, salt_size))
|
||||
{
|
||||
rc = 1;
|
||||
rc = -2;
|
||||
}
|
||||
else if (!relay_auth_check_hash_sha (str_hash_algo, salt, salt_size,
|
||||
hash_sha, relay_password))
|
||||
{
|
||||
rc = -4;;
|
||||
}
|
||||
if (salt_hexa)
|
||||
free (salt_hexa);
|
||||
@@ -432,15 +528,26 @@ relay_auth_password_hash (struct t_relay_client *client,
|
||||
case RELAY_AUTH_PASSWORD_HASH_PBKDF2_SHA256:
|
||||
case RELAY_AUTH_PASSWORD_HASH_PBKDF2_SHA512:
|
||||
hash_pbkdf2_algo = strdup (str_hash_algo + 7);
|
||||
relay_auth_parse_pbkdf2 (pos_hash, &salt_hexa, &salt, &salt_size,
|
||||
&iterations, &hash_pbkdf2);
|
||||
if ((iterations == client->password_hash_iterations)
|
||||
&& relay_auth_check_salt (client, salt_hexa)
|
||||
&& relay_auth_check_hash_pbkdf2 (hash_pbkdf2_algo, salt,
|
||||
salt_size, iterations,
|
||||
hash_pbkdf2, relay_password))
|
||||
relay_auth_parse_pbkdf2 (
|
||||
pos_hash,
|
||||
(client->protocol == RELAY_PROTOCOL_API) ? NULL : &salt_hexa,
|
||||
&salt,
|
||||
&salt_size,
|
||||
&iterations,
|
||||
&hash_pbkdf2);
|
||||
if (iterations != weechat_config_integer (relay_config_network_password_hash_iterations))
|
||||
{
|
||||
rc = 1;
|
||||
rc = -3;
|
||||
}
|
||||
else if (!relay_auth_check_salt (client, salt_hexa, salt, salt_size))
|
||||
{
|
||||
rc = -2;
|
||||
}
|
||||
else if (!relay_auth_check_hash_pbkdf2 (hash_pbkdf2_algo, salt,
|
||||
salt_size, iterations,
|
||||
hash_pbkdf2, relay_password))
|
||||
{
|
||||
rc = -4;
|
||||
}
|
||||
if (hash_pbkdf2_algo)
|
||||
free (hash_pbkdf2_algo);
|
||||
@@ -452,6 +559,7 @@ relay_auth_password_hash (struct t_relay_client *client,
|
||||
free (hash_pbkdf2);
|
||||
break;
|
||||
case RELAY_NUM_PASSWORD_HASH_ALGOS:
|
||||
rc = -4;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,11 +37,9 @@ extern char *relay_auth_password_hash_algo_name[];
|
||||
|
||||
extern int relay_auth_password_hash_algo_search (const char *name);
|
||||
extern char *relay_auth_generate_nonce (int size);
|
||||
extern int relay_auth_check_password_plain (const char *password,
|
||||
extern int relay_auth_check_password_plain (struct t_relay_client *client,
|
||||
const char *password,
|
||||
const char *relay_password);
|
||||
extern int relay_auth_password (struct t_relay_client *client,
|
||||
const char *password,
|
||||
const char *relay_password);
|
||||
extern void relay_auth_parse_sha (const char *parameters,
|
||||
char **salt_hexa,
|
||||
char **salt,
|
||||
@@ -53,8 +51,6 @@ extern void relay_auth_parse_pbkdf2 (const char *parameters,
|
||||
int *salt_size,
|
||||
int *iterations,
|
||||
char **hash);
|
||||
extern int relay_auth_check_salt (struct t_relay_client *client,
|
||||
const char *salt_hexa);
|
||||
extern int relay_auth_check_hash_sha (const char *hash_algo,
|
||||
const char *salt,
|
||||
int salt_size,
|
||||
|
||||
@@ -1391,8 +1391,6 @@ relay_client_new (int sock, const char *address, struct t_relay_server *server)
|
||||
(const char **)relay_config_network_password_hash_algo_list,
|
||||
1);
|
||||
new_client->password_hash_algo = (plain_text_password) ? 0 : -1;
|
||||
new_client->password_hash_iterations = weechat_config_integer (
|
||||
relay_config_network_password_hash_iterations);
|
||||
new_client->listen_start_time = server->start_time;
|
||||
new_client->start_time = time (NULL);
|
||||
new_client->end_time = 0;
|
||||
@@ -1665,12 +1663,6 @@ relay_client_new_with_infolist (struct t_infolist *infolist)
|
||||
new_client->password_hash_algo = weechat_infolist_integer (infolist, "password_hash_algo");
|
||||
else
|
||||
new_client->password_hash_algo = RELAY_AUTH_PASSWORD_HASH_PLAIN;
|
||||
/* "password_hash_iterations" is new in WeeChat 2.9 */
|
||||
if (weechat_infolist_search_var (infolist, "password_hash_iterations"))
|
||||
new_client->password_hash_iterations = weechat_infolist_integer (infolist, "password_hash_iterations");
|
||||
else
|
||||
new_client->password_hash_iterations = weechat_config_integer (
|
||||
relay_config_network_password_hash_iterations);
|
||||
new_client->listen_start_time = weechat_infolist_time (infolist, "listen_start_time");
|
||||
new_client->start_time = weechat_infolist_time (infolist, "start_time");
|
||||
new_client->end_time = weechat_infolist_time (infolist, "end_time");
|
||||
@@ -2102,8 +2094,6 @@ relay_client_add_to_infolist (struct t_infolist *infolist,
|
||||
return 0;
|
||||
if (!weechat_infolist_new_var_integer (ptr_item, "password_hash_algo", client->password_hash_algo))
|
||||
return 0;
|
||||
if (!weechat_infolist_new_var_integer (ptr_item, "password_hash_iterations", client->password_hash_iterations))
|
||||
return 0;
|
||||
if (!weechat_infolist_new_var_time (ptr_item, "listen_start_time", client->listen_start_time))
|
||||
return 0;
|
||||
if (!weechat_infolist_new_var_time (ptr_item, "start_time", client->start_time))
|
||||
@@ -2188,7 +2178,6 @@ relay_client_print_log ()
|
||||
ptr_client->password_hash_algo,
|
||||
(ptr_client->password_hash_algo >= 0) ?
|
||||
relay_auth_password_hash_algo_name[ptr_client->password_hash_algo] : "");
|
||||
weechat_log_printf (" password_hash_iterations. : %d", ptr_client->password_hash_iterations);
|
||||
weechat_log_printf (" listen_start_time . . . . : %lld", (long long)ptr_client->listen_start_time);
|
||||
weechat_log_printf (" start_time. . . . . . . . : %lld", (long long)ptr_client->start_time);
|
||||
weechat_log_printf (" end_time. . . . . . . . . : %lld", (long long)ptr_client->end_time);
|
||||
|
||||
@@ -119,7 +119,6 @@ struct t_relay_client
|
||||
/* example: server for irc protocol */
|
||||
char *nonce; /* nonce used in salt of hashed pwd */
|
||||
int password_hash_algo; /* password hash algo (negotiated) */
|
||||
int password_hash_iterations; /* password hash iterations */
|
||||
time_t listen_start_time; /* when listening started */
|
||||
time_t start_time; /* time of client connection */
|
||||
time_t end_time; /* time of client disconnection */
|
||||
|
||||
@@ -81,6 +81,7 @@ struct t_config_option *relay_config_network_nonce_size = NULL;
|
||||
struct t_config_option *relay_config_network_password = NULL;
|
||||
struct t_config_option *relay_config_network_password_hash_algo = NULL;
|
||||
struct t_config_option *relay_config_network_password_hash_iterations = NULL;
|
||||
struct t_config_option *relay_config_network_time_window = NULL;
|
||||
struct t_config_option *relay_config_network_tls_cert_key = NULL;
|
||||
struct t_config_option *relay_config_network_tls_priorities = NULL;
|
||||
struct t_config_option *relay_config_network_totp_secret = NULL;
|
||||
@@ -1370,6 +1371,13 @@ relay_config_init ()
|
||||
"if your CPU is slow"),
|
||||
NULL, 1, 1000000, "100000", NULL, 0,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
relay_config_network_time_window = weechat_config_new_option (
|
||||
relay_config_file, relay_config_section_network,
|
||||
"time_window", "integer",
|
||||
N_("number of seconds to allow before and after the current time "
|
||||
"for salted password in api protocol"),
|
||||
NULL, 0, 256, "5", NULL, 0,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
relay_config_network_tls_cert_key = weechat_config_new_option (
|
||||
relay_config_file, relay_config_section_network,
|
||||
"tls_cert_key", "string",
|
||||
|
||||
@@ -53,6 +53,7 @@ extern struct t_config_option *relay_config_network_nonce_size;
|
||||
extern struct t_config_option *relay_config_network_password;
|
||||
extern struct t_config_option *relay_config_network_password_hash_algo;
|
||||
extern struct t_config_option *relay_config_network_password_hash_iterations;
|
||||
extern struct t_config_option *relay_config_network_time_window;
|
||||
extern struct t_config_option *relay_config_network_tls_cert_key;
|
||||
extern struct t_config_option *relay_config_network_tls_priorities;
|
||||
extern struct t_config_option *relay_config_network_totp_secret;
|
||||
|
||||
+121
-51
@@ -31,6 +31,7 @@
|
||||
|
||||
#include "../weechat-plugin.h"
|
||||
#include "relay.h"
|
||||
#include "relay-auth.h"
|
||||
#include "relay-client.h"
|
||||
#include "relay-config.h"
|
||||
#include "relay-http.h"
|
||||
@@ -514,7 +515,7 @@ relay_http_add_to_body (struct t_relay_http_request *request,
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks if authentication is OK.
|
||||
* Gets authentication status according to headers in the request.
|
||||
*
|
||||
* Returns:
|
||||
* 0: authentication OK (password + TOTP if enabled)
|
||||
@@ -522,11 +523,15 @@ relay_http_add_to_body (struct t_relay_http_request *request,
|
||||
* -2: invalid password
|
||||
* -3: missing TOTP
|
||||
* -4: invalid TOTP
|
||||
* -5: out of memory
|
||||
* -5: invalid hash algorithm
|
||||
* -6: invalid salt
|
||||
* -7: invalid number of iterations (PBKDF2)
|
||||
* -8: out of memory
|
||||
*/
|
||||
|
||||
int
|
||||
relay_http_check_auth (struct t_relay_http_request *request)
|
||||
relay_http_get_auth_status (struct t_relay_client *client,
|
||||
struct t_relay_http_request *request)
|
||||
{
|
||||
const char *auth, *client_totp, *pos;
|
||||
char *relay_password, *totp_secret, *info_totp_args, *info_totp;
|
||||
@@ -538,6 +543,15 @@ relay_http_check_auth (struct t_relay_http_request *request)
|
||||
totp_secret = NULL;
|
||||
user_pass = NULL;
|
||||
|
||||
relay_password = weechat_string_eval_expression (
|
||||
weechat_config_string (relay_config_network_password),
|
||||
NULL, NULL, NULL);
|
||||
if (!relay_password)
|
||||
{
|
||||
rc = -8;
|
||||
goto end;
|
||||
}
|
||||
|
||||
auth = weechat_hashtable_get (request->headers, "authorization");
|
||||
if (!auth || (weechat_strncasecmp (auth, "basic ", 6) != 0))
|
||||
{
|
||||
@@ -555,7 +569,7 @@ relay_http_check_auth (struct t_relay_http_request *request)
|
||||
user_pass = malloc (length + 1);
|
||||
if (!user_pass)
|
||||
{
|
||||
rc = -5;
|
||||
rc = -8;
|
||||
goto end;
|
||||
}
|
||||
length = weechat_string_base_decode ("64", pos, user_pass);
|
||||
@@ -564,23 +578,43 @@ relay_http_check_auth (struct t_relay_http_request *request)
|
||||
rc = -2;
|
||||
goto end;
|
||||
}
|
||||
if (strncmp (user_pass, "weechat:", 8) != 0)
|
||||
if (strncmp (user_pass, "plain:", 6) == 0)
|
||||
{
|
||||
rc = -2;
|
||||
goto end;
|
||||
switch (relay_auth_check_password_plain (client, user_pass + 6, relay_password))
|
||||
{
|
||||
case 0: /* password OK */
|
||||
break;
|
||||
case -1: /* "plain" is not allowed */
|
||||
rc = -5;
|
||||
goto end;
|
||||
case -2: /* invalid password */
|
||||
default:
|
||||
rc = -2;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
relay_password = weechat_string_eval_expression (
|
||||
weechat_config_string (relay_config_network_password),
|
||||
NULL, NULL, NULL);
|
||||
|
||||
if (!relay_password)
|
||||
else if (strncmp (user_pass, "hash:", 5) == 0)
|
||||
{
|
||||
rc = -5;
|
||||
goto end;
|
||||
switch (relay_auth_password_hash (client, user_pass + 5, relay_password))
|
||||
{
|
||||
case 0: /* password OK */
|
||||
break;
|
||||
case -1: /* invalid hash algorithm */
|
||||
rc = -5;
|
||||
goto end;
|
||||
case -2: /* invalid salt */
|
||||
rc = -6;
|
||||
goto end;
|
||||
case -3: /* invalid iterations */
|
||||
rc = -7;
|
||||
goto end;
|
||||
case -4: /* invalid password */
|
||||
default:
|
||||
rc = -2;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp (user_pass + 8, relay_password) != 0)
|
||||
else
|
||||
{
|
||||
rc = -2;
|
||||
goto end;
|
||||
@@ -631,6 +665,69 @@ end:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks authentication in HTTP request.
|
||||
*
|
||||
* Returns:
|
||||
* 1: authentication OK
|
||||
* 0: authentication failed
|
||||
*/
|
||||
|
||||
int
|
||||
relay_http_check_auth (struct t_relay_client *client,
|
||||
struct t_relay_http_request *request)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = relay_http_get_auth_status (client, request);
|
||||
switch (rc)
|
||||
{
|
||||
case 0: /* authentication OK */
|
||||
break;
|
||||
case -1: /* missing password */
|
||||
relay_http_send_error_json (client, RELAY_HTTP_401_UNAUTHORIZED,
|
||||
NULL,
|
||||
RELAY_HTTP_ERROR_MISSING_PASSWORD);
|
||||
break;
|
||||
case -2: /* invalid password */
|
||||
relay_http_send_error_json (client, RELAY_HTTP_401_UNAUTHORIZED,
|
||||
NULL,
|
||||
RELAY_HTTP_ERROR_INVALID_PASSWORD);
|
||||
break;
|
||||
case -3: /* missing TOTP */
|
||||
relay_http_send_error_json (client, RELAY_HTTP_401_UNAUTHORIZED,
|
||||
NULL,
|
||||
RELAY_HTTP_ERROR_MISSING_TOTP);
|
||||
break;
|
||||
case -4: /* invalid TOTP */
|
||||
relay_http_send_error_json (client, RELAY_HTTP_401_UNAUTHORIZED,
|
||||
NULL,
|
||||
RELAY_HTTP_ERROR_INVALID_TOTP);
|
||||
break;
|
||||
case -5: /* invalid hash algorithm */
|
||||
relay_http_send_error_json (client, RELAY_HTTP_401_UNAUTHORIZED,
|
||||
NULL,
|
||||
RELAY_HTTP_ERROR_INVALID_HASH_ALGO);
|
||||
break;
|
||||
case -6: /* invalid salt */
|
||||
relay_http_send_error_json (client, RELAY_HTTP_401_UNAUTHORIZED,
|
||||
NULL,
|
||||
RELAY_HTTP_ERROR_INVALID_SALT);
|
||||
break;
|
||||
case -7: /* invalid iterations */
|
||||
relay_http_send_error_json (client, RELAY_HTTP_401_UNAUTHORIZED,
|
||||
NULL,
|
||||
RELAY_HTTP_ERROR_INVALID_ITERATIONS);
|
||||
break;
|
||||
case -8: /* out of memory */
|
||||
relay_http_send_error_json (client, RELAY_HTTP_401_UNAUTHORIZED,
|
||||
NULL,
|
||||
RELAY_HTTP_ERROR_OUT_OF_MEMORY);
|
||||
break;
|
||||
}
|
||||
return (rc == 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Processes HTTP websocket request.
|
||||
*/
|
||||
@@ -681,41 +778,14 @@ relay_http_process_websocket (struct t_relay_client *client)
|
||||
/* handshake from client is valid, auth is mandatory for "api" protocol */
|
||||
if (client->protocol == RELAY_PROTOCOL_API)
|
||||
{
|
||||
switch (relay_http_check_auth (client->http_req))
|
||||
if (relay_http_check_auth (client, client->http_req))
|
||||
{
|
||||
case 0: /* authentication OK */
|
||||
relay_client_set_status (client, RELAY_STATUS_CONNECTED);
|
||||
break;
|
||||
case -1: /* missing password */
|
||||
relay_http_send_error_json (client, RELAY_HTTP_401_UNAUTHORIZED,
|
||||
NULL,
|
||||
RELAY_HTTP_ERROR_MISSING_PASSWORD);
|
||||
relay_client_set_status (client, RELAY_STATUS_AUTH_FAILED);
|
||||
return;
|
||||
case -2: /* invalid password */
|
||||
relay_http_send_error_json (client, RELAY_HTTP_401_UNAUTHORIZED,
|
||||
NULL,
|
||||
RELAY_HTTP_ERROR_INVALID_PASSWORD);
|
||||
relay_client_set_status (client, RELAY_STATUS_AUTH_FAILED);
|
||||
return;
|
||||
case -3: /* missing TOTP */
|
||||
relay_http_send_error_json (client, RELAY_HTTP_401_UNAUTHORIZED,
|
||||
NULL,
|
||||
RELAY_HTTP_ERROR_MISSING_TOTP);
|
||||
relay_client_set_status (client, RELAY_STATUS_AUTH_FAILED);
|
||||
return;
|
||||
case -4: /* invalid TOTP */
|
||||
relay_http_send_error_json (client, RELAY_HTTP_401_UNAUTHORIZED,
|
||||
NULL,
|
||||
RELAY_HTTP_ERROR_INVALID_TOTP);
|
||||
relay_client_set_status (client, RELAY_STATUS_AUTH_FAILED);
|
||||
return;
|
||||
case -5: /* out of memory */
|
||||
relay_http_send_error_json (client, RELAY_HTTP_401_UNAUTHORIZED,
|
||||
NULL,
|
||||
RELAY_HTTP_ERROR_OUT_OF_MEMORY);
|
||||
relay_client_set_status (client, RELAY_STATUS_AUTH_FAILED);
|
||||
return;
|
||||
relay_client_set_status (client, RELAY_STATUS_CONNECTED);
|
||||
}
|
||||
else
|
||||
{
|
||||
relay_client_set_status (client, RELAY_STATUS_AUTH_FAILED);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,11 +41,15 @@ enum t_relay_client_http_status
|
||||
#define RELAY_HTTP_500_INTERNAL_SERVER_ERROR 500, "Internal Server Error"
|
||||
#define RELAY_HTTP_503_SERVICE_UNAVAILABLE 503, "Service Unvavailable"
|
||||
|
||||
#define RELAY_HTTP_ERROR_MISSING_PASSWORD "Missing password"
|
||||
#define RELAY_HTTP_ERROR_INVALID_PASSWORD "Invalid password"
|
||||
#define RELAY_HTTP_ERROR_MISSING_TOTP "Missing TOTP"
|
||||
#define RELAY_HTTP_ERROR_INVALID_TOTP "Invalid TOTP"
|
||||
#define RELAY_HTTP_ERROR_OUT_OF_MEMORY "Out of memory"
|
||||
#define RELAY_HTTP_ERROR_MISSING_PASSWORD "Missing password"
|
||||
#define RELAY_HTTP_ERROR_INVALID_PASSWORD "Invalid password"
|
||||
#define RELAY_HTTP_ERROR_MISSING_TOTP "Missing TOTP"
|
||||
#define RELAY_HTTP_ERROR_INVALID_TOTP "Invalid TOTP"
|
||||
#define RELAY_HTTP_ERROR_INVALID_HASH_ALGO "Invalid hash algorithm " \
|
||||
"(not found or not supported)"
|
||||
#define RELAY_HTTP_ERROR_INVALID_SALT "Invalid salt"
|
||||
#define RELAY_HTTP_ERROR_INVALID_ITERATIONS "Invalid number of iterations"
|
||||
#define RELAY_HTTP_ERROR_OUT_OF_MEMORY "Out of memory"
|
||||
|
||||
struct t_relay_http_request
|
||||
{
|
||||
@@ -71,7 +75,8 @@ extern void relay_http_request_reinit (struct t_relay_http_request *request);
|
||||
extern struct t_relay_http_request *relay_http_request_alloc ();
|
||||
extern int relay_http_parse_method_path (struct t_relay_http_request *request,
|
||||
const char *method_path);
|
||||
extern int relay_http_check_auth (struct t_relay_http_request *request);
|
||||
extern int relay_http_check_auth (struct t_relay_client *client,
|
||||
struct t_relay_http_request *request);
|
||||
extern void relay_http_recv (struct t_relay_client *client, const char *data);
|
||||
extern int relay_http_send (struct t_relay_client *client,
|
||||
int return_code, const char *message,
|
||||
|
||||
@@ -170,7 +170,9 @@ relay_weechat_protocol_handshake_reply (struct t_relay_client *client,
|
||||
"password_hash_algo",
|
||||
(client->password_hash_algo >= 0) ?
|
||||
relay_auth_password_hash_algo_name[client->password_hash_algo] : "");
|
||||
snprintf (string, sizeof (string), "%d", client->password_hash_iterations);
|
||||
snprintf (string, sizeof (string),
|
||||
"%d",
|
||||
weechat_config_integer (relay_config_network_password_hash_iterations));
|
||||
weechat_hashtable_set (
|
||||
hashtable,
|
||||
"password_hash_iterations",
|
||||
@@ -388,13 +390,16 @@ RELAY_WEECHAT_PROTOCOL_CALLBACK(init)
|
||||
if (strcmp (options[i], "password") == 0)
|
||||
{
|
||||
password_received = 1;
|
||||
if (relay_auth_password (client, pos, relay_password))
|
||||
if ((client->password_hash_algo == RELAY_AUTH_PASSWORD_HASH_PLAIN)
|
||||
&& (relay_auth_check_password_plain (client, pos, relay_password) == 0))
|
||||
{
|
||||
RELAY_WEECHAT_DATA(client, password_ok) = 1;
|
||||
}
|
||||
}
|
||||
else if (strcmp (options[i], "password_hash") == 0)
|
||||
{
|
||||
password_received = 1;
|
||||
if (relay_auth_password_hash (client, pos, relay_password))
|
||||
if (relay_auth_password_hash (client, pos, relay_password) == 0)
|
||||
RELAY_WEECHAT_DATA(client, password_ok) = 1;
|
||||
}
|
||||
else if (strcmp (options[i], "totp") == 0)
|
||||
|
||||
@@ -26,7 +26,16 @@ extern "C"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
#include "src/core/wee-config-file.h"
|
||||
#include "src/plugins/relay/relay.h"
|
||||
#include "src/plugins/relay/relay-auth.h"
|
||||
#include "src/plugins/relay/relay-client.h"
|
||||
#include "src/plugins/relay/relay-config.h"
|
||||
|
||||
extern int relay_auth_check_salt (struct t_relay_client *client,
|
||||
const char *salt_hexa,
|
||||
const char *salt, int salt_size);
|
||||
}
|
||||
|
||||
#define WEE_CHECK_PARSE_SHA(__parameters) \
|
||||
@@ -98,6 +107,38 @@ TEST(RelayAuth, GenerateNonce)
|
||||
free (nonce);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests functions:
|
||||
* relay_auth_check_password_plain
|
||||
*/
|
||||
|
||||
TEST(RelayAuth, CheckPasswordPlain)
|
||||
{
|
||||
struct t_relay_client *client;
|
||||
|
||||
client = (struct t_relay_client *)calloc (1, sizeof (*client));
|
||||
CHECK(client);
|
||||
client->protocol = RELAY_PROTOCOL_API;
|
||||
|
||||
/* invalid arguments */
|
||||
LONGS_EQUAL(-2, relay_auth_check_password_plain (client, NULL, NULL));
|
||||
LONGS_EQUAL(-2, relay_auth_check_password_plain (client, "abcd", NULL));
|
||||
LONGS_EQUAL(-2, relay_auth_check_password_plain (client, NULL, "password"));
|
||||
|
||||
/* wrong password */
|
||||
LONGS_EQUAL(-2, relay_auth_check_password_plain (client, "test", "password"));
|
||||
LONGS_EQUAL(-2, relay_auth_check_password_plain (client, "Password", "password"));
|
||||
|
||||
/* good password */
|
||||
LONGS_EQUAL(0, relay_auth_check_password_plain (client, "", ""));
|
||||
LONGS_EQUAL(0, relay_auth_check_password_plain (client, "password", "password"));
|
||||
|
||||
/* test with "plain" disabled */
|
||||
config_file_option_set (relay_config_network_password_hash_algo, "*,!plain", 1);
|
||||
LONGS_EQUAL(-1, relay_auth_check_password_plain (client, "password", "password"));
|
||||
config_file_option_reset (relay_config_network_password_hash_algo, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests functions:
|
||||
* relay_auth_parse_sha
|
||||
@@ -241,23 +282,53 @@ TEST(RelayAuth, ParsePbkdf2)
|
||||
|
||||
/*
|
||||
* Tests functions:
|
||||
* relay_auth_check_password_plain
|
||||
* relay_auth_check_salt
|
||||
*/
|
||||
|
||||
TEST(RelayAuth, CheckPasswordPlain)
|
||||
TEST(RelayAuth, CheckSalt)
|
||||
{
|
||||
/* invalid arguments */
|
||||
LONGS_EQUAL(0, relay_auth_check_password_plain (NULL, NULL));
|
||||
LONGS_EQUAL(0, relay_auth_check_password_plain ("abcd", NULL));
|
||||
LONGS_EQUAL(0, relay_auth_check_password_plain (NULL, "password"));
|
||||
struct t_relay_client *client;
|
||||
time_t time_now;
|
||||
char salt[128];
|
||||
|
||||
/* wrong password */
|
||||
LONGS_EQUAL(0, relay_auth_check_password_plain ("test", "password"));
|
||||
LONGS_EQUAL(0, relay_auth_check_password_plain ("Password", "password"));
|
||||
client = (struct t_relay_client *)calloc (1, sizeof (*client));
|
||||
CHECK(client);
|
||||
client->nonce = strdup ("01aa03bb");
|
||||
|
||||
/* good password */
|
||||
LONGS_EQUAL(1, relay_auth_check_password_plain ("", ""));
|
||||
LONGS_EQUAL(1, relay_auth_check_password_plain ("password", "password"));
|
||||
client->protocol = RELAY_PROTOCOL_API;
|
||||
|
||||
LONGS_EQUAL(0, relay_auth_check_salt (NULL, NULL, NULL, 0));
|
||||
LONGS_EQUAL(0, relay_auth_check_salt (client, NULL, NULL, 0));
|
||||
LONGS_EQUAL(0, relay_auth_check_salt (client, NULL, "test", 4));
|
||||
LONGS_EQUAL(0, relay_auth_check_salt (client, NULL, "1234", 4));
|
||||
|
||||
time_now = time (NULL);
|
||||
snprintf (salt, sizeof (salt), "%ld", time_now);
|
||||
LONGS_EQUAL(1, relay_auth_check_salt (client, NULL, salt, strlen (salt)));
|
||||
time_now = time (NULL) - 2;
|
||||
snprintf (salt, sizeof (salt), "%ld", time_now);
|
||||
LONGS_EQUAL(1, relay_auth_check_salt (client, NULL, salt, strlen (salt)));
|
||||
time_now = time (NULL) + 2;
|
||||
snprintf (salt, sizeof (salt), "%ld", time_now);
|
||||
LONGS_EQUAL(1, relay_auth_check_salt (client, NULL, salt, strlen (salt)));
|
||||
time_now = time (NULL) - 10;
|
||||
snprintf (salt, sizeof (salt), "%ld", time_now);
|
||||
LONGS_EQUAL(0, relay_auth_check_salt (client, NULL, salt, strlen (salt)));
|
||||
|
||||
client->protocol = RELAY_PROTOCOL_WEECHAT;
|
||||
|
||||
LONGS_EQUAL(0, relay_auth_check_salt (NULL, NULL, NULL, 0));
|
||||
LONGS_EQUAL(0, relay_auth_check_salt (client, NULL, NULL, 0));
|
||||
LONGS_EQUAL(0, relay_auth_check_salt (client, NULL, "test", 4));
|
||||
LONGS_EQUAL(0, relay_auth_check_salt (client, NULL, "1234", 4));
|
||||
|
||||
LONGS_EQUAL(0, relay_auth_check_salt (client, "01aa", "\x01\xaa", 2));
|
||||
LONGS_EQUAL(0, relay_auth_check_salt (client, "01aa03bb", "\x01\xaa\x03\xbb", 4));
|
||||
LONGS_EQUAL(1, relay_auth_check_salt (client, "01aa03bbcc", "\x01\xaa\x03\xbb\xcc", 5));
|
||||
LONGS_EQUAL(1, relay_auth_check_salt (client, "01AA03BBCC", "\x01\xaa\x03\xbb\xcc", 5));
|
||||
|
||||
free (client->nonce);
|
||||
free (client);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -403,3 +474,13 @@ TEST(RelayAuth, CheckHashPbkdf2)
|
||||
"f53326c3729ffd12",
|
||||
"password"));
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests functions:
|
||||
* relay_auth_password_hash
|
||||
*/
|
||||
|
||||
TEST(RelayAuth, PasswordHash)
|
||||
{
|
||||
/* TODO: write tests */
|
||||
}
|
||||
|
||||
@@ -28,10 +28,15 @@ extern "C"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
#include <gcrypt.h>
|
||||
#include "src/core/wee-config-file.h"
|
||||
#include "src/core/wee-crypto.h"
|
||||
#include "src/core/wee-hashtable.h"
|
||||
#include "src/core/wee-hook.h"
|
||||
#include "src/core/wee-string.h"
|
||||
#include "src/plugins/relay/relay.h"
|
||||
#include "src/plugins/relay/relay-client.h"
|
||||
#include "src/plugins/relay/relay-config.h"
|
||||
#include "src/plugins/relay/relay-http.h"
|
||||
#include "src/plugins/relay/relay-websocket.h"
|
||||
@@ -45,6 +50,8 @@ extern int relay_http_parse_header (struct t_relay_http_request *request,
|
||||
const char *header);
|
||||
extern void relay_http_add_to_body (struct t_relay_http_request *request,
|
||||
char **partial_message);
|
||||
extern int relay_http_get_auth_status (struct t_relay_client *client,
|
||||
struct t_relay_http_request *request);
|
||||
extern char *relay_http_compress (struct t_relay_http_request *request,
|
||||
const char *data, int data_size,
|
||||
int *compressed_size,
|
||||
@@ -589,51 +596,244 @@ TEST(RelayHttp, AddToBody)
|
||||
|
||||
/*
|
||||
* Tests functions:
|
||||
* relay_http_check_auth
|
||||
* relay_http_get_auth_status
|
||||
*/
|
||||
|
||||
TEST(RelayHttp, CheckAuth)
|
||||
TEST(RelayHttp, GetAuthStatus)
|
||||
{
|
||||
struct t_relay_client *client;
|
||||
struct t_relay_http_request *request;
|
||||
char *totp, *totp2;
|
||||
const char *good_pwd = "secret_password";
|
||||
const char *bad_pwd = "test";
|
||||
char *totp, *totp2, salt[1024], salt_pass[1024], hash[1024], hash_hexa[2048];
|
||||
char auth[4096], auth_base64[4096], auth_header[8192];
|
||||
time_t time_now;
|
||||
int hash_size;
|
||||
|
||||
config_file_option_set (relay_config_network_password, "secret_password", 1);
|
||||
config_file_option_set (relay_config_network_password, good_pwd, 1);
|
||||
|
||||
client = (struct t_relay_client *)calloc (1, sizeof (*client));
|
||||
CHECK(client);
|
||||
client->protocol = RELAY_PROTOCOL_API;
|
||||
|
||||
request = relay_http_request_alloc ();
|
||||
CHECK(request);
|
||||
|
||||
/* test password */
|
||||
LONGS_EQUAL(-1, relay_http_check_auth (request));
|
||||
LONGS_EQUAL(-1, relay_http_get_auth_status (client, request));
|
||||
hashtable_set (request->headers, "authorization", "Basic ");
|
||||
LONGS_EQUAL(-2, relay_http_check_auth (request));
|
||||
LONGS_EQUAL(-2, relay_http_get_auth_status (client, request));
|
||||
hashtable_set (request->headers, "authorization", "Basic \u26c4");
|
||||
LONGS_EQUAL(-2, relay_http_check_auth (request));
|
||||
/* set invalid user/password: "weechat:test" */
|
||||
hashtable_set (request->headers, "authorization", "Basic d2VlY2hhdDp0ZXN0");
|
||||
LONGS_EQUAL(-2, relay_http_check_auth (request));
|
||||
/* set valid user/password: "weechat:secret_password" */
|
||||
LONGS_EQUAL(-2, relay_http_get_auth_status (client, request));
|
||||
|
||||
/* test invalid plain-text password ("test") */
|
||||
hashtable_set (request->headers, "authorization", "Basic cGxhaW46dGVzdA==");
|
||||
LONGS_EQUAL(-2, relay_http_get_auth_status (client, request));
|
||||
|
||||
/* test valid plain-text password ("secret_password") */
|
||||
hashtable_set (request->headers,
|
||||
"authorization", "Basic d2VlY2hhdDpzZWNyZXRfcGFzc3dvcmQ");
|
||||
LONGS_EQUAL(0, relay_http_check_auth (request));
|
||||
"authorization",
|
||||
"Basic cGxhaW46c2VjcmV0X3Bhc3N3b3Jk");
|
||||
LONGS_EQUAL(0, relay_http_get_auth_status (client, request));
|
||||
|
||||
/* test invalid hash: "SHA128" */
|
||||
time_now = time (NULL);
|
||||
snprintf (salt_pass, sizeof (salt_pass),
|
||||
"%ld%s", time_now, bad_pwd);
|
||||
LONGS_EQUAL(1, weecrypto_hash (salt_pass, strlen (salt_pass),
|
||||
GCRY_MD_SHA256, hash, &hash_size));
|
||||
LONGS_EQUAL(64, string_base_encode ("16", hash, hash_size, hash_hexa));
|
||||
snprintf (auth, sizeof (auth),
|
||||
"hash:sha128:%ld:%s",
|
||||
time_now,
|
||||
hash_hexa);
|
||||
string_base_encode ("64", auth, strlen (auth), auth_base64);
|
||||
snprintf (auth_header, sizeof (auth_header), "Basic %s", auth_base64);
|
||||
hashtable_set (request->headers, "authorization", auth_header);
|
||||
LONGS_EQUAL(-5, relay_http_get_auth_status (client, request));
|
||||
|
||||
/* test invalid password hashed with SHA256: "test" */
|
||||
time_now = time (NULL);
|
||||
snprintf (salt_pass, sizeof (salt_pass),
|
||||
"%ld%s", time_now, bad_pwd);
|
||||
LONGS_EQUAL(1, weecrypto_hash (salt_pass, strlen (salt_pass),
|
||||
GCRY_MD_SHA256, hash, &hash_size));
|
||||
LONGS_EQUAL(64, string_base_encode ("16", hash, hash_size, hash_hexa));
|
||||
snprintf (auth, sizeof (auth),
|
||||
"hash:sha256:%ld:%s",
|
||||
time_now,
|
||||
hash_hexa);
|
||||
string_base_encode ("64", auth, strlen (auth), auth_base64);
|
||||
snprintf (auth_header, sizeof (auth_header), "Basic %s", auth_base64);
|
||||
hashtable_set (request->headers, "authorization", auth_header);
|
||||
LONGS_EQUAL(-2, relay_http_get_auth_status (client, request));
|
||||
|
||||
/* test invalid password hashed with SHA512: "test" */
|
||||
time_now = time (NULL);
|
||||
snprintf (salt_pass, sizeof (salt_pass),
|
||||
"%ld%s", time_now, bad_pwd);
|
||||
LONGS_EQUAL(1, weecrypto_hash (salt_pass, strlen (salt_pass),
|
||||
GCRY_MD_SHA512, hash, &hash_size));
|
||||
LONGS_EQUAL(128, string_base_encode ("16", hash, hash_size, hash_hexa));
|
||||
snprintf (auth, sizeof (auth),
|
||||
"hash:sha512:%ld:%s",
|
||||
time_now,
|
||||
hash_hexa);
|
||||
string_base_encode ("64", auth, strlen (auth), auth_base64);
|
||||
snprintf (auth_header, sizeof (auth_header), "Basic %s", auth_base64);
|
||||
hashtable_set (request->headers, "authorization", auth_header);
|
||||
LONGS_EQUAL(-2, relay_http_get_auth_status (client, request));
|
||||
|
||||
/* test valid password hashed with SHA256: "secret_password" but too old time (salt) */
|
||||
time_now = time (NULL) - 10;
|
||||
snprintf (salt_pass, sizeof (salt_pass),
|
||||
"%ld%s", time_now, good_pwd);
|
||||
LONGS_EQUAL(1, weecrypto_hash (salt_pass, strlen (salt_pass),
|
||||
GCRY_MD_SHA256, hash, &hash_size));
|
||||
LONGS_EQUAL(64, string_base_encode ("16", hash, hash_size, hash_hexa));
|
||||
snprintf (auth, sizeof (auth),
|
||||
"hash:sha256:%ld:%s",
|
||||
time_now,
|
||||
hash_hexa);
|
||||
string_base_encode ("64", auth, strlen (auth), auth_base64);
|
||||
snprintf (auth_header, sizeof (auth_header), "Basic %s", auth_base64);
|
||||
hashtable_set (request->headers, "authorization", auth_header);
|
||||
LONGS_EQUAL(-6, relay_http_get_auth_status (client, request));
|
||||
|
||||
/* test valid password hashed with SHA256: "secret_password" */
|
||||
time_now = time (NULL);
|
||||
snprintf (salt_pass, sizeof (salt_pass),
|
||||
"%ld%s", time_now, good_pwd);
|
||||
LONGS_EQUAL(1, weecrypto_hash (salt_pass, strlen (salt_pass),
|
||||
GCRY_MD_SHA256, hash, &hash_size));
|
||||
LONGS_EQUAL(64, string_base_encode ("16", hash, hash_size, hash_hexa));
|
||||
snprintf (auth, sizeof (auth),
|
||||
"hash:sha256:%ld:%s",
|
||||
time_now,
|
||||
hash_hexa);
|
||||
string_base_encode ("64", auth, strlen (auth), auth_base64);
|
||||
snprintf (auth_header, sizeof (auth_header), "Basic %s", auth_base64);
|
||||
hashtable_set (request->headers, "authorization", auth_header);
|
||||
LONGS_EQUAL(0, relay_http_get_auth_status (client, request));
|
||||
|
||||
/* test valid password hashed with SHA512: "secret_password" */
|
||||
time_now = time (NULL);
|
||||
snprintf (salt_pass, sizeof (salt_pass),
|
||||
"%ld%s", time_now, good_pwd);
|
||||
LONGS_EQUAL(1, weecrypto_hash (salt_pass, strlen (salt_pass),
|
||||
GCRY_MD_SHA512, hash, &hash_size));
|
||||
LONGS_EQUAL(128, string_base_encode ("16", hash, hash_size, hash_hexa));
|
||||
snprintf (auth, sizeof (auth),
|
||||
"hash:sha512:%ld:%s",
|
||||
time_now,
|
||||
hash_hexa);
|
||||
string_base_encode ("64", auth, strlen (auth), auth_base64);
|
||||
snprintf (auth_header, sizeof (auth_header), "Basic %s", auth_base64);
|
||||
hashtable_set (request->headers, "authorization", auth_header);
|
||||
LONGS_EQUAL(0, relay_http_get_auth_status (client, request));
|
||||
|
||||
/* test invalid number of iterations */
|
||||
time_now = time (NULL);
|
||||
snprintf (salt, sizeof (salt), "%ld", time_now);
|
||||
LONGS_EQUAL(1, weecrypto_hash_pbkdf2 (good_pwd, strlen (good_pwd),
|
||||
GCRY_MD_SHA256,
|
||||
salt, strlen (salt),
|
||||
123,
|
||||
hash, &hash_size));
|
||||
LONGS_EQUAL(64, string_base_encode ("16", hash, hash_size, hash_hexa));
|
||||
snprintf (auth, sizeof (auth),
|
||||
"hash:pbkdf2+sha256:%ld:123:%s",
|
||||
time_now,
|
||||
hash_hexa);
|
||||
string_base_encode ("64", auth, strlen (auth), auth_base64);
|
||||
snprintf (auth_header, sizeof (auth_header), "Basic %s", auth_base64);
|
||||
hashtable_set (request->headers, "authorization", auth_header);
|
||||
LONGS_EQUAL(-7, relay_http_get_auth_status (client, request));
|
||||
|
||||
/* test invalid password hashed with PBKDF2+SHA256: "test" */
|
||||
time_now = time (NULL);
|
||||
snprintf (salt, sizeof (salt), "%ld", time_now);
|
||||
LONGS_EQUAL(1, weecrypto_hash_pbkdf2 (bad_pwd, strlen (bad_pwd),
|
||||
GCRY_MD_SHA256,
|
||||
salt, strlen (salt),
|
||||
100000,
|
||||
hash, &hash_size));
|
||||
LONGS_EQUAL(64, string_base_encode ("16", hash, hash_size, hash_hexa));
|
||||
snprintf (auth, sizeof (auth),
|
||||
"hash:pbkdf2+sha256:%ld:100000:%s",
|
||||
time_now,
|
||||
hash_hexa);
|
||||
string_base_encode ("64", auth, strlen (auth), auth_base64);
|
||||
snprintf (auth_header, sizeof (auth_header), "Basic %s", auth_base64);
|
||||
hashtable_set (request->headers, "authorization", auth_header);
|
||||
LONGS_EQUAL(-2, relay_http_get_auth_status (client, request));
|
||||
|
||||
/* test valid password hashed with PBKDF2+SHA256: "secret_password" */
|
||||
time_now = time (NULL);
|
||||
snprintf (salt, sizeof (salt), "%ld", time_now);
|
||||
LONGS_EQUAL(1, weecrypto_hash_pbkdf2 (good_pwd, strlen (good_pwd),
|
||||
GCRY_MD_SHA256,
|
||||
salt, strlen (salt),
|
||||
100000,
|
||||
hash, &hash_size));
|
||||
LONGS_EQUAL(64, string_base_encode ("16", hash, hash_size, hash_hexa));
|
||||
snprintf (auth, sizeof (auth),
|
||||
"hash:pbkdf2+sha256:%ld:100000:%s",
|
||||
time_now,
|
||||
hash_hexa);
|
||||
string_base_encode ("64", auth, strlen (auth), auth_base64);
|
||||
snprintf (auth_header, sizeof (auth_header), "Basic %s", auth_base64);
|
||||
hashtable_set (request->headers, "authorization", auth_header);
|
||||
LONGS_EQUAL(0, relay_http_get_auth_status (client, request));
|
||||
|
||||
/* test valid password hashed with PBKDF2+SHA512: "secret_password" */
|
||||
time_now = time (NULL);
|
||||
snprintf (salt, sizeof (salt), "%ld", time_now);
|
||||
LONGS_EQUAL(1, weecrypto_hash_pbkdf2 (good_pwd, strlen (good_pwd),
|
||||
GCRY_MD_SHA512,
|
||||
salt, strlen (salt),
|
||||
100000,
|
||||
hash, &hash_size));
|
||||
LONGS_EQUAL(128, string_base_encode ("16", hash, hash_size, hash_hexa));
|
||||
snprintf (auth, sizeof (auth),
|
||||
"hash:pbkdf2+sha512:%ld:100000:%s",
|
||||
time_now,
|
||||
hash_hexa);
|
||||
string_base_encode ("64", auth, strlen (auth), auth_base64);
|
||||
snprintf (auth_header, sizeof (auth_header), "Basic %s", auth_base64);
|
||||
hashtable_set (request->headers, "authorization", auth_header);
|
||||
LONGS_EQUAL(0, relay_http_get_auth_status (client, request));
|
||||
|
||||
/* test missing/invalid TOTP */
|
||||
config_file_option_set (relay_config_network_totp_secret, "secretbase32", 1);
|
||||
config_file_option_set (relay_config_network_totp_window, "1", 1);
|
||||
LONGS_EQUAL(-3, relay_http_check_auth (request));
|
||||
LONGS_EQUAL(-3, relay_http_get_auth_status (client, request));
|
||||
totp = hook_info_get (NULL, "totp_generate", "secretbase32");
|
||||
CHECK(totp);
|
||||
totp2 = strdup (totp);
|
||||
totp2[0] = (totp2[0] == '1') ? '2' : '1';
|
||||
hashtable_set (request->headers, "x-weechat-totp", totp2);
|
||||
LONGS_EQUAL(-4, relay_http_check_auth (request));
|
||||
LONGS_EQUAL(-4, relay_http_get_auth_status (client, request));
|
||||
hashtable_set (request->headers, "x-weechat-totp", totp);
|
||||
LONGS_EQUAL(0, relay_http_check_auth (request));
|
||||
LONGS_EQUAL(0, relay_http_get_auth_status (client, request));
|
||||
free (totp);
|
||||
free (totp2);
|
||||
config_file_option_reset (relay_config_network_totp_secret, 1);
|
||||
config_file_option_reset (relay_config_network_totp_window, 1);
|
||||
|
||||
config_file_option_reset (relay_config_network_password, 1);
|
||||
|
||||
relay_http_request_free (request);
|
||||
free (client);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests functions:
|
||||
* relay_http_check_auth
|
||||
*/
|
||||
|
||||
TEST(RelayHttp, CheckAuth)
|
||||
{
|
||||
/* TODO: write tests */
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user