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