auth_basic.c revision 362181
1/* ==================================================================== 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 * ==================================================================== 19 */ 20 21/*** Basic authentication ***/ 22 23#include <serf.h> 24#include <serf_private.h> 25#include <auth/auth.h> 26 27#include <apr.h> 28#include <apr_base64.h> 29#include <apr_strings.h> 30 31/* Stores the context information related to Basic authentication. 32 This information is stored in the per server cache in the serf context. */ 33typedef struct basic_authn_info_t { 34 const char *header; 35 const char *value; 36} basic_authn_info_t; 37 38apr_status_t 39serf__handle_basic_auth(int code, 40 serf_request_t *request, 41 serf_bucket_t *response, 42 const char *auth_hdr, 43 const char *auth_attr, 44 void *baton, 45 apr_pool_t *pool) 46{ 47 const char *tmp; 48 apr_size_t tmp_len; 49 serf_connection_t *conn = request->conn; 50 serf_context_t *ctx = conn->ctx; 51 serf__authn_info_t *authn_info; 52 basic_authn_info_t *basic_info; 53 apr_status_t status; 54 apr_pool_t *cred_pool; 55 char *username, *password, *realm_name; 56 const char *eq, *realm = NULL; 57 58 /* Can't do Basic authentication if there's no callback to get 59 username & password. */ 60 if (!ctx->cred_cb) { 61 return SERF_ERROR_AUTHN_FAILED; 62 } 63 64 if (code == 401) { 65 authn_info = serf__get_authn_info_for_server(conn); 66 } else { 67 authn_info = &ctx->proxy_authn_info; 68 } 69 basic_info = authn_info->baton; 70 71 realm_name = NULL; 72 eq = strchr(auth_attr, '='); 73 74 if (eq && strncasecmp(auth_attr, "realm", 5) == 0) { 75 realm_name = apr_pstrdup(pool, eq + 1); 76 if (realm_name[0] == '\"') { 77 apr_size_t realm_len; 78 79 realm_len = strlen(realm_name); 80 if (realm_name[realm_len - 1] == '\"') { 81 realm_name[realm_len - 1] = '\0'; 82 realm_name++; 83 } 84 } 85 86 if (!realm_name) { 87 return SERF_ERROR_AUTHN_MISSING_ATTRIBUTE; 88 } 89 90 realm = serf__construct_realm(code == 401 ? HOST : PROXY, 91 conn, realm_name, 92 pool); 93 } 94 95 /* Ask the application for credentials */ 96 apr_pool_create(&cred_pool, pool); 97 status = serf__provide_credentials(ctx, 98 &username, &password, 99 request, baton, 100 code, authn_info->scheme->name, 101 realm, cred_pool); 102 if (status) { 103 apr_pool_destroy(cred_pool); 104 return status; 105 } 106 107 tmp = apr_pstrcat(conn->pool, username, ":", password, NULL); 108 tmp_len = strlen(tmp); 109 apr_pool_destroy(cred_pool); 110 111 serf__encode_auth_header(&basic_info->value, 112 authn_info->scheme->name, 113 tmp, tmp_len, pool); 114 basic_info->header = (code == 401) ? "Authorization" : "Proxy-Authorization"; 115 116 return APR_SUCCESS; 117} 118 119apr_status_t 120serf__init_basic(int code, 121 serf_context_t *ctx, 122 apr_pool_t *pool) 123{ 124 return APR_SUCCESS; 125} 126 127/* For Basic authentication we expect all authn info to be the same for all 128 connections in the context to the same server (same realm, username, 129 password). Therefore we can keep the header value in the per-server store 130 context instead of per connection. 131 TODO: we currently don't cache this info per realm, so each time a request 132 'switches realms', we have to ask the application for new credentials. */ 133apr_status_t 134serf__init_basic_connection(const serf__authn_scheme_t *scheme, 135 int code, 136 serf_connection_t *conn, 137 apr_pool_t *pool) 138{ 139 serf_context_t *ctx = conn->ctx; 140 serf__authn_info_t *authn_info; 141 142 if (code == 401) { 143 authn_info = serf__get_authn_info_for_server(conn); 144 } else { 145 authn_info = &ctx->proxy_authn_info; 146 } 147 148 if (!authn_info->baton) { 149 authn_info->baton = apr_pcalloc(pool, sizeof(basic_authn_info_t)); 150 } 151 152 return APR_SUCCESS; 153} 154 155apr_status_t 156serf__setup_request_basic_auth(peer_t peer, 157 int code, 158 serf_connection_t *conn, 159 serf_request_t *request, 160 const char *method, 161 const char *uri, 162 serf_bucket_t *hdrs_bkt) 163{ 164 serf_context_t *ctx = conn->ctx; 165 serf__authn_info_t *authn_info; 166 basic_authn_info_t *basic_info; 167 168 if (peer == HOST) { 169 authn_info = serf__get_authn_info_for_server(conn); 170 } else { 171 authn_info = &ctx->proxy_authn_info; 172 } 173 basic_info = authn_info->baton; 174 175 if (basic_info && basic_info->header && basic_info->value) { 176 serf_bucket_headers_setn(hdrs_bkt, basic_info->header, 177 basic_info->value); 178 return APR_SUCCESS; 179 } 180 181 return SERF_ERROR_AUTHN_FAILED; 182} 183