diff options
Diffstat (limited to 'contrib/serf/auth/auth_digest.c')
-rw-r--r-- | contrib/serf/auth/auth_digest.c | 109 |
1 files changed, 78 insertions, 31 deletions
diff --git a/contrib/serf/auth/auth_digest.c b/contrib/serf/auth/auth_digest.c index 1c4adf025694..74033865cf87 100644 --- a/contrib/serf/auth/auth_digest.c +++ b/contrib/serf/auth/auth_digest.c @@ -27,8 +27,12 @@ /** Digest authentication, implements RFC 2617. **/ +/* TODO: add support for the domain attribute. This defines the protection + space, so that serf can decide per URI if it should reuse the cached + credentials for the server, or not. */ + /* Stores the context information related to Digest authentication. - The context is per connection. */ + This information is stored in the per server cache in the serf context. */ typedef struct digest_authn_info_t { /* nonce-count for digest authentication */ unsigned int digest_nc; @@ -217,7 +221,7 @@ serf__handle_digest_auth(int code, { char *attrs; char *nextkv; - const char *realm_name = NULL; + const char *realm, *realm_name = NULL; const char *nonce = NULL; const char *algorithm = NULL; const char *qop = NULL; @@ -225,10 +229,8 @@ serf__handle_digest_auth(int code, const char *key; serf_connection_t *conn = request->conn; serf_context_t *ctx = conn->ctx; - serf__authn_info_t *authn_info = (code == 401) ? &ctx->authn_info : - &ctx->proxy_authn_info; - digest_authn_info_t *digest_info = (code == 401) ? conn->authn_baton : - conn->proxy_authn_baton; + serf__authn_info_t *authn_info; + digest_authn_info_t *digest_info; apr_status_t status; apr_pool_t *cred_pool; char *username, *password; @@ -239,6 +241,13 @@ serf__handle_digest_auth(int code, return SERF_ERROR_AUTHN_FAILED; } + if (code == 401) { + authn_info = serf__get_authn_info_for_server(conn); + } else { + authn_info = &ctx->proxy_authn_info; + } + digest_info = authn_info->baton; + /* Need a copy cuz we're going to write NUL characters into the string. */ attrs = apr_pstrdup(pool, auth_attr); @@ -286,17 +295,17 @@ serf__handle_digest_auth(int code, return SERF_ERROR_AUTHN_MISSING_ATTRIBUTE; } - authn_info->realm = apr_psprintf(conn->pool, "<%s://%s:%d> %s", - conn->host_info.scheme, - conn->host_info.hostname, - conn->host_info.port, - realm_name); + realm = serf__construct_realm(code == 401 ? HOST : PROXY, + conn, realm_name, + pool); /* Ask the application for credentials */ apr_pool_create(&cred_pool, pool); - status = (*ctx->cred_cb)(&username, &password, request, baton, - code, authn_info->scheme->name, - authn_info->realm, cred_pool); + status = serf__provide_credentials(ctx, + &username, &password, + request, baton, + code, authn_info->scheme->name, + realm, cred_pool); if (status) { apr_pool_destroy(cred_pool); return status; @@ -305,9 +314,12 @@ serf__handle_digest_auth(int code, digest_info->header = (code == 401) ? "Authorization" : "Proxy-Authorization"; - /* Store the digest authentication parameters in the context relative - to this connection, so we can use it to create the Authorization header - when setting up requests. */ + /* Store the digest authentication parameters in the context cached for + this server in the serf context, so we can use it to create the + Authorization header when setting up requests on the same or different + connections (e.g. in case of KeepAlive off on the server). + TODO: we currently don't cache this info per realm, so each time a request + 'switches realms', we have to ask the application for new credentials. */ digest_info->pool = conn->pool; digest_info->qop = apr_pstrdup(digest_info->pool, qop); digest_info->nonce = apr_pstrdup(digest_info->pool, nonce); @@ -339,16 +351,22 @@ serf__init_digest(int code, } apr_status_t -serf__init_digest_connection(int code, +serf__init_digest_connection(const serf__authn_scheme_t *scheme, + int code, serf_connection_t *conn, apr_pool_t *pool) { - /* Digest authentication is done per connection, so keep all progress - information per connection. */ + serf_context_t *ctx = conn->ctx; + serf__authn_info_t *authn_info; + if (code == 401) { - conn->authn_baton = apr_pcalloc(pool, sizeof(digest_authn_info_t)); + authn_info = serf__get_authn_info_for_server(conn); } else { - conn->proxy_authn_baton = apr_pcalloc(pool, sizeof(digest_authn_info_t)); + authn_info = &ctx->proxy_authn_info; + } + + if (!authn_info->baton) { + authn_info->baton = apr_pcalloc(pool, sizeof(digest_authn_info_t)); } /* Make serf send the initial requests one by one */ @@ -366,23 +384,44 @@ serf__setup_request_digest_auth(peer_t peer, const char *uri, serf_bucket_t *hdrs_bkt) { - digest_authn_info_t *digest_info = (peer == HOST) ? conn->authn_baton : - conn->proxy_authn_baton; + serf_context_t *ctx = conn->ctx; + serf__authn_info_t *authn_info; + digest_authn_info_t *digest_info; apr_status_t status = APR_SUCCESS; + if (peer == HOST) { + authn_info = serf__get_authn_info_for_server(conn); + } else { + authn_info = &ctx->proxy_authn_info; + } + digest_info = authn_info->baton; + if (digest_info && digest_info->realm) { const char *value; - apr_uri_t parsed_uri; + const char *path; /* TODO: per request pool? */ - /* Extract path from uri. */ - status = apr_uri_parse(conn->pool, uri, &parsed_uri); + /* for request 'CONNECT serf.googlecode.com:443', the uri also should be + serf.googlecode.com:443. apr_uri_parse can't handle this, so special + case. */ + if (strcmp(method, "CONNECT") == 0) + path = uri; + else { + apr_uri_t parsed_uri; + + /* Extract path from uri. */ + status = apr_uri_parse(conn->pool, uri, &parsed_uri); + if (status) + return status; + + path = parsed_uri.path; + } /* Build a new Authorization header. */ digest_info->header = (peer == HOST) ? "Authorization" : "Proxy-Authorization"; - value = build_auth_header(digest_info, parsed_uri.path, method, + value = build_auth_header(digest_info, path, method, conn->pool); serf_bucket_headers_setn(hdrs_bkt, digest_info->header, @@ -392,7 +431,7 @@ serf__setup_request_digest_auth(peer_t peer, /* Store the uri of this request on the serf_request_t object, to make it available when validating the Authentication-Info header of the matching response. */ - request->auth_baton = parsed_uri.path; + request->auth_baton = path; } return status; @@ -413,8 +452,7 @@ serf__validate_response_digest_auth(peer_t peer, const char *qop = NULL; const char *nc_str = NULL; serf_bucket_t *hdrs; - digest_authn_info_t *digest_info = (peer == HOST) ? conn->authn_baton : - conn->proxy_authn_baton; + serf_context_t *ctx = conn->ctx; hdrs = serf_bucket_response_get_headers(response); @@ -468,6 +506,15 @@ serf__validate_response_digest_auth(peer_t peer, const char *ha2, *tmp, *resp_hdr_hex; unsigned char resp_hdr[APR_MD5_DIGESTSIZE]; const char *req_uri = request->auth_baton; + serf__authn_info_t *authn_info; + digest_authn_info_t *digest_info; + + if (peer == HOST) { + authn_info = serf__get_authn_info_for_server(conn); + } else { + authn_info = &ctx->proxy_authn_info; + } + digest_info = authn_info->baton; ha2 = build_digest_ha2(req_uri, "", qop, pool); tmp = apr_psprintf(pool, "%s:%s:%s:%s:%s:%s", |