summaryrefslogtreecommitdiffstats
path: root/contrib/serf/auth/auth_digest.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/serf/auth/auth_digest.c')
-rw-r--r--contrib/serf/auth/auth_digest.c109
1 files changed, 78 insertions, 31 deletions
diff --git a/contrib/serf/auth/auth_digest.c b/contrib/serf/auth/auth_digest.c
index 1c4adf0..7403386 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",
OpenPOWER on IntegriCloud