summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog.adoc2
-rw-r--r--src/plugins/relay/api/relay-api-protocol.c57
-rw-r--r--src/plugins/relay/api/relay-api.c2
-rw-r--r--src/plugins/relay/relay-auth.c234
-rw-r--r--src/plugins/relay/relay-auth.h8
-rw-r--r--src/plugins/relay/relay-client.c11
-rw-r--r--src/plugins/relay/relay-client.h1
-rw-r--r--src/plugins/relay/relay-config.c8
-rw-r--r--src/plugins/relay/relay-config.h1
-rw-r--r--src/plugins/relay/relay-http.c172
-rw-r--r--src/plugins/relay/relay-http.h17
-rw-r--r--src/plugins/relay/weechat/relay-weechat-protocol.c11
-rw-r--r--tests/unit/plugins/relay/test-relay-auth.cpp109
-rw-r--r--tests/unit/plugins/relay/test-relay-http.cpp234
14 files changed, 638 insertions, 229 deletions
diff --git a/ChangeLog.adoc b/ChangeLog.adoc
index 677da6da5..198aa428f 100644
--- a/ChangeLog.adoc
+++ b/ChangeLog.adoc
@@ -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::
diff --git a/src/plugins/relay/api/relay-api-protocol.c b/src/plugins/relay/api/relay-api-protocol.c
index f04264125..b850194f7 100644
--- a/src/plugins/relay/api/relay-api-protocol.c
+++ b/src/plugins/relay/api/relay-api-protocol.c
@@ -39,60 +39,6 @@
/*
- * 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;
diff --git a/src/plugins/relay/api/relay-api.c b/src/plugins/relay/api/relay-api.c
index a82c72e0b..158305367 100644
--- a/src/plugins/relay/api/relay-api.c
+++ b/src/plugins/relay/api/relay-api.c
@@ -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);
}
diff --git a/src/plugins/relay/relay-auth.c b/src/plugins/relay/relay-auth.c
index 76bdf35a7..a03dc0559 100644
--- a/src/plugins/relay/relay-auth.c
+++ b/src/plugins/relay/relay-auth.c
@@ -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;
-
- return (strcmp (password, relay_password) == 0) ? 1 : 0;
-}
+ if (!client || !password || !relay_password)
+ return -2;
-/*
- * 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 < 0)
+ {
+ rc = -1;
+ goto end;
+ }
- if (hash_algo != client->password_hash_algo)
+ /* 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;
}
diff --git a/src/plugins/relay/relay-auth.h b/src/plugins/relay/relay-auth.h
index 9d1158c45..dcb7801fc 100644
--- a/src/plugins/relay/relay-auth.h
+++ b/src/plugins/relay/relay-auth.h
@@ -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,
diff --git a/src/plugins/relay/relay-client.c b/src/plugins/relay/relay-client.c
index fa62d8f20..b5260700d 100644
--- a/src/plugins/relay/relay-client.c
+++ b/src/plugins/relay/relay-client.c
@@ -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);
diff --git a/src/plugins/relay/relay-client.h b/src/plugins/relay/relay-client.h
index 0afec9387..9d22f629f 100644
--- a/src/plugins/relay/relay-client.h
+++ b/src/plugins/relay/relay-client.h
@@ -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 */
diff --git a/src/plugins/relay/relay-config.c b/src/plugins/relay/relay-config.c
index b9c4422ec..148e693d6 100644
--- a/src/plugins/relay/relay-config.c
+++ b/src/plugins/relay/relay-config.c
@@ -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",
diff --git a/src/plugins/relay/relay-config.h b/src/plugins/relay/relay-config.h
index de5697341..e454ba97e 100644
--- a/src/plugins/relay/relay-config.h
+++ b/src/plugins/relay/relay-config.h
@@ -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;
diff --git a/src/plugins/relay/relay-http.c b/src/plugins/relay/relay-http.c
index a59552599..51ce00174 100644
--- a/src/plugins/relay/relay-http.c
+++ b/src/plugins/relay/relay-http.c
@@ -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;
@@ -632,6 +666,69 @@ end:
}
/*
+ * 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;
}
}
diff --git a/src/plugins/relay/relay-http.h b/src/plugins/relay/relay-http.h
index 8ed0bcd88..5716cb98d 100644
--- a/src/plugins/relay/relay-http.h
+++ b/src/plugins/relay/relay-http.h
@@ -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,
diff --git a/src/plugins/relay/weechat/relay-weechat-protocol.c b/src/plugins/relay/weechat/relay-weechat-protocol.c
index a7d47e3af..948ecd38f 100644
--- a/src/plugins/relay/weechat/relay-weechat-protocol.c
+++ b/src/plugins/relay/weechat/relay-weechat-protocol.c
@@ -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)
diff --git a/tests/unit/plugins/relay/test-relay-auth.cpp b/tests/unit/plugins/relay/test-relay-auth.cpp
index af7738093..32574b6aa 100644
--- a/tests/unit/plugins/relay/test-relay-auth.cpp
+++ b/tests/unit/plugins/relay/test-relay-auth.cpp
@@ -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) \
@@ -100,6 +109,38 @@ TEST(RelayAuth, GenerateNonce)
/*
* 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"));
-
- /* wrong password */
- LONGS_EQUAL(0, relay_auth_check_password_plain ("test", "password"));
- LONGS_EQUAL(0, relay_auth_check_password_plain ("Password", "password"));
-
- /* good password */
- LONGS_EQUAL(1, relay_auth_check_password_plain ("", ""));
- LONGS_EQUAL(1, relay_auth_check_password_plain ("password", "password"));
+ struct t_relay_client *client;
+ time_t time_now;
+ char salt[128];
+
+ client = (struct t_relay_client *)calloc (1, sizeof (*client));
+ CHECK(client);
+ client->nonce = strdup ("01aa03bb");
+
+ 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 */
+}
diff --git a/tests/unit/plugins/relay/test-relay-http.cpp b/tests/unit/plugins/relay/test-relay-http.cpp
index 64bb7b752..075e286d8 100644
--- a/tests/unit/plugins/relay/test-relay-http.cpp
+++ b/tests/unit/plugins/relay/test-relay-http.cpp
@@ -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, good_pwd, 1);
- config_file_option_set (relay_config_network_password, "secret_password", 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 */
}
/*