1251877Speter/* Copyright 2009 Justin Erenkrantz and Greg Stein 2251877Speter * 3251877Speter * Licensed under the Apache License, Version 2.0 (the "License"); 4251877Speter * you may not use this file except in compliance with the License. 5251877Speter * You may obtain a copy of the License at 6251877Speter * 7251877Speter * http://www.apache.org/licenses/LICENSE-2.0 8251877Speter * 9251877Speter * Unless required by applicable law or agreed to in writing, software 10251877Speter * distributed under the License is distributed on an "AS IS" BASIS, 11251877Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12251877Speter * See the License for the specific language governing permissions and 13251877Speter * limitations under the License. 14251877Speter */ 15251877Speter 16251877Speter/*** Basic authentication ***/ 17251877Speter 18251877Speter#include <serf.h> 19251877Speter#include <serf_private.h> 20251877Speter#include <auth/auth.h> 21251877Speter 22251877Speter#include <apr.h> 23251877Speter#include <apr_base64.h> 24251877Speter#include <apr_strings.h> 25251877Speter 26253895Speter/* Stores the context information related to Basic authentication. 27253895Speter This information is stored in the per server cache in the serf context. */ 28251877Spetertypedef struct basic_authn_info_t { 29251877Speter const char *header; 30251877Speter const char *value; 31251877Speter} basic_authn_info_t; 32251877Speter 33251877Speterapr_status_t 34251877Speterserf__handle_basic_auth(int code, 35251877Speter serf_request_t *request, 36251877Speter serf_bucket_t *response, 37251877Speter const char *auth_hdr, 38251877Speter const char *auth_attr, 39251877Speter void *baton, 40251877Speter apr_pool_t *pool) 41251877Speter{ 42251877Speter const char *tmp; 43251877Speter apr_size_t tmp_len; 44251877Speter serf_connection_t *conn = request->conn; 45251877Speter serf_context_t *ctx = conn->ctx; 46253895Speter serf__authn_info_t *authn_info; 47253895Speter basic_authn_info_t *basic_info; 48251877Speter apr_status_t status; 49251877Speter apr_pool_t *cred_pool; 50253895Speter char *username, *password, *realm_name; 51262339Speter const char *eq, *realm = NULL; 52251877Speter 53251877Speter /* Can't do Basic authentication if there's no callback to get 54251877Speter username & password. */ 55251877Speter if (!ctx->cred_cb) { 56251877Speter return SERF_ERROR_AUTHN_FAILED; 57251877Speter } 58251877Speter 59253895Speter if (code == 401) { 60253895Speter authn_info = serf__get_authn_info_for_server(conn); 61253895Speter } else { 62253895Speter authn_info = &ctx->proxy_authn_info; 63253895Speter } 64253895Speter basic_info = authn_info->baton; 65251877Speter 66253895Speter realm_name = NULL; 67253895Speter eq = strchr(auth_attr, '='); 68251877Speter 69253895Speter if (eq && strncasecmp(auth_attr, "realm", 5) == 0) { 70253895Speter realm_name = apr_pstrdup(pool, eq + 1); 71253895Speter if (realm_name[0] == '\"') { 72253895Speter apr_size_t realm_len; 73253895Speter 74253895Speter realm_len = strlen(realm_name); 75253895Speter if (realm_name[realm_len - 1] == '\"') { 76253895Speter realm_name[realm_len - 1] = '\0'; 77253895Speter realm_name++; 78251877Speter } 79251877Speter } 80251877Speter 81251877Speter if (!realm_name) { 82251877Speter return SERF_ERROR_AUTHN_MISSING_ATTRIBUTE; 83251877Speter } 84251877Speter 85253895Speter realm = serf__construct_realm(code == 401 ? HOST : PROXY, 86253895Speter conn, realm_name, 87253895Speter pool); 88251877Speter } 89251877Speter 90251877Speter /* Ask the application for credentials */ 91251877Speter apr_pool_create(&cred_pool, pool); 92253895Speter status = serf__provide_credentials(ctx, 93253895Speter &username, &password, 94253895Speter request, baton, 95253895Speter code, authn_info->scheme->name, 96253895Speter realm, cred_pool); 97251877Speter if (status) { 98251877Speter apr_pool_destroy(cred_pool); 99251877Speter return status; 100251877Speter } 101251877Speter 102251877Speter tmp = apr_pstrcat(conn->pool, username, ":", password, NULL); 103251877Speter tmp_len = strlen(tmp); 104251877Speter apr_pool_destroy(cred_pool); 105251877Speter 106251877Speter serf__encode_auth_header(&basic_info->value, 107251877Speter authn_info->scheme->name, 108251877Speter tmp, tmp_len, pool); 109251877Speter basic_info->header = (code == 401) ? "Authorization" : "Proxy-Authorization"; 110251877Speter 111251877Speter return APR_SUCCESS; 112251877Speter} 113251877Speter 114251877Speterapr_status_t 115251877Speterserf__init_basic(int code, 116251877Speter serf_context_t *ctx, 117251877Speter apr_pool_t *pool) 118251877Speter{ 119251877Speter return APR_SUCCESS; 120251877Speter} 121251877Speter 122253895Speter/* For Basic authentication we expect all authn info to be the same for all 123253895Speter connections in the context to the same server (same realm, username, 124253895Speter password). Therefore we can keep the header value in the per-server store 125253895Speter context instead of per connection. 126253895Speter TODO: we currently don't cache this info per realm, so each time a request 127253895Speter 'switches realms', we have to ask the application for new credentials. */ 128251877Speterapr_status_t 129253895Speterserf__init_basic_connection(const serf__authn_scheme_t *scheme, 130253895Speter int code, 131251877Speter serf_connection_t *conn, 132251877Speter apr_pool_t *pool) 133251877Speter{ 134253895Speter serf_context_t *ctx = conn->ctx; 135253895Speter serf__authn_info_t *authn_info; 136253895Speter 137253895Speter if (code == 401) { 138253895Speter authn_info = serf__get_authn_info_for_server(conn); 139253895Speter } else { 140253895Speter authn_info = &ctx->proxy_authn_info; 141253895Speter } 142253895Speter 143253895Speter if (!authn_info->baton) { 144253895Speter authn_info->baton = apr_pcalloc(pool, sizeof(basic_authn_info_t)); 145253895Speter } 146253895Speter 147251877Speter return APR_SUCCESS; 148251877Speter} 149251877Speter 150251877Speterapr_status_t 151251877Speterserf__setup_request_basic_auth(peer_t peer, 152251877Speter int code, 153251877Speter serf_connection_t *conn, 154251877Speter serf_request_t *request, 155251877Speter const char *method, 156251877Speter const char *uri, 157251877Speter serf_bucket_t *hdrs_bkt) 158251877Speter{ 159251877Speter serf_context_t *ctx = conn->ctx; 160253895Speter serf__authn_info_t *authn_info; 161253895Speter basic_authn_info_t *basic_info; 162251877Speter 163251877Speter if (peer == HOST) { 164253895Speter authn_info = serf__get_authn_info_for_server(conn); 165251877Speter } else { 166253895Speter authn_info = &ctx->proxy_authn_info; 167251877Speter } 168253895Speter basic_info = authn_info->baton; 169251877Speter 170253895Speter if (basic_info && basic_info->header && basic_info->value) { 171253895Speter serf_bucket_headers_setn(hdrs_bkt, basic_info->header, 172253895Speter basic_info->value); 173251877Speter return APR_SUCCESS; 174251877Speter } 175251877Speter 176251877Speter return SERF_ERROR_AUTHN_FAILED; 177251877Speter} 178