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 /* 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 {
34 serf__handle_basic_auth(int code,
35 serf_request_t *request,
36 serf_bucket_t *response,
38 const char *auth_attr,
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;
49 apr_pool_t *cred_pool;
50 char *username, *password, *realm_name;
51 const char *eq, *realm = NULL;
53 /* Can't do Basic authentication if there's no callback to get
54 username & password. */
56 return SERF_ERROR_AUTHN_FAILED;
60 authn_info = serf__get_authn_info_for_server(conn);
62 authn_info = &ctx->proxy_authn_info;
64 basic_info = authn_info->baton;
67 eq = strchr(auth_attr, '=');
69 if (eq && strncasecmp(auth_attr, "realm", 5) == 0) {
70 realm_name = apr_pstrdup(pool, eq + 1);
71 if (realm_name[0] == '\"') {
74 realm_len = strlen(realm_name);
75 if (realm_name[realm_len - 1] == '\"') {
76 realm_name[realm_len - 1] = '\0';
82 return SERF_ERROR_AUTHN_MISSING_ATTRIBUTE;
85 realm = serf__construct_realm(code == 401 ? HOST : PROXY,
90 /* Ask the application for credentials */
91 apr_pool_create(&cred_pool, pool);
92 status = serf__provide_credentials(ctx,
95 code, authn_info->scheme->name,
98 apr_pool_destroy(cred_pool);
102 tmp = apr_pstrcat(conn->pool, username, ":", password, NULL);
103 tmp_len = strlen(tmp);
104 apr_pool_destroy(cred_pool);
106 serf__encode_auth_header(&basic_info->value,
107 authn_info->scheme->name,
109 basic_info->header = (code == 401) ? "Authorization" : "Proxy-Authorization";
115 serf__init_basic(int code,
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. */
129 serf__init_basic_connection(const serf__authn_scheme_t *scheme,
131 serf_connection_t *conn,
134 serf_context_t *ctx = conn->ctx;
135 serf__authn_info_t *authn_info;
138 authn_info = serf__get_authn_info_for_server(conn);
140 authn_info = &ctx->proxy_authn_info;
143 if (!authn_info->baton) {
144 authn_info->baton = apr_pcalloc(pool, sizeof(basic_authn_info_t));
151 serf__setup_request_basic_auth(peer_t peer,
153 serf_connection_t *conn,
154 serf_request_t *request,
157 serf_bucket_t *hdrs_bkt)
159 serf_context_t *ctx = conn->ctx;
160 serf__authn_info_t *authn_info;
161 basic_authn_info_t *basic_info;
164 authn_info = serf__get_authn_info_for_server(conn);
166 authn_info = &ctx->proxy_authn_info;
168 basic_info = authn_info->baton;
170 if (basic_info && basic_info->header && basic_info->value) {
171 serf_bucket_headers_setn(hdrs_bkt, basic_info->header,
176 return SERF_ERROR_AUTHN_FAILED;