|
Packit |
3adb1e |
/* ====================================================================
|
|
Packit |
3adb1e |
* Licensed to the Apache Software Foundation (ASF) under one
|
|
Packit |
3adb1e |
* or more contributor license agreements. See the NOTICE file
|
|
Packit |
3adb1e |
* distributed with this work for additional information
|
|
Packit |
3adb1e |
* regarding copyright ownership. The ASF licenses this file
|
|
Packit |
3adb1e |
* to you under the Apache License, Version 2.0 (the
|
|
Packit |
3adb1e |
* "License"); you may not use this file except in compliance
|
|
Packit |
3adb1e |
* with the License. You may obtain a copy of the License at
|
|
Packit |
3adb1e |
*
|
|
Packit |
3adb1e |
* http://www.apache.org/licenses/LICENSE-2.0
|
|
Packit |
3adb1e |
*
|
|
Packit |
3adb1e |
* Unless required by applicable law or agreed to in writing,
|
|
Packit |
3adb1e |
* software distributed under the License is distributed on an
|
|
Packit |
3adb1e |
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
Packit |
3adb1e |
* KIND, either express or implied. See the License for the
|
|
Packit |
3adb1e |
* specific language governing permissions and limitations
|
|
Packit |
3adb1e |
* under the License.
|
|
Packit |
3adb1e |
* ====================================================================
|
|
Packit |
3adb1e |
*/
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
/*** Basic authentication ***/
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
#include <serf.h>
|
|
Packit |
3adb1e |
#include <serf_private.h>
|
|
Packit |
3adb1e |
#include <auth/auth.h>
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
#include <apr.h>
|
|
Packit |
3adb1e |
#include <apr_base64.h>
|
|
Packit |
3adb1e |
#include <apr_strings.h>
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
/* Stores the context information related to Basic authentication.
|
|
Packit |
3adb1e |
This information is stored in the per server cache in the serf context. */
|
|
Packit |
3adb1e |
typedef struct basic_authn_info_t {
|
|
Packit |
3adb1e |
const char *header;
|
|
Packit |
3adb1e |
const char *value;
|
|
Packit |
3adb1e |
} basic_authn_info_t;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
apr_status_t
|
|
Packit |
3adb1e |
serf__handle_basic_auth(int code,
|
|
Packit |
3adb1e |
serf_request_t *request,
|
|
Packit |
3adb1e |
serf_bucket_t *response,
|
|
Packit |
3adb1e |
const char *auth_hdr,
|
|
Packit |
3adb1e |
const char *auth_attr,
|
|
Packit |
3adb1e |
void *baton,
|
|
Packit |
3adb1e |
apr_pool_t *pool)
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
const char *tmp;
|
|
Packit |
3adb1e |
apr_size_t tmp_len;
|
|
Packit |
3adb1e |
serf_connection_t *conn = request->conn;
|
|
Packit |
3adb1e |
serf_context_t *ctx = conn->ctx;
|
|
Packit |
3adb1e |
serf__authn_info_t *authn_info;
|
|
Packit |
3adb1e |
basic_authn_info_t *basic_info;
|
|
Packit |
3adb1e |
apr_status_t status;
|
|
Packit |
3adb1e |
apr_pool_t *cred_pool;
|
|
Packit |
3adb1e |
char *username, *password, *realm_name;
|
|
Packit |
3adb1e |
const char *eq, *realm = NULL;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
/* Can't do Basic authentication if there's no callback to get
|
|
Packit |
3adb1e |
username & password. */
|
|
Packit |
3adb1e |
if (!ctx->cred_cb) {
|
|
Packit |
3adb1e |
return SERF_ERROR_AUTHN_FAILED;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
if (code == 401) {
|
|
Packit |
3adb1e |
authn_info = serf__get_authn_info_for_server(conn);
|
|
Packit |
3adb1e |
} else {
|
|
Packit |
3adb1e |
authn_info = &ctx->proxy_authn_info;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
basic_info = authn_info->baton;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
realm_name = NULL;
|
|
Packit |
3adb1e |
eq = strchr(auth_attr, '=');
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
if (eq && strncasecmp(auth_attr, "realm", 5) == 0) {
|
|
Packit |
3adb1e |
realm_name = apr_pstrdup(pool, eq + 1);
|
|
Packit |
3adb1e |
if (realm_name[0] == '\"') {
|
|
Packit |
3adb1e |
apr_size_t realm_len;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
realm_len = strlen(realm_name);
|
|
Packit |
3adb1e |
if (realm_name[realm_len - 1] == '\"') {
|
|
Packit |
3adb1e |
realm_name[realm_len - 1] = '\0';
|
|
Packit |
3adb1e |
realm_name++;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
if (!realm_name) {
|
|
Packit |
3adb1e |
return SERF_ERROR_AUTHN_MISSING_ATTRIBUTE;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
realm = serf__construct_realm(code == 401 ? HOST : PROXY,
|
|
Packit |
3adb1e |
conn, realm_name,
|
|
Packit |
3adb1e |
pool);
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
/* Ask the application for credentials */
|
|
Packit |
3adb1e |
apr_pool_create(&cred_pool, pool);
|
|
Packit |
3adb1e |
status = serf__provide_credentials(ctx,
|
|
Packit |
3adb1e |
&username, &password,
|
|
Packit |
3adb1e |
request, baton,
|
|
Packit |
3adb1e |
code, authn_info->scheme->name,
|
|
Packit |
3adb1e |
realm, cred_pool);
|
|
Packit |
3adb1e |
if (status) {
|
|
Packit |
3adb1e |
apr_pool_destroy(cred_pool);
|
|
Packit |
3adb1e |
return status;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
tmp = apr_pstrcat(conn->pool, username, ":", password, NULL);
|
|
Packit |
3adb1e |
tmp_len = strlen(tmp);
|
|
Packit |
3adb1e |
apr_pool_destroy(cred_pool);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
serf__encode_auth_header(&basic_info->value,
|
|
Packit |
3adb1e |
authn_info->scheme->name,
|
|
Packit |
3adb1e |
tmp, tmp_len, pool);
|
|
Packit |
3adb1e |
basic_info->header = (code == 401) ? "Authorization" : "Proxy-Authorization";
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
return APR_SUCCESS;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
apr_status_t
|
|
Packit |
3adb1e |
serf__init_basic(int code,
|
|
Packit |
3adb1e |
serf_context_t *ctx,
|
|
Packit |
3adb1e |
apr_pool_t *pool)
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
return APR_SUCCESS;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
/* For Basic authentication we expect all authn info to be the same for all
|
|
Packit |
3adb1e |
connections in the context to the same server (same realm, username,
|
|
Packit |
3adb1e |
password). Therefore we can keep the header value in the per-server store
|
|
Packit |
3adb1e |
context instead of per connection.
|
|
Packit |
3adb1e |
TODO: we currently don't cache this info per realm, so each time a request
|
|
Packit |
3adb1e |
'switches realms', we have to ask the application for new credentials. */
|
|
Packit |
3adb1e |
apr_status_t
|
|
Packit |
3adb1e |
serf__init_basic_connection(const serf__authn_scheme_t *scheme,
|
|
Packit |
3adb1e |
int code,
|
|
Packit |
3adb1e |
serf_connection_t *conn,
|
|
Packit |
3adb1e |
apr_pool_t *pool)
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
serf_context_t *ctx = conn->ctx;
|
|
Packit |
3adb1e |
serf__authn_info_t *authn_info;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
if (code == 401) {
|
|
Packit |
3adb1e |
authn_info = serf__get_authn_info_for_server(conn);
|
|
Packit |
3adb1e |
} else {
|
|
Packit |
3adb1e |
authn_info = &ctx->proxy_authn_info;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
if (!authn_info->baton) {
|
|
Packit |
3adb1e |
authn_info->baton = apr_pcalloc(pool, sizeof(basic_authn_info_t));
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
return APR_SUCCESS;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
apr_status_t
|
|
Packit |
3adb1e |
serf__setup_request_basic_auth(peer_t peer,
|
|
Packit |
3adb1e |
int code,
|
|
Packit |
3adb1e |
serf_connection_t *conn,
|
|
Packit |
3adb1e |
serf_request_t *request,
|
|
Packit |
3adb1e |
const char *method,
|
|
Packit |
3adb1e |
const char *uri,
|
|
Packit |
3adb1e |
serf_bucket_t *hdrs_bkt)
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
serf_context_t *ctx = conn->ctx;
|
|
Packit |
3adb1e |
serf__authn_info_t *authn_info;
|
|
Packit |
3adb1e |
basic_authn_info_t *basic_info;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
if (peer == HOST) {
|
|
Packit |
3adb1e |
authn_info = serf__get_authn_info_for_server(conn);
|
|
Packit |
3adb1e |
} else {
|
|
Packit |
3adb1e |
authn_info = &ctx->proxy_authn_info;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
basic_info = authn_info->baton;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
if (basic_info && basic_info->header && basic_info->value) {
|
|
Packit |
3adb1e |
serf_bucket_headers_setn(hdrs_bkt, basic_info->header,
|
|
Packit |
3adb1e |
basic_info->value);
|
|
Packit |
3adb1e |
return APR_SUCCESS;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
return SERF_ERROR_AUTHN_FAILED;
|
|
Packit |
3adb1e |
}
|