]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/serf/auth/auth_basic.c
Update Apache Serf to 1.3.9 to support OpenSSL 1.1.1.
[FreeBSD/FreeBSD.git] / contrib / serf / auth / auth_basic.c
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
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
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
17  *    under the License.
18  * ====================================================================
19  */
20
21 /*** Basic authentication ***/
22
23 #include <serf.h>
24 #include <serf_private.h>
25 #include <auth/auth.h>
26
27 #include <apr.h>
28 #include <apr_base64.h>
29 #include <apr_strings.h>
30
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 {
34     const char *header;
35     const char *value;
36 } basic_authn_info_t;
37
38 apr_status_t
39 serf__handle_basic_auth(int code,
40                         serf_request_t *request,
41                         serf_bucket_t *response,
42                         const char *auth_hdr,
43                         const char *auth_attr,
44                         void *baton,
45                         apr_pool_t *pool)
46 {
47     const char *tmp;
48     apr_size_t tmp_len;
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;
53     apr_status_t status;
54     apr_pool_t *cred_pool;
55     char *username, *password, *realm_name;
56     const char *eq, *realm = NULL;
57
58     /* Can't do Basic authentication if there's no callback to get
59        username & password. */
60     if (!ctx->cred_cb) {
61         return SERF_ERROR_AUTHN_FAILED;
62     }
63
64     if (code == 401) {
65         authn_info = serf__get_authn_info_for_server(conn);
66     } else {
67         authn_info = &ctx->proxy_authn_info;
68     }
69     basic_info = authn_info->baton;
70
71     realm_name = NULL;
72     eq = strchr(auth_attr, '=');
73
74     if (eq && strncasecmp(auth_attr, "realm", 5) == 0) {
75         realm_name = apr_pstrdup(pool, eq + 1);
76         if (realm_name[0] == '\"') {
77             apr_size_t realm_len;
78
79             realm_len = strlen(realm_name);
80             if (realm_name[realm_len - 1] == '\"') {
81                 realm_name[realm_len - 1] = '\0';
82                 realm_name++;
83             }
84         }
85
86         if (!realm_name) {
87             return SERF_ERROR_AUTHN_MISSING_ATTRIBUTE;
88         }
89
90         realm = serf__construct_realm(code == 401 ? HOST : PROXY,
91                                       conn, realm_name,
92                                       pool);
93     }
94
95     /* Ask the application for credentials */
96     apr_pool_create(&cred_pool, pool);
97     status = serf__provide_credentials(ctx,
98                                        &username, &password,
99                                        request, baton,
100                                        code, authn_info->scheme->name,
101                                        realm, cred_pool);
102     if (status) {
103         apr_pool_destroy(cred_pool);
104         return status;
105     }
106
107     tmp = apr_pstrcat(conn->pool, username, ":", password, NULL);
108     tmp_len = strlen(tmp);
109     apr_pool_destroy(cred_pool);
110
111     serf__encode_auth_header(&basic_info->value,
112                              authn_info->scheme->name,
113                              tmp, tmp_len, pool);
114     basic_info->header = (code == 401) ? "Authorization" : "Proxy-Authorization";
115
116     return APR_SUCCESS;
117 }
118
119 apr_status_t
120 serf__init_basic(int code,
121                  serf_context_t *ctx,
122                  apr_pool_t *pool)
123 {
124     return APR_SUCCESS;
125 }
126
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. */
133 apr_status_t
134 serf__init_basic_connection(const serf__authn_scheme_t *scheme,
135                             int code,
136                             serf_connection_t *conn,
137                             apr_pool_t *pool)
138 {
139     serf_context_t *ctx = conn->ctx;
140     serf__authn_info_t *authn_info;
141
142     if (code == 401) {
143         authn_info = serf__get_authn_info_for_server(conn);
144     } else {
145         authn_info = &ctx->proxy_authn_info;
146     }
147
148     if (!authn_info->baton) {
149         authn_info->baton = apr_pcalloc(pool, sizeof(basic_authn_info_t));
150     }
151
152     return APR_SUCCESS;
153 }
154
155 apr_status_t
156 serf__setup_request_basic_auth(peer_t peer,
157                                int code,
158                                serf_connection_t *conn,
159                                serf_request_t *request,
160                                const char *method,
161                                const char *uri,
162                                serf_bucket_t *hdrs_bkt)
163 {
164     serf_context_t *ctx = conn->ctx;
165     serf__authn_info_t *authn_info;
166     basic_authn_info_t *basic_info;
167
168     if (peer == HOST) {
169         authn_info = serf__get_authn_info_for_server(conn);
170     } else {
171         authn_info = &ctx->proxy_authn_info;
172     }
173     basic_info = authn_info->baton;
174
175     if (basic_info && basic_info->header && basic_info->value) {
176         serf_bucket_headers_setn(hdrs_bkt, basic_info->header,
177                                  basic_info->value);
178         return APR_SUCCESS;
179     }
180
181     return SERF_ERROR_AUTHN_FAILED;
182 }