auth_basic.c revision 262324
1155192Srwatson/* Copyright 2009 Justin Erenkrantz and Greg Stein 2155192Srwatson * 3155192Srwatson * Licensed under the Apache License, Version 2.0 (the "License"); 4155192Srwatson * you may not use this file except in compliance with the License. 5155192Srwatson * You may obtain a copy of the License at 6155192Srwatson * 7155192Srwatson * http://www.apache.org/licenses/LICENSE-2.0 8155192Srwatson * 9155192Srwatson * Unless required by applicable law or agreed to in writing, software 10155192Srwatson * distributed under the License is distributed on an "AS IS" BASIS, 11155192Srwatson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12155192Srwatson * See the License for the specific language governing permissions and 13155192Srwatson * limitations under the License. 14155192Srwatson */ 15155192Srwatson 16155192Srwatson/*** Basic authentication ***/ 17155192Srwatson 18155192Srwatson#include <serf.h> 19155192Srwatson#include <serf_private.h> 20155192Srwatson#include <auth/auth.h> 21155192Srwatson 22155192Srwatson#include <apr.h> 23155192Srwatson#include <apr_base64.h> 24155192Srwatson#include <apr_strings.h> 25155192Srwatson 26155192Srwatson/* Stores the context information related to Basic authentication. 27155192Srwatson This information is stored in the per server cache in the serf context. */ 28155192Srwatsontypedef struct basic_authn_info_t { 29155192Srwatson const char *header; 30155192Srwatson const char *value; 31155192Srwatson} basic_authn_info_t; 32155192Srwatson 33155192Srwatsonapr_status_t 34155192Srwatsonserf__handle_basic_auth(int code, 35155192Srwatson serf_request_t *request, 36155192Srwatson serf_bucket_t *response, 37156882Srwatson const char *auth_hdr, 38156882Srwatson const char *auth_attr, 39155192Srwatson void *baton, 40155192Srwatson apr_pool_t *pool) 41155192Srwatson{ 42155192Srwatson const char *tmp; 43155192Srwatson apr_size_t tmp_len; 44155192Srwatson serf_connection_t *conn = request->conn; 45155192Srwatson serf_context_t *ctx = conn->ctx; 46155192Srwatson serf__authn_info_t *authn_info; 47155192Srwatson basic_authn_info_t *basic_info; 48155192Srwatson apr_status_t status; 49155192Srwatson apr_pool_t *cred_pool; 50155192Srwatson char *username, *password, *realm_name; 51155192Srwatson const char *eq, *realm = NULL; 52155192Srwatson 53155192Srwatson /* Can't do Basic authentication if there's no callback to get 54155192Srwatson username & password. */ 55155192Srwatson if (!ctx->cred_cb) { 56156888Srwatson return SERF_ERROR_AUTHN_FAILED; 57156888Srwatson } 58156888Srwatson 59156888Srwatson if (code == 401) { 60156888Srwatson authn_info = serf__get_authn_info_for_server(conn); 61156888Srwatson } else { 62156888Srwatson authn_info = &ctx->proxy_authn_info; 63156888Srwatson } 64156888Srwatson basic_info = authn_info->baton; 65156888Srwatson 66156888Srwatson realm_name = NULL; 67156888Srwatson eq = strchr(auth_attr, '='); 68156888Srwatson 69156889Srwatson if (eq && strncasecmp(auth_attr, "realm", 5) == 0) { 70156889Srwatson realm_name = apr_pstrdup(pool, eq + 1); 71155192Srwatson if (realm_name[0] == '\"') { 72155192Srwatson apr_size_t realm_len; 73155192Srwatson 74155192Srwatson realm_len = strlen(realm_name); 75155192Srwatson if (realm_name[realm_len - 1] == '\"') { 76155192Srwatson realm_name[realm_len - 1] = '\0'; 77161813Swsalamon realm_name++; 78161813Swsalamon } 79155192Srwatson } 80155192Srwatson 81155192Srwatson if (!realm_name) { 82155192Srwatson return SERF_ERROR_AUTHN_MISSING_ATTRIBUTE; 83155192Srwatson } 84156889Srwatson 85156889Srwatson realm = serf__construct_realm(code == 401 ? HOST : PROXY, 86156889Srwatson conn, realm_name, 87155192Srwatson pool); 88155192Srwatson } 89159269Srwatson 90159269Srwatson /* Ask the application for credentials */ 91159269Srwatson apr_pool_create(&cred_pool, pool); 92155192Srwatson status = serf__provide_credentials(ctx, 93155192Srwatson &username, &password, 94155192Srwatson request, baton, 95155192Srwatson code, authn_info->scheme->name, 96159269Srwatson realm, cred_pool); 97159269Srwatson if (status) { 98159269Srwatson apr_pool_destroy(cred_pool); 99162380Scsjp return status; 100162380Scsjp } 101162380Scsjp 102155192Srwatson tmp = apr_pstrcat(conn->pool, username, ":", password, NULL); 103155192Srwatson tmp_len = strlen(tmp); 104155192Srwatson apr_pool_destroy(cred_pool); 105155192Srwatson 106155192Srwatson serf__encode_auth_header(&basic_info->value, 107155192Srwatson authn_info->scheme->name, 108155192Srwatson tmp, tmp_len, pool); 109155192Srwatson basic_info->header = (code == 401) ? "Authorization" : "Proxy-Authorization"; 110156889Srwatson 111156889Srwatson return APR_SUCCESS; 112156889Srwatson} 113156889Srwatson 114156889Srwatsonapr_status_t 115156889Srwatsonserf__init_basic(int code, 116156889Srwatson serf_context_t *ctx, 117155192Srwatson apr_pool_t *pool) 118155192Srwatson{ 119155192Srwatson return APR_SUCCESS; 120155192Srwatson} 121155192Srwatson 122155192Srwatson/* For Basic authentication we expect all authn info to be the same for all 123155192Srwatson connections in the context to the same server (same realm, username, 124155192Srwatson password). Therefore we can keep the header value in the per-server store 125155192Srwatson context instead of per connection. 126155192Srwatson TODO: we currently don't cache this info per realm, so each time a request 127155192Srwatson 'switches realms', we have to ask the application for new credentials. */ 128156889Srwatsonapr_status_t 129156889Srwatsonserf__init_basic_connection(const serf__authn_scheme_t *scheme, 130156889Srwatson int code, 131156889Srwatson serf_connection_t *conn, 132155192Srwatson apr_pool_t *pool) 133155192Srwatson{ 134155192Srwatson serf_context_t *ctx = conn->ctx; 135155192Srwatson serf__authn_info_t *authn_info; 136155192Srwatson 137155192Srwatson if (code == 401) { 138155192Srwatson authn_info = serf__get_authn_info_for_server(conn); 139155192Srwatson } else { 140155192Srwatson authn_info = &ctx->proxy_authn_info; 141155192Srwatson } 142155192Srwatson 143155192Srwatson if (!authn_info->baton) { 144155192Srwatson authn_info->baton = apr_pcalloc(pool, sizeof(basic_authn_info_t)); 145155192Srwatson } 146155192Srwatson 147155192Srwatson return APR_SUCCESS; 148155192Srwatson} 149155192Srwatson 150155192Srwatsonapr_status_t 151156889Srwatsonserf__setup_request_basic_auth(peer_t peer, 152156889Srwatson int code, 153156889Srwatson serf_connection_t *conn, 154155192Srwatson serf_request_t *request, 155155192Srwatson const char *method, 156155192Srwatson const char *uri, 157155192Srwatson serf_bucket_t *hdrs_bkt) 158155192Srwatson{ 159155192Srwatson serf_context_t *ctx = conn->ctx; 160155192Srwatson serf__authn_info_t *authn_info; 161155192Srwatson basic_authn_info_t *basic_info; 162155192Srwatson 163155192Srwatson if (peer == HOST) { 164155192Srwatson authn_info = serf__get_authn_info_for_server(conn); 165155192Srwatson } else { 166155192Srwatson authn_info = &ctx->proxy_authn_info; 167156889Srwatson } 168156889Srwatson basic_info = authn_info->baton; 169156889Srwatson 170156889Srwatson if (basic_info && basic_info->header && basic_info->value) { 171156889Srwatson serf_bucket_headers_setn(hdrs_bkt, basic_info->header, 172156889Srwatson basic_info->value); 173156889Srwatson return APR_SUCCESS; 174156889Srwatson } 175156889Srwatson 176156889Srwatson return SERF_ERROR_AUTHN_FAILED; 177155192Srwatson} 178155192Srwatson