From 2f90e3f1eed3c68e56fcdfac04e2534d9c67be39 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Wed, 19 Mar 2025 00:07:13 +0000 Subject: [PATCH] api: Workaround Safari negligence by falling back to MD5 digest for it alone Safari only supports MD5 hashing for Digest HTTP authentication --- src/datum_api.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/datum_api.c b/src/datum_api.c index 92b446c..3aaa212 100644 --- a/src/datum_api.c +++ b/src/datum_api.c @@ -417,13 +417,26 @@ bool datum_api_check_admin_password_only(struct MHD_Connection * const connectio return false; } +static enum MHD_DigestAuthAlgorithm datum_api_pick_digest_algo(struct MHD_Connection * const connection, const bool nonce_is_stale) { + const char * const ua = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "User-Agent"); + if (strstr(ua, "AppleWebKit/") && !(strstr(ua, "Chrome/") || strstr(ua, "Brave/") || strstr(ua, "Edge/"))) { + static bool safari_warned = false; + if (!(nonce_is_stale && safari_warned)) { + DLOG_WARN("Detected login request from Apple Safari. For some reason, this browser only supports obsolete and insecure MD5 digest authentication. Login at your own risk!"); + safari_warned = true; + } + return MHD_DIGEST_ALG_MD5; + } + return MHD_DIGEST_ALG_SHA256; +} + bool datum_api_check_admin_password_httponly(struct MHD_Connection * const connection, const create_response_func_t auth_failure_response_creator) { int ret; char * const username = MHD_digest_auth_get_username(connection); const char * const realm = "DATUM Gateway"; if (username) { - ret = MHD_digest_auth_check2(connection, realm, username, datum_config.api_admin_password, 300, MHD_DIGEST_ALG_SHA256); + ret = MHD_digest_auth_check2(connection, realm, username, datum_config.api_admin_password, 300, MHD_DIGEST_ALG_AUTO); free(username); } else { ret = MHD_NO; @@ -433,8 +446,9 @@ bool datum_api_check_admin_password_httponly(struct MHD_Connection * const conne if (username && !nonce_is_stale) { DLOG_DEBUG("Wrong password in HTTP authentication"); } + const enum MHD_DigestAuthAlgorithm algo = datum_api_pick_digest_algo(connection, nonce_is_stale); struct MHD_Response * const response = auth_failure_response_creator(); - ret = MHD_queue_auth_fail_response2(connection, realm, datum_config.api_csrf_token, response, nonce_is_stale ? MHD_YES : MHD_NO, MHD_DIGEST_ALG_SHA256); + ret = MHD_queue_auth_fail_response2(connection, realm, datum_config.api_csrf_token, response, nonce_is_stale ? MHD_YES : MHD_NO, algo); MHD_destroy_response(response); return false; }