]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/serf/auth/auth_basic.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / serf / auth / auth_basic.c
1 /* Copyright 2009 Justin Erenkrantz and Greg Stein
2  *
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
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
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.
14  */
15
16 /*** Basic authentication ***/
17
18 #include <serf.h>
19 #include <serf_private.h>
20 #include <auth/auth.h>
21
22 #include <apr.h>
23 #include <apr_base64.h>
24 #include <apr_strings.h>
25
26 /* Stores the context information related to Basic authentication.
27    This information is stored in the per server cache in the serf context. */
28 typedef struct basic_authn_info_t {
29     const char *header;
30     const char *value;
31 } basic_authn_info_t;
32
33 apr_status_t
34 serf__handle_basic_auth(int code,
35                         serf_request_t *request,
36                         serf_bucket_t *response,
37                         const char *auth_hdr,
38                         const char *auth_attr,
39                         void *baton,
40                         apr_pool_t *pool)
41 {
42     const char *tmp;
43     apr_size_t tmp_len;
44     serf_connection_t *conn = request->conn;
45     serf_context_t *ctx = conn->ctx;
46     serf__authn_info_t *authn_info;
47     basic_authn_info_t *basic_info;
48     apr_status_t status;
49     apr_pool_t *cred_pool;
50     char *username, *password, *realm_name;
51     const char *eq, *realm;
52
53     /* Can't do Basic authentication if there's no callback to get
54        username & password. */
55     if (!ctx->cred_cb) {
56         return SERF_ERROR_AUTHN_FAILED;
57     }
58
59     if (code == 401) {
60         authn_info = serf__get_authn_info_for_server(conn);
61     } else {
62         authn_info = &ctx->proxy_authn_info;
63     }
64     basic_info = authn_info->baton;
65
66     realm_name = NULL;
67     eq = strchr(auth_attr, '=');
68
69     if (eq && strncasecmp(auth_attr, "realm", 5) == 0) {
70         realm_name = apr_pstrdup(pool, eq + 1);
71         if (realm_name[0] == '\"') {
72             apr_size_t realm_len;
73
74             realm_len = strlen(realm_name);
75             if (realm_name[realm_len - 1] == '\"') {
76                 realm_name[realm_len - 1] = '\0';
77                 realm_name++;
78             }
79         }
80
81         if (!realm_name) {
82             return SERF_ERROR_AUTHN_MISSING_ATTRIBUTE;
83         }
84
85         realm = serf__construct_realm(code == 401 ? HOST : PROXY,
86                                       conn, realm_name,
87                                       pool);
88     }
89
90     /* Ask the application for credentials */
91     apr_pool_create(&cred_pool, pool);
92     status = serf__provide_credentials(ctx,
93                                        &username, &password,
94                                        request, baton,
95                                        code, authn_info->scheme->name,
96                                        realm, cred_pool);
97     if (status) {
98         apr_pool_destroy(cred_pool);
99         return status;
100     }
101
102     tmp = apr_pstrcat(conn->pool, username, ":", password, NULL);
103     tmp_len = strlen(tmp);
104     apr_pool_destroy(cred_pool);
105
106     serf__encode_auth_header(&basic_info->value,
107                              authn_info->scheme->name,
108                              tmp, tmp_len, pool);
109     basic_info->header = (code == 401) ? "Authorization" : "Proxy-Authorization";
110
111     return APR_SUCCESS;
112 }
113
114 apr_status_t
115 serf__init_basic(int code,
116                  serf_context_t *ctx,
117                  apr_pool_t *pool)
118 {
119     return APR_SUCCESS;
120 }
121
122 /* For Basic authentication we expect all authn info to be the same for all
123    connections in the context to the same server (same realm, username,
124    password). Therefore we can keep the header value in the per-server store
125    context instead of per connection.
126    TODO: we currently don't cache this info per realm, so each time a request
127    'switches realms', we have to ask the application for new credentials. */
128 apr_status_t
129 serf__init_basic_connection(const serf__authn_scheme_t *scheme,
130                             int code,
131                             serf_connection_t *conn,
132                             apr_pool_t *pool)
133 {
134     serf_context_t *ctx = conn->ctx;
135     serf__authn_info_t *authn_info;
136
137     if (code == 401) {
138         authn_info = serf__get_authn_info_for_server(conn);
139     } else {
140         authn_info = &ctx->proxy_authn_info;
141     }
142
143     if (!authn_info->baton) {
144         authn_info->baton = apr_pcalloc(pool, sizeof(basic_authn_info_t));
145     }
146
147     return APR_SUCCESS;
148 }
149
150 apr_status_t
151 serf__setup_request_basic_auth(peer_t peer,
152                                int code,
153                                serf_connection_t *conn,
154                                serf_request_t *request,
155                                const char *method,
156                                const char *uri,
157                                serf_bucket_t *hdrs_bkt)
158 {
159     serf_context_t *ctx = conn->ctx;
160     serf__authn_info_t *authn_info;
161     basic_authn_info_t *basic_info;
162
163     if (peer == HOST) {
164         authn_info = serf__get_authn_info_for_server(conn);
165     } else {
166         authn_info = &ctx->proxy_authn_info;
167     }
168     basic_info = authn_info->baton;
169
170     if (basic_info && basic_info->header && basic_info->value) {
171         serf_bucket_headers_setn(hdrs_bkt, basic_info->header,
172                                  basic_info->value);
173         return APR_SUCCESS;
174     }
175
176     return SERF_ERROR_AUTHN_FAILED;
177 }