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
10 * http://www.apache.org/licenses/LICENSE-2.0
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
18 * ====================================================================
21 /*** Basic authentication ***/
24 #include <serf_private.h>
25 #include <auth/auth.h>
28 #include <apr_base64.h>
29 #include <apr_strings.h>
31 /* Stores the context information related to Basic authentication.
32 This information is stored in the per server cache in the serf context. */
33 typedef struct basic_authn_info_t {
39 serf__handle_basic_auth(int code,
40 serf_request_t *request,
41 serf_bucket_t *response,
43 const char *auth_attr,
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;
54 apr_pool_t *cred_pool;
55 char *username, *password, *realm_name;
56 const char *eq, *realm = NULL;
58 /* Can't do Basic authentication if there's no callback to get
59 username & password. */
61 return SERF_ERROR_AUTHN_FAILED;
65 authn_info = serf__get_authn_info_for_server(conn);
67 authn_info = &ctx->proxy_authn_info;
69 basic_info = authn_info->baton;
72 eq = strchr(auth_attr, '=');
74 if (eq && strncasecmp(auth_attr, "realm", 5) == 0) {
75 realm_name = apr_pstrdup(pool, eq + 1);
76 if (realm_name[0] == '\"') {
79 realm_len = strlen(realm_name);
80 if (realm_name[realm_len - 1] == '\"') {
81 realm_name[realm_len - 1] = '\0';
87 return SERF_ERROR_AUTHN_MISSING_ATTRIBUTE;
90 realm = serf__construct_realm(code == 401 ? HOST : PROXY,
95 /* Ask the application for credentials */
96 apr_pool_create(&cred_pool, pool);
97 status = serf__provide_credentials(ctx,
100 code, authn_info->scheme->name,
103 apr_pool_destroy(cred_pool);
107 tmp = apr_pstrcat(conn->pool, username, ":", password, NULL);
108 tmp_len = strlen(tmp);
109 apr_pool_destroy(cred_pool);
111 serf__encode_auth_header(&basic_info->value,
112 authn_info->scheme->name,
114 basic_info->header = (code == 401) ? "Authorization" : "Proxy-Authorization";
120 serf__init_basic(int code,
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. */
134 serf__init_basic_connection(const serf__authn_scheme_t *scheme,
136 serf_connection_t *conn,
139 serf_context_t *ctx = conn->ctx;
140 serf__authn_info_t *authn_info;
143 authn_info = serf__get_authn_info_for_server(conn);
145 authn_info = &ctx->proxy_authn_info;
148 if (!authn_info->baton) {
149 authn_info->baton = apr_pcalloc(pool, sizeof(basic_authn_info_t));
156 serf__setup_request_basic_auth(peer_t peer,
158 serf_connection_t *conn,
159 serf_request_t *request,
162 serf_bucket_t *hdrs_bkt)
164 serf_context_t *ctx = conn->ctx;
165 serf__authn_info_t *authn_info;
166 basic_authn_info_t *basic_info;
169 authn_info = serf__get_authn_info_for_server(conn);
171 authn_info = &ctx->proxy_authn_info;
173 basic_info = authn_info->baton;
175 if (basic_info && basic_info->header && basic_info->value) {
176 serf_bucket_headers_setn(hdrs_bkt, basic_info->header,
181 return SERF_ERROR_AUTHN_FAILED;