31
34
return APR_SUCCESS;
37
/* These authentication schemes are in order of decreasing security, the topmost
38
scheme will be used first when the server supports it.
40
Each set of handlers should support both server (401) and proxy (407)
43
Use lower case for the scheme names to enable case insensitive matching.
34
45
static const serf__authn_scheme_t serf_authn_schemes[] = {
46
#ifdef SERF_HAVE_SPNEGO
52
serf__init_spnego_connection,
53
serf__handle_spnego_auth,
54
serf__setup_request_spnego_auth,
55
serf__validate_response_spnego_auth,
63
serf__init_spnego_connection,
64
serf__handle_spnego_auth,
65
serf__setup_request_spnego_auth,
66
serf__validate_response_spnego_auth,
68
#endif /* #ifdef WIN32 */
69
#endif /* SERF_HAVE_SPNEGO */
75
serf__init_digest_connection,
76
serf__handle_digest_auth,
77
serf__setup_request_digest_auth,
78
serf__validate_response_digest_auth,
40
85
serf__init_basic_connection,
42
87
serf__setup_request_basic_auth,
43
88
default_auth_response_handler,
50
serf__init_basic_connection,
51
serf__handle_basic_auth,
52
serf__setup_request_basic_auth,
53
default_auth_response_handler,
60
serf__init_digest_connection,
61
serf__handle_digest_auth,
62
serf__setup_request_digest_auth,
63
serf__validate_response_digest_auth,
70
serf__init_digest_connection,
71
serf__handle_digest_auth,
72
serf__setup_request_digest_auth,
73
serf__validate_response_digest_auth,
81
serf__init_kerb_connection,
82
serf__handle_kerb_auth,
83
serf__setup_request_kerb_auth,
84
serf__validate_response_kerb_auth,
87
90
/* ADD NEW AUTHENTICATION IMPLEMENTATIONS HERE (as they're written) */
132
120
* Returns a non-0 value of a matching handler was found.
134
static int handle_auth_header(void *baton,
122
static int handle_auth_headers(int code,
125
serf_request_t *request,
126
serf_bucket_t *response,
129
const serf__authn_scheme_t *scheme;
130
serf_connection_t *conn = request->conn;
131
serf_context_t *ctx = conn->ctx;
134
status = SERF_ERROR_AUTHN_NOT_SUPPORTED;
136
/* Find the matching authentication handler.
137
Note that we don't reuse the auth scheme stored in the context,
138
as that may have changed. (ex. fallback from ntlm to basic.) */
139
for (scheme = serf_authn_schemes; scheme->name != 0; ++scheme) {
140
const char *auth_hdr;
141
serf__auth_handler_func_t handler;
142
serf__authn_info_t *authn_info;
144
if (! (ctx->authn_types & scheme->type))
147
serf__log_skt(AUTH_VERBOSE, __FILE__, conn->skt,
148
"Client supports: %s\n", scheme->name);
150
auth_hdr = apr_hash_get(hdrs, scheme->key, APR_HASH_KEY_STRING);
156
authn_info = serf__get_authn_info_for_server(conn);
158
authn_info = &ctx->proxy_authn_info;
161
if (authn_info->failed_authn_types & scheme->type) {
162
/* Skip this authn type since we already tried it before. */
166
/* Found a matching scheme */
167
status = APR_SUCCESS;
169
handler = scheme->handle_func;
171
serf__log_skt(AUTH_VERBOSE, __FILE__, conn->skt,
172
"... matched: %s\n", scheme->name);
174
/* If this is the first time we use this scheme on this context and/or
175
this connection, make sure to initialize the authentication handler
177
if (authn_info->scheme != scheme) {
178
status = scheme->init_ctx_func(code, ctx, ctx->pool);
180
status = scheme->init_conn_func(scheme, code, conn,
183
authn_info->scheme = scheme;
185
authn_info->scheme = NULL;
190
const char *auth_attr = strchr(auth_hdr, ' ');
195
status = handler(code, request, response,
196
auth_hdr, auth_attr, baton, ctx->pool);
199
if (status == APR_SUCCESS)
202
/* No success authenticating with this scheme, try the next.
203
If no more authn schemes are found the status of this scheme will be
206
serf__log_skt(AUTH_VERBOSE, __FILE__, conn->skt,
207
"%s authentication failed.\n", scheme->name);
209
/* Clear per-request auth_baton when switching to next auth scheme. */
210
request->auth_baton = NULL;
212
/* Remember failed auth types to skip in future. */
213
authn_info->failed_authn_types |= scheme->type;
220
* Baton passed to the store_header_in_dict callback function
228
static int store_header_in_dict(void *baton,
138
232
auth_baton_t *ab = baton;
139
int scheme_found = FALSE;
140
const char *auth_name;
141
233
const char *auth_attr;
142
const serf__authn_scheme_t *scheme = NULL;
143
serf_connection_t *conn = ab->request->conn;
144
serf_context_t *ctx = conn->ctx;
146
236
/* We're only interested in xxxx-Authenticate headers. */
147
if (strcmp(key, ab->header) != 0)
237
if (strcasecmp(key, ab->header) != 0)
150
/* Extract the authentication scheme name, and prepare for reading
240
/* Extract the authentication scheme name. */
152
241
auth_attr = strchr(header, ' ');
154
243
auth_name = apr_pstrmemdup(ab->pool, header, auth_attr - header);
160
ab->last_scheme_name = auth_name;
162
/* Find the matching authentication handler.
163
Note that we don't reuse the auth scheme stored in the context,
164
as that may have changed. (ex. fallback from ntlm to basic.) */
165
for (scheme = serf_authn_schemes; scheme->code != 0; ++scheme) {
166
if (ab->code == scheme->code &&
167
strcmp(auth_name, scheme->name) == 0 &&
168
ctx->authn_types & scheme->type) {
169
serf__auth_handler_func_t handler = scheme->handle_func;
170
apr_status_t status = 0;
172
/* If this is the first time we use this scheme on this connection,
173
make sure to initialize the authentication handler first. */
174
if (ab->code == 401 && ctx->authn_info.scheme != scheme) {
175
status = scheme->init_ctx_func(ab->code, ctx, ctx->pool);
177
status = scheme->init_conn_func(ab->code, conn, conn->pool);
180
ctx->authn_info.scheme = scheme;
182
ctx->authn_info.scheme = NULL;
185
else if (ab->code == 407 && ctx->proxy_authn_info.scheme != scheme) {
186
status = scheme->init_ctx_func(ab->code, ctx, ctx->pool);
188
status = scheme->init_conn_func(ab->code, conn, conn->pool);
191
ctx->proxy_authn_info.scheme = scheme;
193
ctx->proxy_authn_info.scheme = NULL;
200
status = handler(ab->code, ab->request, ab->response,
201
header, auth_attr, ab->baton, ctx->pool);
204
/* If the authentication fails, cache the error for now. Try the
205
next available scheme. If there's none raise the error. */
207
scheme_found = FALSE;
210
/* Let the caller now if the authentication setup was succesful
218
/* If a matching scheme handler was found, we can stop iterating
219
over the response headers - so return a non-0 value. */
246
auth_name = apr_pstrmemdup(ab->pool, header, strlen(header));
248
/* Convert scheme name to lower case to enable case insensitive matching. */
249
for (c = auth_name; *c != '\0'; c++)
250
*c = (char)apr_tolower(*c);
252
apr_hash_set(ab->hdrs, auth_name, APR_HASH_KEY_STRING,
253
apr_pstrdup(ab->pool, header));
223
258
/* Dispatch authentication handling. This function matches the possible
338
369
/* Requeue the request with the necessary auth headers. */
339
370
/* ### Application doesn't know about this request! */
340
serf_connection_priority_request_create(request->conn,
342
request->setup_baton);
371
if (request->ssltunnel) {
372
serf__ssltunnel_request_create(request->conn,
374
request->setup_baton);
376
serf_connection_priority_request_create(request->conn,
378
request->setup_baton);
383
serf__validate_response_func_t validate_resp;
384
serf_connection_t *conn = request->conn;
385
serf_context_t *ctx = conn->ctx;
386
serf__authn_info_t *authn_info;
387
apr_status_t resp_status = APR_SUCCESS;
390
/* Validate the response server authn headers. */
391
authn_info = serf__get_authn_info_for_server(conn);
392
if (authn_info->scheme) {
393
validate_resp = authn_info->scheme->validate_response_func;
394
resp_status = validate_resp(authn_info->scheme, HOST, sl.code,
395
conn, request, response, pool);
398
/* Validate the response proxy authn headers. */
399
authn_info = &ctx->proxy_authn_info;
400
if (!resp_status && authn_info->scheme) {
401
validate_resp = authn_info->scheme->validate_response_func;
402
resp_status = validate_resp(authn_info->scheme, PROXY, sl.code,
403
conn, request, response, pool);
407
/* If there was an error in the final step of the authentication,
408
consider the reponse body as invalid and discard it. */
409
status = discard_body(response);
410
*consumed_response = 1;
411
if (!APR_STATUS_IS_EOF(status)) {
414
/* The whole body was discarded, now return our error. */
347
419
return APR_SUCCESS;
373
445
apr_base64_encode(ptr, data, data_len);
448
const char *serf__construct_realm(peer_t peer,
449
serf_connection_t *conn,
450
const char *realm_name,
454
return apr_psprintf(pool, "<%s://%s:%d> %s",
455
conn->host_info.scheme,
456
conn->host_info.hostname,
457
conn->host_info.port,
460
serf_context_t *ctx = conn->ctx;
462
return apr_psprintf(pool, "<http://%s:%d> %s",
463
ctx->proxy_address->hostname,
464
ctx->proxy_address->port,
469
serf__authn_info_t *serf__get_authn_info_for_server(serf_connection_t *conn)
471
serf_context_t *ctx = conn->ctx;
472
serf__authn_info_t *authn_info;
474
authn_info = apr_hash_get(ctx->server_authn_info, conn->host_url,
475
APR_HASH_KEY_STRING);
478
authn_info = apr_pcalloc(ctx->pool, sizeof(serf__authn_info_t));
479
apr_hash_set(ctx->server_authn_info,
480
apr_pstrdup(ctx->pool, conn->host_url),
481
APR_HASH_KEY_STRING, authn_info);