summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjoe <joe@61a7d7f5-40b7-0310-9c16-bb0ea8cb1845>2006-02-15 09:20:28 +0000
committerjoe <joe@61a7d7f5-40b7-0310-9c16-bb0ea8cb1845>2006-02-15 09:20:28 +0000
commitbb39111d683808ef4b392caee24b8f43ae6c3eeb (patch)
treed1b8a1942f1519f95bc144af68112c5f29368069
parent8508a4ecb83a2929d3f5c043e32d2ee1bc3e0541 (diff)
downloadneon-bb39111d683808ef4b392caee24b8f43ae6c3eeb.tar.gz
Merge r909 from trunk:
* test/auth.c (make_digest): Factored out from check_digest. (check_digest): Use make_digest. (make_authinfo_header): New function. (serve_digest): Add Authentication-Info handling. (test_digest): Factored out from digest_rfc2617/digest_rfc2069. (digest_rfc2617, digest_rfc2069): Use test_digest. (digest_auth_info, digest_failures): New test cases. git-svn-id: http://svn.webdav.org/repos/projects/neon/branches/0.25.x@910 61a7d7f5-40b7-0310-9c16-bb0ea8cb1845
-rw-r--r--test/auth.c193
1 files changed, 165 insertions, 28 deletions
diff --git a/test/auth.c b/test/auth.c
index d8f3069..4525acc 100644
--- a/test/auth.c
+++ b/test/auth.c
@@ -374,6 +374,16 @@ static void dup_header(char *header)
struct digest_parms {
const char *realm, *nonce;
int rfc2617;
+ int send_ainfo;
+ enum digest_failure {
+ fail_not,
+ fail_ai_bad_nc,
+ fail_ai_bad_digest,
+ fail_ai_bad_cnonce,
+ fail_ai_omit_cnonce,
+ fail_ai_omit_digest,
+ fail_ai_omit_nc
+ } failure;
};
struct digest_state {
@@ -383,12 +393,15 @@ struct digest_state {
long nc;
};
-/* Check that the response-digest matches. */
-static int check_digest(struct digest_state *state, struct digest_parms *parms)
+/* Write the request-digest into 'digest' (or response-digest if
+ * auth_info is non-zero) for given digest auth state and
+ * parameters. */
+static void make_digest(struct digest_state *state, struct digest_parms *parms,
+ int auth_info, char digest[33])
{
struct ne_md5_ctx ctx;
md5_uint32 result[4];
- char h_a1[33], h_a2[33], dig[33];
+ char h_a1[33], h_a2[33];
/* H(A1) */
ne_md5_init_ctx(&ctx);
@@ -403,7 +416,8 @@ static int check_digest(struct digest_state *state, struct digest_parms *parms)
/* H(A2) */
ne_md5_init_ctx(&ctx);
- ne_md5_process_bytes(state->method, strlen(state->method), &ctx);
+ if (!auth_info)
+ ne_md5_process_bytes(state->method, strlen(state->method), &ctx);
ne_md5_process_bytes(":", 1, &ctx);
ne_md5_process_bytes(state->uri, strlen(state->uri), &ctx);
ne_md5_finish_ctx(&ctx, result);
@@ -429,17 +443,24 @@ static int check_digest(struct digest_state *state, struct digest_parms *parms)
ne_md5_process_bytes(h_a2, strlen(h_a2), &ctx);
ne_md5_finish_ctx(&ctx, result);
- ne_md5_to_ascii((void *)result, dig);
+ ne_md5_to_ascii((void *)result, digest);
+}
+
+/* Verify that the response-digest matches expected state. */
+static int check_digest(struct digest_state *state, struct digest_parms *parms)
+{
+ char digest[33];
+
+ make_digest(state, parms, 0, digest);
NE_DEBUG(NE_DBG_HTTP, "Got digest: %s, expected: %s\n",
- state->digest, dig);
+ state->digest, digest);
- ONCMP(dig, state->digest, "Digest response", "request-digest");
+ ONCMP(digest, state->digest, "Digest response", "request-digest");
return OK;
}
-
#define DIGCMP(field, name, value) \
do { \
if (ne_strcasecmp(name, #field) == 0) { \
@@ -511,6 +532,44 @@ static int verify_digest_header(struct digest_state *state,
return OK;
}
+static char *make_authinfo_header(struct digest_state *state,
+ struct digest_parms *parms)
+{
+ ne_buffer *buf = ne_buffer_create();
+ char digest[33], *ncval, *cnonce;
+
+ if (parms->failure == fail_ai_bad_digest) {
+ strcpy(digest, "fish");
+ } else {
+ make_digest(state, parms, 1, digest);
+ }
+
+ if (parms->failure == fail_ai_bad_nc) {
+ ncval = "999";
+ } else {
+ ncval = state->ncval;
+ }
+
+ if (parms->failure == fail_ai_bad_cnonce) {
+ cnonce = "another-fish";
+ } else {
+ cnonce = state->cnonce;
+ }
+
+ if (parms->failure != fail_ai_omit_nc) {
+ ne_buffer_concat(buf, "nc=", ncval, ", ", NULL);
+ }
+ if (parms->failure != fail_ai_omit_cnonce) {
+ ne_buffer_concat(buf, "cnonce=\"", cnonce, "\", ", NULL);
+ }
+ if (parms->failure != fail_ai_omit_digest) {
+ ne_buffer_concat(buf, "rspauth=\"", digest, "\", ", NULL);
+ }
+ ne_buffer_czappend(buf, "qop=\"auth\"");
+
+ return ne_buffer_finish(buf);
+}
+
/* Server process for Digest auth handling. */
static int serve_digest(ne_socket *sock, void *userdata)
{
@@ -564,50 +623,126 @@ static int serve_digest(ne_socket *sock, void *userdata)
CALL(verify_digest_header(&state, parms, digest_hdr));
- SEND_STRING(sock, "HTTP/1.1 200 You did good\r\n"
- "Content-Length: 0\r\n" "\r\n");
+ if (parms->send_ainfo) {
+ char *ai = make_authinfo_header(&state, parms);
+
+ ne_snprintf(resp, sizeof resp,
+ "HTTP/1.1 200 Well, if you insist\r\n"
+ "Content-Length: 0\r\n"
+ "Authentication-Info: %s\r\n"
+ "\r\n", ai);
+
+ ne_free(ai);
+
+
+ } else {
+ ne_snprintf(resp, sizeof resp,
+ "HTTP/1.1 200 You did good\r\n"
+ "Content-Length: 0\r\n" "\r\n");
+ }
+
+ SEND_STRING(sock, resp);
return OK;
}
-/* Test for RFC2617-style Digest auth. */
-static int digest_rfc2617(void)
+static int test_digest(struct digest_parms *parms)
{
ne_session *sess = ne_session_create("http", "localhost", 7777);
- struct digest_parms parms;
-
- parms.realm = "WallyWorld";
- parms.nonce = "random-invented-string";
- parms.rfc2617 = 1;
ne_set_server_auth(sess, auth_cb, NULL);
- CALL(spawn_server(7777, serve_digest, &parms));
+ CALL(spawn_server(7777, serve_digest, parms));
CALL(any_2xx_request(sess, "/fish"));
ne_session_destroy(sess);
- CALL(await_server());
+ return await_server();
+}
- return OK;
+/* Test for RFC2617-style Digest auth. */
+static int digest_rfc2617(void)
+{
+ struct digest_parms parms;
+
+ parms.realm = "WallyWorld";
+ parms.nonce = "random-invented-string";
+ parms.rfc2617 = 1;
+ parms.send_ainfo = 0;
+
+ return test_digest(&parms);
}
/* Test for RFC2069-style Digest auth. */
static int digest_rfc2069(void)
{
- ne_session *sess = ne_session_create("http", "localhost", 7777);
struct digest_parms parms;
parms.realm = "WallyWorld";
parms.nonce = "random-invented-string";
parms.rfc2617 = 0;
+ parms.send_ainfo = 0;
- ne_set_server_auth(sess, auth_cb, NULL);
- CALL(spawn_server(7777, serve_digest, &parms));
+ return test_digest(&parms);
+}
- CALL(any_2xx_request(sess, "/fish"));
-
- ne_session_destroy(sess);
- CALL(await_server());
+/* Test for Authentication-Info handling. */
+static int digest_auth_info(void)
+{
+ struct digest_parms parms;
+
+ parms.realm = "WallyWorld";
+ parms.nonce = "random-invented-string";
+ parms.rfc2617 = 1;
+ parms.send_ainfo = 1;
+
+ return test_digest(&parms);
+}
+
+static int digest_failures(void)
+{
+ struct digest_parms parms;
+ static const struct {
+ enum digest_failure mode;
+ const char *message;
+ } fails[] = {
+ { fail_ai_bad_nc, "nonce count mismatch" },
+ { fail_ai_bad_digest, "digest mismatch" },
+ { fail_ai_bad_cnonce, "client nonce mismatch" },
+ { fail_ai_omit_nc, "missing parameters" },
+ { fail_ai_omit_digest, "missing parameters" },
+ { fail_ai_omit_cnonce, "missing parameters" },
+ { fail_not, NULL }
+ };
+ size_t n;
+
+ parms.realm = "WallyWorld";
+ parms.nonce = "random-invented-string";
+ parms.rfc2617 = 1;
+ parms.send_ainfo = 1;
+
+ for (n = 0; fails[n].message; n++) {
+ ne_session *sess = ne_session_create("http", "localhost", 7777);
+ int ret;
+
+ parms.failure = fails[n].mode;
+
+ ne_set_server_auth(sess, auth_cb, NULL);
+ CALL(spawn_server(7777, serve_digest, &parms));
+
+ ret = any_2xx_request(sess, "/fish");
+ ONV(ret == NE_OK,
+ ("request success; expecting error '%s'",
+ fails[n].message));
+
+#if 0
+ ONV(strstr(ne_get_error(sess), fails[n].message) == NULL,
+ ("request fails with error '%s'; expecting '%s'",
+ ne_get_error(sess), fails[n].message));
+#endif
+
+ ne_session_destroy(sess);
+ CALL(await_server());
+ }
return OK;
}
@@ -626,7 +761,9 @@ ne_test tests[] = {
T(forget_regress),
T(tunnel_regress),
T(negotiate_regress),
- T(digest_rfc2617),
T(digest_rfc2069),
+ T(digest_rfc2617),
+ T(digest_auth_info),
+ T(digest_failures),
T(NULL)
};