1
/* Copyright 2009 Justin Erenkrantz and Greg Stein
3
* Licensed under the Apache License, Version 2.0 (the "License");
4
* you may not use this file except in compliance with the License.
5
* You may obtain a copy of the License at
7
* http://www.apache.org/licenses/LICENSE-2.0
9
* Unless required by applicable law or agreed to in writing, software
10
* distributed under the License is distributed on an "AS IS" BASIS,
11
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
* See the License for the specific language governing permissions and
13
* limitations under the License.
16
/*** Basic authentication ***/
19
#include <serf_private.h>
20
#include <auth/auth.h>
23
#include <apr_base64.h>
24
#include <apr_strings.h>
26
typedef struct basic_authn_info_t {
32
serf__handle_basic_auth(int code,
33
serf_request_t *request,
34
serf_bucket_t *response,
36
const char *auth_attr,
42
serf_connection_t *conn = request->conn;
43
serf_context_t *ctx = conn->ctx;
44
serf__authn_info_t *authn_info = (code == 401) ? &ctx->authn_info :
45
&ctx->proxy_authn_info;
46
basic_authn_info_t *basic_info = authn_info->baton;
48
apr_pool_t *cred_pool;
49
char *username, *password;
51
/* Can't do Basic authentication if there's no callback to get
52
username & password. */
54
return SERF_ERROR_AUTHN_FAILED;
57
if (!authn_info->realm) {
58
char *realm_name = NULL;
59
const char *eq = strchr(auth_attr, '=');
61
if (eq && strncasecmp(auth_attr, "realm", 5) == 0) {
62
realm_name = apr_pstrdup(pool, eq + 1);
63
if (realm_name[0] == '\"') {
66
realm_len = strlen(realm_name);
67
if (realm_name[realm_len - 1] == '\"') {
68
realm_name[realm_len - 1] = '\0';
75
return SERF_ERROR_AUTHN_MISSING_ATTRIBUTE;
78
authn_info->realm = apr_psprintf(conn->pool, "<%s://%s:%d> %s",
79
conn->host_info.scheme,
80
conn->host_info.hostname,
85
/* Ask the application for credentials */
86
apr_pool_create(&cred_pool, pool);
87
status = (*ctx->cred_cb)(&username, &password, request, baton,
88
code, authn_info->scheme->name,
89
authn_info->realm, cred_pool);
91
apr_pool_destroy(cred_pool);
95
tmp = apr_pstrcat(conn->pool, username, ":", password, NULL);
96
tmp_len = strlen(tmp);
97
apr_pool_destroy(cred_pool);
99
serf__encode_auth_header(&basic_info->value,
100
authn_info->scheme->name,
102
basic_info->header = (code == 401) ? "Authorization" : "Proxy-Authorization";
107
/* For Basic authentication we expect all authn info to be the same for all
108
connections in the context (same realm, username, password). Therefore we
109
can keep the header value in the context instead of per connection. */
111
serf__init_basic(int code,
116
ctx->authn_info.baton = apr_pcalloc(pool, sizeof(basic_authn_info_t));
118
ctx->proxy_authn_info.baton = apr_pcalloc(pool, sizeof(basic_authn_info_t));
125
serf__init_basic_connection(int code,
126
serf_connection_t *conn,
133
serf__setup_request_basic_auth(int code,
134
serf_connection_t *conn,
137
serf_bucket_t *hdrs_bkt)
139
serf_context_t *ctx = conn->ctx;
140
basic_authn_info_t *authn_info;
143
authn_info = ctx->authn_info.baton;
145
authn_info = ctx->proxy_authn_info.baton;
148
if (authn_info && authn_info->header && authn_info->value) {
149
serf_bucket_headers_setn(hdrs_bkt, authn_info->header,
154
return SERF_ERROR_AUTHN_FAILED;