Skip to content

Commit 84db738

Browse files
committed
Support SHA-256 for in-band digest auth
1 parent f6908fd commit 84db738

File tree

2 files changed

+78
-58
lines changed

2 files changed

+78
-58
lines changed

src/mg_rpc.c

+71-56
Original file line numberDiff line numberDiff line change
@@ -920,65 +920,80 @@ bool mg_rpc_check_digest_auth(struct mg_rpc_request_info *ri) {
920920
}
921921

922922
#ifdef MGOS_HAVE_MONGOOSE
923-
if (ri->auth.len > 0) {
924-
struct json_token trealm = JSON_INVALID_TOKEN,
925-
tusername = JSON_INVALID_TOKEN,
926-
tnonce = JSON_INVALID_TOKEN, tcnonce = JSON_INVALID_TOKEN,
927-
tresponse = JSON_INVALID_TOKEN;
928-
929-
if (json_scanf(ri->auth.p, ri->auth.len,
930-
"{realm: %T username %T nonce:%T cnonce:%T response:%T}",
931-
&trealm, &tusername, &tnonce, &tcnonce, &tresponse) == 5) {
932-
struct mg_str realm = mg_mk_str_n(trealm.ptr, trealm.len);
933-
struct mg_str username = mg_mk_str_n(tusername.ptr, tusername.len);
934-
struct mg_str nonce = mg_mk_str_n(tnonce.ptr, tnonce.len);
935-
struct mg_str cnonce = mg_mk_str_n(tcnonce.ptr, tcnonce.len);
936-
struct mg_str response = mg_mk_str_n(tresponse.ptr, tresponse.len);
937-
938-
LOG(LL_DEBUG, ("Got auth: Realm:%.*s, Username:%.*s, Nonce: %.*s, "
939-
"CNonce:%.*s, Response:%.*s",
940-
(int) realm.len, realm.p, (int) username.len, username.p,
941-
(int) nonce.len, nonce.p, (int) cnonce.len, cnonce.p,
942-
(int) response.len, response.p));
943-
944-
if (mg_vcmp(&realm, mgos_sys_config_get_rpc_auth_domain()) != 0) {
945-
LOG(LL_WARN,
946-
("Got auth request with different realm: expected: "
947-
"\"%s\", got: \"%.*s\"",
948-
mgos_sys_config_get_rpc_auth_domain(), (int) realm.len, realm.p));
949-
} else {
950-
FILE *htdigest_fp = fopen(mgos_sys_config_get_rpc_auth_file(), "r");
951-
952-
if (htdigest_fp == NULL) {
953-
mg_rpc_send_errorf(ri, 500, "failed to open htdigest file");
954-
ri = NULL;
955-
return false;
956-
}
957-
958-
/*
959-
* TODO(dfrank): add method to the struct mg_rpc_request_info and use
960-
* it as either method or uri
961-
*/
962-
int authenticated = mg_check_digest_auth(
963-
mg_mk_str("dummy_method"), mg_mk_str("dummy_uri"), username, cnonce,
964-
response, mg_mk_str("auth"), mg_mk_str("1"), nonce, realm,
965-
htdigest_fp);
966-
967-
fclose(htdigest_fp);
968-
969-
if (authenticated) {
970-
LOG(LL_DEBUG, ("Auth ok"));
971-
ri->authn_info.username = mg_strdup(username);
972-
return true;
973-
} else {
974-
LOG(LL_WARN, ("Invalid digest auth for user %.*s", (int) username.len,
975-
username.p));
976-
}
977-
}
923+
if (ri->auth.len == 0) {
924+
/* No auth info in the frame, it's not an error. */
925+
return true;
926+
}
927+
enum mg_auth_algo algo = MG_AUTH_ALGO_MD5;
928+
struct json_token trealm = JSON_INVALID_TOKEN, tusername = JSON_INVALID_TOKEN,
929+
tnonce = JSON_INVALID_TOKEN, tcnonce = JSON_INVALID_TOKEN,
930+
tresponse = JSON_INVALID_TOKEN, talgo = JSON_INVALID_TOKEN;
931+
json_scanf(
932+
ri->auth.p, ri->auth.len,
933+
"{realm: %T username %T nonce:%T cnonce:%T response:%T algorithm:%T}",
934+
&trealm, &tusername, &tnonce, &tcnonce, &tresponse, &talgo);
935+
struct mg_str realm = mg_mk_str_n(trealm.ptr, trealm.len);
936+
struct mg_str username = mg_mk_str_n(tusername.ptr, tusername.len);
937+
struct mg_str nonce = mg_mk_str_n(tnonce.ptr, tnonce.len);
938+
struct mg_str cnonce = mg_mk_str_n(tcnonce.ptr, tcnonce.len);
939+
struct mg_str response = mg_mk_str_n(tresponse.ptr, tresponse.len);
940+
struct mg_str algorithm = mg_mk_str_n(talgo.ptr, talgo.len);
941+
if (realm.len == 0 || username.len == 0 || nonce.len == 0 ||
942+
cnonce.len == 0 || response.len == 0) {
943+
/* Incomplete auth info is an error. */
944+
return false;
945+
}
946+
if (algorithm.len > 0) {
947+
if (mg_vcmp(&algorithm, "MD5") == 0) {
948+
algo = MG_AUTH_ALGO_MD5;
949+
} else if (mg_vcmp(&algorithm, "SHA-256") == 0) {
950+
algo = MG_AUTH_ALGO_SHA256;
978951
} else {
979-
LOG(LL_WARN, ("Not all auth parts are present, ignoring"));
952+
LOG(LL_ERROR,
953+
("Unknown auth algo '%.*s'", (int) algorithm.len, algorithm.p));
954+
return false;
980955
}
981956
}
957+
LOG(LL_DEBUG, ("Got auth: Realm:%.*s, Username:%.*s, Nonce: %.*s, "
958+
"CNonce:%.*s, Response:%.*s Algo:%d",
959+
(int) realm.len, realm.p, (int) username.len, username.p,
960+
(int) nonce.len, nonce.p, (int) cnonce.len, cnonce.p,
961+
(int) response.len, response.p, algo));
962+
if ((int) algo != mgos_sys_config_get_rpc_auth_algo()) {
963+
LOG(LL_ERROR, ("Auth algo mismatch: %d vs %d", algo,
964+
mgos_sys_config_get_rpc_auth_algo()));
965+
return false;
966+
}
967+
968+
if (mg_vcmp(&realm, mgos_sys_config_get_rpc_auth_domain()) != 0) {
969+
LOG(LL_WARN,
970+
("Got auth request with different realm: expected: "
971+
"\"%s\", got: \"%.*s\"",
972+
mgos_sys_config_get_rpc_auth_domain(), (int) realm.len, realm.p));
973+
return false;
974+
}
975+
976+
FILE *htdigest_fp = fopen(mgos_sys_config_get_rpc_auth_file(), "r");
977+
if (htdigest_fp == NULL) {
978+
mg_rpc_send_errorf(ri, 500, "failed to open password file");
979+
ri = NULL;
980+
return false;
981+
}
982+
983+
int authenticated = mg_check_digest_auth_algo(
984+
mg_mk_str("dummy_method"), mg_mk_str("dummy_uri"), username, cnonce,
985+
response, mg_mk_str("auth"), mg_mk_str("1"), nonce, realm, algo,
986+
htdigest_fp);
987+
988+
fclose(htdigest_fp);
989+
990+
if (authenticated) {
991+
LOG(LL_DEBUG, ("Auth ok, user %.*s", (int) username.len, username.p));
992+
ri->authn_info.username = mg_strdup(username);
993+
} else {
994+
LOG(LL_WARN,
995+
("Invalid digest auth for user %.*s", (int) username.len, username.p));
996+
}
982997
#endif /* MGOS_HAVE_MONGOOSE */
983998

984999
/*

src/mgos_rpc.c

+7-2
Original file line numberDiff line numberDiff line change
@@ -455,8 +455,12 @@ static bool mgos_rpc_req_prehandler(struct mg_rpc_request_info *ri,
455455
/*
456456
* RPC-specific auth domain and file are set, so check if authn info was
457457
* provided in the RPC frame.
458+
*
459+
* Note: this function returns false only if there is something wrong with
460+
* the format of the information provided, not authenotcation failure.
458461
*/
459462
if (!mg_rpc_check_digest_auth(ri)) {
463+
mg_rpc_send_errorf(ri, 400, "bad request");
460464
ri = NULL;
461465
ret = false;
462466
goto clean;
@@ -479,14 +483,15 @@ static bool mgos_rpc_req_prehandler(struct mg_rpc_request_info *ri,
479483
mg_rpc_free_request_info(ri);
480484
ri = NULL;
481485
} else {
482-
/* TODO(dfrank): implement nc properly, instead of always setting it to 1.
486+
/*
487+
* TODO(rojer): implement nc properly, instead of always setting it to 1.
483488
*/
484489
mg_rpc_send_error_jsonf(
485490
ri, 401,
486491
"{auth_type: %Q, nonce: %llu, nc: %d, realm: %Q, algorithm: %Q}",
487492
"digest", (uint64_t) mg_time(), 1,
488493
mgos_sys_config_get_rpc_auth_domain(),
489-
(mgos_sys_config_get_rpc_auth_algo() == MG_AUTH_ALGO_MD5
494+
(mgos_sys_config_get_rpc_auth_algo() == (int) MG_AUTH_ALGO_MD5
490495
? "MD5"
491496
: "SHA-256"));
492497
ri = NULL;

0 commit comments

Comments
 (0)