diff options
author | joe <joe@61a7d7f5-40b7-0310-9c16-bb0ea8cb1845> | 2007-01-06 14:27:18 +0000 |
---|---|---|
committer | joe <joe@61a7d7f5-40b7-0310-9c16-bb0ea8cb1845> | 2007-01-06 14:27:18 +0000 |
commit | 3242cbb80711ac5083a00f838396995e81678d93 (patch) | |
tree | 2a6308556d72ea8fb55fb734954d67554496de8e | |
parent | 6bdfd6d6608ea6a5c339a0529938ed68a0f7f450 (diff) | |
download | neon-3242cbb80711ac5083a00f838396995e81678d93.tar.gz |
* src/ne_auth.c (digest_challenge): Fix to fail correctly for invalid
case where stale=true is given with an initial challenge; fix to not
leak sess->nonce for a valid stale challenge.
* test/auth.c (struct digest_parms): Add stale field, enum value.
(make_digest_header): Send stale=true as appropriate.
(serve_digest): Adjust to serve challenges with stale=true.
(digest): Add test for stale=true handling.
(digest_failures): Add test for error stale=true failure case.
git-svn-id: http://svn.webdav.org/repos/projects/neon/trunk@1129 61a7d7f5-40b7-0310-9c16-bb0ea8cb1845
-rw-r--r-- | src/ne_auth.c | 46 | ||||
-rw-r--r-- | test/auth.c | 59 |
2 files changed, 75 insertions, 30 deletions
diff --git a/src/ne_auth.c b/src/ne_auth.c index c2ee89f..4e0bb72 100644 --- a/src/ne_auth.c +++ b/src/ne_auth.c @@ -1,6 +1,6 @@ /* HTTP Authentication routines - Copyright (C) 1999-2006, Joe Orton <joe@manyfish.co.uk> + Copyright (C) 1999-2007, Joe Orton <joe@manyfish.co.uk> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -625,25 +625,40 @@ static int digest_challenge(auth_session *sess, int attempt, challenge_error(errmsg, _("missing parameter in Digest challenge")); return -1; } + else if (parms->stale && sess->nonce_count == 0) { + challenge_error(errmsg, _("initial Digest challenge was stale")); + return -1; + } + else if (parms->stale && (sess->alg != parms->alg + || strcmp(sess->realm, parms->realm))) { + /* With stale=true the realm and algorithm cannot change since these + * require re-hashing H(A1) which defeats the point. */ + challenge_error(errmsg, _("stale Digest challenge with new algorithm or realm")); + return -1; + } if (!parms->stale) { - /* Forget the old session details */ - clean_session(sess); + /* Non-stale challenge: clear session and request credentials. */ + clean_session(sess); - sess->realm = ne_strdup(parms->realm); + sess->realm = ne_strdup(parms->realm); + sess->alg = parms->alg; + sess->cnonce = get_cnonce(); - /* Not a stale response: really need user authentication */ - if (get_credentials(sess, errmsg, attempt, parms, password)) { - /* Failed to get credentials */ - return -1; - } + if (get_credentials(sess, errmsg, attempt, parms, password)) { + /* Failed to get credentials */ + return -1; + } } - sess->alg = parms->alg; + else { + /* Stale challenge: accept a new nonce or opa */ + if (sess->nonce) ne_free(sess->nonce); + if (sess->opaque && parms->opaque) ne_free(sess->opaque); + } + sess->nonce = ne_strdup(parms->nonce); - sess->cnonce = get_cnonce(); - /* TODO: add domain handling. */ - if (parms->opaque != NULL) { - sess->opaque = ne_strdup(parms->opaque); /* don't strip the quotes */ + if (parms->opaque) { + sess->opaque = ne_strdup(parms->opaque); } if (parms->got_qop) { @@ -967,8 +982,7 @@ static int verify_digest_response(struct auth_request *req, auth_session *sess, /* Check for a nextnonce */ if (nextnonce != NULL) { NE_DEBUG(NE_DBG_HTTPAUTH, "auth: Found nextnonce of [%s].\n", nextnonce); - if (sess->nonce != NULL) - ne_free(sess->nonce); + ne_free(sess->nonce); sess->nonce = ne_strdup(nextnonce); sess->nonce_count = 0; } diff --git a/test/auth.c b/test/auth.c index 50dde35..39146e6 100644 --- a/test/auth.c +++ b/test/auth.c @@ -375,9 +375,11 @@ struct digest_parms { int proxy; int send_nextnonce; int num_requests; + int stale; enum digest_failure { fail_not, fail_bogus_alg, + fail_req0_stale, fail_omit_qop, fail_omit_realm, fail_omit_nonce, @@ -645,6 +647,11 @@ static char *make_digest_header(struct digest_state *state, ne_buffer_concat(buf, "opaque=\"", parms->opaque, "\", ", NULL); } + if (parms->failure == fail_req0_stale + || parms->stale == parms->num_requests) { + ne_buffer_concat(buf, "stale='true', ", NULL); + } + ne_buffer_concat(buf, "nonce=\"", state->nonce, "\"", NULL); return ne_buffer_finish(buf); @@ -670,6 +677,11 @@ static int serve_digest(ne_socket *sock, void *userdata) state.cnonce = state.digest = state.ncval = NULL; + parms->num_requests += parms->stale ? 1 : 0; + + NE_DEBUG(NE_DBG_HTTP, ">>>> Response sequence begins, %d requests.\n", + parms->num_requests); + want_header = parms->proxy ? "Proxy-Authorization" : "Authorization"; digest_hdr = NULL; got_header = dup_header; @@ -694,8 +706,19 @@ static int serve_digest(ne_socket *sock, void *userdata) ONN("no Authorization header sent", digest_hdr == NULL); CALL(verify_digest_header(&state, parms, digest_hdr)); - - if (parms->send_ainfo) { + + if (parms->num_requests == parms->stale) { + state.nonce = ne_concat("stale-", state.nonce, NULL); + state.nc = 1; + + ne_snprintf(resp, sizeof resp, + "HTTP/1.1 %d Auth Denied\r\n" + "%s\r\n" + "Content-Length: 0\r\n" "\r\n", + parms->proxy ? 407 : 401, + make_digest_header(&state, parms)); + } + else if (parms->send_ainfo) { char *ai = make_authinfo_header(&state, parms); ne_snprintf(resp, sizeof resp, @@ -714,7 +737,7 @@ static int serve_digest(ne_socket *sock, void *userdata) SEND_STRING(sock, resp); NE_DEBUG(NE_DBG_HTTP, "Handled request; %d requests remain.\n", - parms->num_requests); + parms->num_requests - 1); } while (--parms->num_requests); return OK; @@ -724,6 +747,8 @@ static int test_digest(struct digest_parms *parms) { ne_session *sess; + NE_DEBUG(NE_DBG_HTTP, ">>>> Request sequence begins.\n"); + if (parms->proxy) { sess = ne_session_create("http", "www.example.com", 80); ne_session_proxy(sess, "localhost", 7777); @@ -749,24 +774,27 @@ static int digest(void) { struct digest_parms parms[] = { /* RFC 2617-style */ - { "WallyWorld", "this-is-a-nonce", NULL, 1, 0, 0, 0, 0, 1, fail_not }, - { "WallyWorld", "this-is-also-a-nonce", "opaque-string", 1, 0, 0, 0, 0, 1, fail_not }, + { "WallyWorld", "this-is-a-nonce", NULL, 1, 0, 0, 0, 0, 1, 0, fail_not }, + { "WallyWorld", "this-is-also-a-nonce", "opaque-string", 1, 0, 0, 0, 0, 1, 0, fail_not }, /* ... with A-I */ - { "WallyWorld", "nonce-nonce-nonce", "opaque-string", 1, 1, 0, 0, 0, 1, fail_not }, + { "WallyWorld", "nonce-nonce-nonce", "opaque-string", 1, 1, 0, 0, 0, 1, 0, fail_not }, /* ... with md5-sess. */ - { "WallyWorld", "nonce-nonce-nonce", "opaque-string", 1, 1, 1, 0, 0, 1, fail_not }, + { "WallyWorld", "nonce-nonce-nonce", "opaque-string", 1, 1, 1, 0, 0, 1, 0, fail_not }, /* many requests, with changing nonces; tests for next-nonce handling bug. */ - { "WallyWorld", "this-is-a-nonce", "opaque-thingy", 1, 1, 0, 0, 1, 20, fail_not }, + { "WallyWorld", "this-is-a-nonce", "opaque-thingy", 1, 1, 0, 0, 1, 20, 0, fail_not }, + /* staleness. */ + { "WallyWorld", "this-is-a-nonce", "opaque-thingy", 1, 1, 0, 0, 0, 3, 2, fail_not }, + /* RFC 2069-style */ - { "WallyWorld", "lah-di-da-di-dah", NULL, 0, 0, 0, 0, 0, 1, fail_not }, - { "WallyWorld", "fee-fi-fo-fum", "opaque-string", 0, 0, 0, 0, 0, 1, fail_not }, - { "WallyWorld", "fee-fi-fo-fum", "opaque-string", 0, 1, 0, 0, 0, 1, fail_not }, + { "WallyWorld", "lah-di-da-di-dah", NULL, 0, 0, 0, 0, 0, 1, 0, fail_not }, + { "WallyWorld", "fee-fi-fo-fum", "opaque-string", 0, 0, 0, 0, 0, 1, 0, fail_not }, + { "WallyWorld", "fee-fi-fo-fum", "opaque-string", 0, 1, 0, 0, 0, 1, 0, fail_not }, /* Proxy auth */ - { "WallyWorld", "this-is-also-a-nonce", "opaque-string", 1, 1, 0, 0, 0, 1, fail_not }, + { "WallyWorld", "this-is-also-a-nonce", "opaque-string", 1, 1, 0, 0, 0, 1, 0, fail_not }, /* Proxy + A-I */ - { "WallyWorld", "this-is-also-a-nonce", "opaque-string", 1, 1, 0, 1, 0, 1, fail_not }, + { "WallyWorld", "this-is-also-a-nonce", "opaque-string", 1, 1, 0, 1, 0, 1, 0, fail_not }, { NULL } }; @@ -795,6 +823,7 @@ static int digest_failures(void) { fail_ai_omit_digest, "missing parameters" }, { fail_ai_omit_cnonce, "missing parameters" }, { fail_bogus_alg, "unknown algorithm" }, + { fail_req0_stale, "initial Digest challenge was stale" }, { fail_not, NULL } }; size_t n; @@ -808,6 +837,7 @@ static int digest_failures(void) parms.proxy = 0; parms.send_nextnonce = 0; parms.num_requests = 1; + parms.stale = 0; for (n = 0; fails[n].message; n++) { ne_session *sess = ne_session_create("http", "localhost", 7777); @@ -829,7 +859,8 @@ static int digest_failures(void) ne_session_destroy(sess); - if (fails[n].mode == fail_bogus_alg) { + if (fails[n].mode == fail_bogus_alg + || fails[n].mode == fail_req0_stale) { reap_server(); } else { CALL(await_server()); |