diff options
Diffstat (limited to 'auth/auth_basic.c')
-rw-r--r-- | auth/auth_basic.c | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/auth/auth_basic.c b/auth/auth_basic.c new file mode 100644 index 0000000..b876cb8 --- /dev/null +++ b/auth/auth_basic.c @@ -0,0 +1,155 @@ +/* Copyright 2009 Justin Erenkrantz and Greg Stein + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*** Basic authentication ***/ + +#include <serf.h> +#include <serf_private.h> +#include <auth/auth.h> + +#include <apr.h> +#include <apr_base64.h> +#include <apr_strings.h> + +typedef struct basic_authn_info_t { + const char *header; + const char *value; +} basic_authn_info_t; + +apr_status_t +serf__handle_basic_auth(int code, + serf_request_t *request, + serf_bucket_t *response, + const char *auth_hdr, + const char *auth_attr, + void *baton, + apr_pool_t *pool) +{ + const char *tmp; + apr_size_t tmp_len; + 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; + basic_authn_info_t *basic_info = authn_info->baton; + apr_status_t status; + apr_pool_t *cred_pool; + char *username, *password; + + /* Can't do Basic authentication if there's no callback to get + username & password. */ + if (!ctx->cred_cb) { + return SERF_ERROR_AUTHN_FAILED; + } + + if (!authn_info->realm) { + char *realm_name = NULL; + const char *eq = strchr(auth_attr, '='); + + if (eq && strncasecmp(auth_attr, "realm", 5) == 0) { + realm_name = apr_pstrdup(pool, eq + 1); + if (realm_name[0] == '\"') { + apr_size_t realm_len; + + realm_len = strlen(realm_name); + if (realm_name[realm_len - 1] == '\"') { + realm_name[realm_len - 1] = '\0'; + realm_name++; + } + } + } + + if (!realm_name) { + 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); + } + + /* 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); + if (status) { + apr_pool_destroy(cred_pool); + return status; + } + + tmp = apr_pstrcat(conn->pool, username, ":", password, NULL); + tmp_len = strlen(tmp); + apr_pool_destroy(cred_pool); + + serf__encode_auth_header(&basic_info->value, + authn_info->scheme->name, + tmp, tmp_len, pool); + basic_info->header = (code == 401) ? "Authorization" : "Proxy-Authorization"; + + return APR_SUCCESS; +} + +/* For Basic authentication we expect all authn info to be the same for all + connections in the context (same realm, username, password). Therefore we + can keep the header value in the context instead of per connection. */ +apr_status_t +serf__init_basic(int code, + serf_context_t *ctx, + apr_pool_t *pool) +{ + if (code == 401) { + ctx->authn_info.baton = apr_pcalloc(pool, sizeof(basic_authn_info_t)); + } else { + ctx->proxy_authn_info.baton = apr_pcalloc(pool, sizeof(basic_authn_info_t)); + } + + return APR_SUCCESS; +} + +apr_status_t +serf__init_basic_connection(int code, + serf_connection_t *conn, + apr_pool_t *pool) +{ + return APR_SUCCESS; +} + +apr_status_t +serf__setup_request_basic_auth(int code, + serf_connection_t *conn, + const char *method, + const char *uri, + serf_bucket_t *hdrs_bkt) +{ + serf_context_t *ctx = conn->ctx; + basic_authn_info_t *authn_info; + + if (code == 401) { + authn_info = ctx->authn_info.baton; + } else { + authn_info = ctx->proxy_authn_info.baton; + } + + if (authn_info && authn_info->header && authn_info->value) { + serf_bucket_headers_setn(hdrs_bkt, authn_info->header, + authn_info->value); + return APR_SUCCESS; + } + + return SERF_ERROR_AUTHN_FAILED; +} |