Author: brane
Date: Mon Jun 16 03:19:00 2025
New Revision: 1926453
URL: http://svn.apache.org/viewvc?rev=1926453&view=rev
Log:
On the user-defined-authn branch: start figuring out how the public authn
callbacks will look like, and what sort of support from the implementation
they'll need.
* serf.h
(SERF_AUTHN_FLAG_NONE,
SERF_AUTHN_FLAG_PIPE,
SERF_AUTHN_FLAG_CREDS): Bit mask constants for authn scheme requirements.
(serf_authn_handle_func_t,
serf_authn_handle_func_t,
serf_authn_setup_request_func_t,
serf_authn_validate_response_func_t): Declare callback types. Still mostly
guesswork as to what the actual arguments will be like.
(serf_authn_register_scheme): Add the flags and callback arguments.
(serf_request_bucket_request_create): Fix typo in docstring.
* auth/auth.h
(serf__authn_scheme_t::user_magic): Renamed from 'magic'.
(serf__authn_scheme_t::user_baton): Renamed from baton'.
(serf__authn_scheme_t::user_flags,
serf__authn_scheme_t::user_init_conn_func,
serf__authn_scheme_t::user_handle_func,
serf__authn_scheme_t::user_setup_request_func,
serf__authn_scheme_t::user_validate_response_func): New members.
* auth/auth.c
(serf_authn_register_scheme): Add and store the new parameters
to the authn descriptor struct.
* auth/auth_user_defined.c
(validate_user_authn): Change magic -> user_magic.
(get_authn_info): New helper function.
(authn_baton_wrapper): New; the per-connection authentication baton.
(serf__authn_user__init_conn): Implement connection initialization.
(serf__authn_user__handle,
serf__authn_user__setup_request,
serf__authn_user__validate_response): Add logging to argument validation.
* serf_private.h
(serf__connection_set_pipelining): Change the return type.
* src/outgoing.c
(serf__connection_set_pipelining): Return the previous pipelining state.
* test/test_auth.c
(test_authn_register_one,
test_authn_register_two,
test_authn_register_twice): Update calls to serf_authn_register_scheme.
(user_authn_baton, user_authn_t): Baton type for user-defined authn tests.
(USER_AUTHN_COUNT): Helper macro for counting callback invocations.
(user_authn_make_baton): Allocation helper for user_authn_t.
(user_authn_cache, user_authn_baton_t): Per-connection authn baton type.
(user_authn_prefix): Helper string for validation.
(user_authn_init_conn): Complete connection-init callback.
(user_authn_handle,
user_authn_setup_request,
user_authn_validate_response): Placeholders for the other three callbacks.
(user_authn_credentials_callback): Credentials callback for user-authn tests.
(user_authentication): Partial test for user authentication.
(test_user_authentication,
test_user_authentication_keepalive_off): Two entry points for this test.
(test_auth): Register only test_user_authentication for now.
* test/test_util.c
(setup_test_context): Duh. Set up logging only once per new context.
Modified:
serf/branches/user-defined-authn/auth/auth.c
serf/branches/user-defined-authn/auth/auth.h
serf/branches/user-defined-authn/auth/auth_user_defined.c
serf/branches/user-defined-authn/serf.h
serf/branches/user-defined-authn/serf_private.h
serf/branches/user-defined-authn/src/outgoing.c
serf/branches/user-defined-authn/test/test_auth.c
serf/branches/user-defined-authn/test/test_util.c
Modified: serf/branches/user-defined-authn/auth/auth.c
URL:
http://svn.apache.org/viewvc/serf/branches/user-defined-authn/auth/auth.c?rev=1926453&r1=1926452&r2=1926453&view=diff
==============================================================================
--- serf/branches/user-defined-authn/auth/auth.c (original)
+++ serf/branches/user-defined-authn/auth/auth.c Mon Jun 16 03:19:00 2025
@@ -623,11 +623,14 @@ static unsigned int find_next_user_schem
return avail & -avail;
}
-apr_status_t serf_authn_register_scheme(serf_context_t *ctx,
- const char *name,
- void *baton,
- apr_pool_t *result_pool,
- int *type)
+apr_status_t serf_authn_register_scheme(
+ serf_context_t *ctx, const char *name, void *baton, int flags,
+ serf_authn_init_conn_func_t init_conn,
+ serf_authn_handle_func_t handle,
+ serf_authn_setup_request_func_t setup_request,
+ serf_authn_validate_response_func_t validate_response,
+ apr_pool_t *result_pool,
+ int *type)
{
serf__authn_scheme_t *authn_scheme;
apr_status_t lock_status;
@@ -655,8 +658,13 @@ apr_status_t serf_authn_register_scheme(
authn_scheme->validate_response_func = serf__authn_user__validate_response;
/* User-defined scheme data. */
- authn_scheme->magic = serf__authn_user__magic;
- authn_scheme->baton = baton;
+ authn_scheme->user_magic = serf__authn_user__magic;
+ authn_scheme->user_baton = baton;
+ authn_scheme->user_flags = flags;
+ authn_scheme->user_init_conn_func = init_conn;
+ authn_scheme->user_handle_func = handle;
+ authn_scheme->user_setup_request_func = setup_request;
+ authn_scheme->user_validate_response_func = validate_response;
lock_status = lock_authn_schemes(ctx->config);
if (lock_status)
Modified: serf/branches/user-defined-authn/auth/auth.h
URL:
http://svn.apache.org/viewvc/serf/branches/user-defined-authn/auth/auth.h?rev=1926453&r1=1926452&r2=1926453&view=diff
==============================================================================
--- serf/branches/user-defined-authn/auth/auth.h (original)
+++ serf/branches/user-defined-authn/auth/auth.h Mon Jun 16 03:19:00 2025
@@ -114,10 +114,19 @@ struct serf__authn_scheme_t {
*/
/* The magic number that helps verify the user-defined scheme data. */
- apr_uint64_t magic;
+ apr_uint64_t user_magic;
+
+ /* The flags for this authentication scheme */
+ int user_flags;
/* The baton used by the callbacks. */
- void *baton;
+ void *user_baton;
+
+ /* Authentication callbacks. */
+ serf_authn_init_conn_func_t user_init_conn_func;
+ serf_authn_handle_func_t user_handle_func;
+ serf_authn_setup_request_func_t user_setup_request_func;
+ serf_authn_validate_response_func_t user_validate_response_func;
};
Modified: serf/branches/user-defined-authn/auth/auth_user_defined.c
URL:
http://svn.apache.org/viewvc/serf/branches/user-defined-authn/auth/auth_user_defined.c?rev=1926453&r1=1926452&r2=1926453&view=diff
==============================================================================
--- serf/branches/user-defined-authn/auth/auth_user_defined.c (original)
+++ serf/branches/user-defined-authn/auth/auth_user_defined.c Mon Jun 16
03:19:00 2025
@@ -25,25 +25,101 @@
#include "auth.h"
-static const bool
-validate_user_authn(const serf__authn_scheme_t *scheme)
+static bool validate_user_authn(const serf__authn_scheme_t *scheme)
{
return (scheme->type & *serf__authn_user__type_mask
- && scheme->magic == serf__authn_user__magic);
+ && scheme->user_magic == serf__authn_user__magic);
}
+
+static serf__authn_info_t *get_authn_info(int code, serf_connection_t *conn)
+{
+ switch (code)
+ {
+ case SERF_AUTHN_CODE_HOST:
+ return serf__get_authn_info_for_server(conn);
+ case SERF_AUTHN_CODE_PROXY:
+ return &conn->ctx->proxy_authn_info;
+ }
+
+ /* FIXME: ??? Shouldn't be possible. */
+ return NULL;
+}
+
+
+/* Used for serf__authn_info_t::baton */
+struct callback_authn_baton {
+ /* The connection's pipelining state before we changed it. */
+ int pipelining;
+
+ /* The user-defined scheme's per-connection baton. */
+ void *user_authn_baton;
+};
+
+
apr_status_t
serf__authn_user__init_conn(const serf__authn_scheme_t *scheme,
int code,
serf_connection_t *conn,
apr_pool_t *pool)
{
- if (!validate_user_authn(scheme))
+ serf__authn_info_t *const authn_info = get_authn_info(code, conn);
+ struct callback_authn_baton *authn_baton;
+ apr_status_t status = APR_SUCCESS;
+
+ serf__log(LOGLVL_DEBUG, LOGCOMP_AUTHN, __FILE__, conn->config,
+ "User-defined scheme %s: callback: init-conn\n",
+ scheme->name);
+
+ if (!validate_user_authn(scheme)) {
+ serf__log(LOGLVL_ERROR, LOGCOMP_AUTHN, __FILE__, conn->config,
+ "Not a user-defined scheme: %s\n", scheme->name);
return APR_EINVAL;
-
- return APR_ENOTIMPL;
+ }
+ if (!scheme->user_init_conn_func) {
+ serf__log(LOGLVL_ERROR, LOGCOMP_AUTHN, __FILE__, conn->config,
+ "User-defined scheme %s: missing callback: init-conn\n",
+ scheme->name);
+ return APR_ENOTIMPL;
+ }
+ if (!authn_info) {
+ serf__log(LOGLVL_ERROR, LOGCOMP_AUTHN, __FILE__, conn->config,
+ "User-defined scheme %s init-conn: invalid code: %d\n",
+ scheme->name, code);
+ return APR_ERANGE;
+ }
+
+ authn_baton = authn_info->baton;
+ if (authn_baton == NULL) {
+ apr_pool_t *scratch_pool;
+
+ serf__log(LOGLVL_DEBUG, LOGCOMP_AUTHN, __FILE__, conn->config,
+ "User-defined scheme %s: create authn baton\n",
+ scheme->name);
+
+ apr_pool_create(&scratch_pool, pool);
+ authn_baton = apr_pcalloc(pool, sizeof(*authn_baton));
+ status = scheme->user_init_conn_func(scheme->user_baton, code,
+ pool, scratch_pool,
+ &authn_baton->user_authn_baton);
+ apr_pool_destroy(scratch_pool);
+
+ if (status == APR_SUCCESS)
+ authn_info->baton = authn_baton;
+ }
+
+ /* Turn off pipelining if the scheme requires it. */
+ if (status == APR_SUCCESS
+ && !(scheme->user_flags & SERF_AUTHN_FLAG_PIPE)) {
+ serf__log(LOGLVL_DEBUG, LOGCOMP_AUTHN, __FILE__, conn->config,
+ "User-defined scheme %s: pipelining off for %s\n",
+ scheme->name, conn->host_url);
+ authn_baton->pipelining = serf__connection_set_pipelining(conn, 0);
+ }
+ return status;
}
+
apr_status_t
serf__authn_user__handle(const serf__authn_scheme_t *scheme,
int code,
@@ -53,12 +129,26 @@ serf__authn_user__handle(const serf__aut
const char *auth_attr,
apr_pool_t *pool)
{
- if (!validate_user_authn(scheme))
+ serf__log(LOGLVL_DEBUG, LOGCOMP_AUTHN, __FILE__, request->conn->config,
+ "User-defined scheme %s: callback: handle-auth\n",
+ scheme->name);
+
+ if (!validate_user_authn(scheme)) {
+ serf__log(LOGLVL_ERROR, LOGCOMP_AUTHN, __FILE__, request->conn->config,
+ "Not a user-defined scheme: %s\n", scheme->name);
return APR_EINVAL;
+ }
+ if (!scheme->user_handle_func) {
+ serf__log(LOGLVL_ERROR, LOGCOMP_AUTHN, __FILE__, request->conn->config,
+ "User-defined scheme %s: missing callback: handle-auth\n",
+ scheme->name);
+ return APR_ENOTIMPL;
+ }
return APR_ENOTIMPL;
}
+
apr_status_t
serf__authn_user__setup_request(const serf__authn_scheme_t *scheme,
peer_t peer,
@@ -69,12 +159,26 @@ serf__authn_user__setup_request(const se
const char *uri,
serf_bucket_t *hdrs_bkt)
{
- if (!validate_user_authn(scheme))
+ serf__log(LOGLVL_DEBUG, LOGCOMP_AUTHN, __FILE__, conn->config,
+ "User-defined scheme %s: callback: setup-request\n",
+ scheme->name);
+
+ if (!validate_user_authn(scheme)) {
+ serf__log(LOGLVL_ERROR, LOGCOMP_AUTHN, __FILE__, conn->config,
+ "Not a user-defined scheme: %s\n", scheme->name);
return APR_EINVAL;
+ }
+ if (!scheme->user_setup_request_func) {
+ serf__log(LOGLVL_ERROR, LOGCOMP_AUTHN, __FILE__, conn->config,
+ "User-defined scheme %s: missing callback: setup-request\n",
+ scheme->name);
+ return APR_ENOTIMPL;
+ }
return APR_ENOTIMPL;
}
+
apr_status_t
serf__authn_user__validate_response(const serf__authn_scheme_t *scheme,
peer_t peer,
@@ -84,8 +188,22 @@ serf__authn_user__validate_response(cons
serf_bucket_t *response,
apr_pool_t *pool)
{
- if (!validate_user_authn(scheme))
+ serf__log(LOGLVL_DEBUG, LOGCOMP_AUTHN, __FILE__, conn->config,
+ "User-defined scheme %s: callback: validate-response\n",
+ scheme->name);
+
+ if (!validate_user_authn(scheme)) {
+ serf__log(LOGLVL_ERROR, LOGCOMP_AUTHN, __FILE__, conn->config,
+ "Not a user-defined scheme: %s\n", scheme->name);
return APR_EINVAL;
+ }
+ if (!scheme->user_validate_response_func) {
+ serf__log(LOGLVL_ERROR, LOGCOMP_AUTHN, __FILE__, conn->config,
+ "User-defined scheme %s:"
+ " missing callback: validate-response\n",
+ scheme->name);
+ return APR_ENOTIMPL;
+ }
return APR_ENOTIMPL;
}
Modified: serf/branches/user-defined-authn/serf.h
URL:
http://svn.apache.org/viewvc/serf/branches/user-defined-authn/serf.h?rev=1926453&r1=1926452&r2=1926453&view=diff
==============================================================================
--- serf/branches/user-defined-authn/serf.h (original)
+++ serf/branches/user-defined-authn/serf.h Mon Jun 16 03:19:00 2025
@@ -966,18 +966,73 @@ serf_bucket_t *serf_request_bucket_reque
#define SERF_AUTHN_CODE_HOST 401 /**< Authentication request from a host */
#define SERF_AUTHN_CODE_PROXY 407 /**< Authentication requset from a proxy */
+/* Flags returned from the init-connection callback. */
+#define SERF_AUTHN_FLAG_NONE 0x00 /**< Authn flags: None */
+#define SERF_AUTHN_FLAG_PIPE 0x01 /**< Authn flags: Allow pipelining */
+#define SERF_AUTHN_FLAG_CREDS 0x02 /**< Authn flags: Require credentials */
+
+/** TODO: */
+typedef apr_status_t
+(*serf_authn_init_conn_func_t)(void *baton, int code,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool,
+ void **authn_baton);
+
+/** TODO: */
+typedef apr_status_t
+(*serf_authn_handle_func_t)(void *baton,
+ int code,
+ serf_request_t *request,
+ serf_bucket_t *response,
+ const char *auth_hdr,
+ const char *auth_attr,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+
+/** TODO: */
+typedef apr_status_t
+(*serf_authn_setup_request_func_t)(void *baton,
+ int peer,
+ int code,
+ serf_connection_t *conn,
+ serf_request_t *request,
+ const char *method,
+ const char *uri,
+ serf_bucket_t *headers,
+ apr_pool_t *scratch_pool);
+
+/** TODO: */
+typedef apr_status_t
+(*serf_authn_validate_response_func_t)(void *baton,
+ int peer,
+ int code,
+ serf_connection_t *conn,
+ serf_request_t *request,
+ serf_bucket_t *response,
+ apr_pool_t *scratch_pool);
+
/**
* Register an autehtication scheme.
*
- * The number returned in @a type can be used as a bit mask in
- * serf_config_authn_types(). If an error occurs during registration,
- * @a type will be set to @c SERF_AUTHN_NONE.
+ * The context in @a ctx is used for logging.
*
* The @a name is the name of the authentication scheme as it appears in the
* authorization headers. It must be a valid token as defined in RFC-9110
* (see reference, below).
*
- * The context in @a ctx is used for logging.
+ * @a baton will be passed unchanged to the callbacks.
+ *
+ * @a flags is a bitmask of @c APR_AUTHN_FLAG_* constants that define the
+ * scheme's requirements; e.g., whether the credentials callback should be
+ * invoked, or whether pipelining should be disabled while the authentication
+ * handshake is in progress.
+ *
+ * @a init_conn, @a handle, @a setup_request and @a validate_response are the
+ * callbacks that implement the authentication handshake for this scheme.
+ *
+ * The number returned in @a type can be used as a bit mask in
+ * serf_config_authn_types(). If an error occurs during registration,
+ * @a type will be set to @c SERF_AUTHN_NONE.
*
* Internal structures related to this provider will be allocated from
* @a result_pool, so take care that it lives as long as the autehtication
@@ -986,11 +1041,14 @@ serf_bucket_t *serf_request_bucket_reque
* @see https://www.rfc-editor.org/rfc/rfc9110#section-11.1
* @since New in 1.4
*/
-apr_status_t serf_authn_register_scheme(serf_context_t *ctx,
- const char *name,
- void *baton,
- apr_pool_t *result_pool,
- int *type);
+apr_status_t serf_authn_register_scheme(
+ serf_context_t *ctx, const char *name, void *baton, int flags,
+ serf_authn_init_conn_func_t init_conn,
+ serf_authn_handle_func_t handle,
+ serf_authn_setup_request_func_t setup_request,
+ serf_authn_validate_response_func_t validate_response,
+ apr_pool_t *result_pool,
+ int *type);
/* FIXME: Think some more about whether unregistering schemes makes sense. */
/**
@@ -999,8 +1057,8 @@ apr_status_t serf_authn_register_scheme(
* Removes the scheme, identified by @a type that was returned from and
* @a name that was supplied to serf_authn_register_scheme(), from the
* list of supported authentication schemes. Uses @a scratch_pool for
- * temporary allocations; this pool can be destroyed afterthe function
- * returns.
+ * temporary allocations; this pool can be destroyed after the function
+ * has returned.
*
* The context in @a ctx is used for logging.
*
Modified: serf/branches/user-defined-authn/serf_private.h
URL:
http://svn.apache.org/viewvc/serf/branches/user-defined-authn/serf_private.h?rev=1926453&r1=1926452&r2=1926453&view=diff
==============================================================================
--- serf/branches/user-defined-authn/serf_private.h (original)
+++ serf/branches/user-defined-authn/serf_private.h Mon Jun 16 03:19:00 2025
@@ -741,7 +741,7 @@ apr_status_t serf__conn_update_pollset(s
serf_request_t *serf__ssltunnel_request_create(serf_connection_t *conn,
serf_request_setup_t setup,
void *setup_baton);
-void serf__connection_set_pipelining(serf_connection_t *conn, int enabled);
+int serf__connection_set_pipelining(serf_connection_t *conn, int enabled);
apr_status_t serf__connection_flush(serf_connection_t *conn,
bool fetch_new);
Modified: serf/branches/user-defined-authn/src/outgoing.c
URL:
http://svn.apache.org/viewvc/serf/branches/user-defined-authn/src/outgoing.c?rev=1926453&r1=1926452&r2=1926453&view=diff
==============================================================================
--- serf/branches/user-defined-authn/src/outgoing.c (original)
+++ serf/branches/user-defined-authn/src/outgoing.c Mon Jun 16 03:19:00 2025
@@ -1460,9 +1460,11 @@ void serf_connection_set_max_outstanding
HTTP pipelining can achieve this by calling:
serf_connection_set_max_outstanding_requests(conn, 1) .
*/
-void serf__connection_set_pipelining(serf_connection_t *conn, int enabled)
+int serf__connection_set_pipelining(serf_connection_t *conn, int enabled)
{
+ int pipelining = conn->pipelining;
conn->pipelining = enabled;
+ return pipelining;
}
void serf_connection_set_async_responses(
Modified: serf/branches/user-defined-authn/test/test_auth.c
URL:
http://svn.apache.org/viewvc/serf/branches/user-defined-authn/test/test_auth.c?rev=1926453&r1=1926452&r2=1926453&view=diff
==============================================================================
--- serf/branches/user-defined-authn/test/test_auth.c (original)
+++ serf/branches/user-defined-authn/test/test_auth.c Mon Jun 16 03:19:00 2025
@@ -531,8 +531,10 @@ static void test_authn_register_one(CuTe
CuAssertIntEquals(tc, APR_SUCCESS, status);
/* Register an authentication scheme */
- status = serf_authn_register_scheme(tb->context,
- "Fizzle", baton, tb->pool, &type);
+ status = serf_authn_register_scheme(tb->context, "Fizzle", baton,
+ SERF_AUTHN_FLAG_NONE,
+ NULL, NULL, NULL, NULL,
+ tb->pool, &type);
CuAssertIntEquals(tc, APR_SUCCESS, status);
CuAssertTrue(tc, type != SERF_AUTHN_NONE);
@@ -554,13 +556,17 @@ static void test_authn_register_two(CuTe
CuAssertIntEquals(tc, APR_SUCCESS, status);
/* Register the schemes */
- status = serf_authn_register_scheme(tb->context,
- "Tweedledee", baton1, tb->pool,
&type1);
+ status = serf_authn_register_scheme(tb->context, "Tweedledee", baton1,
+ SERF_AUTHN_FLAG_NONE,
+ NULL, NULL, NULL, NULL,
+ tb->pool, &type1);
CuAssertIntEquals(tc, APR_SUCCESS, status);
CuAssertTrue(tc, type1 != SERF_AUTHN_NONE);
- status = serf_authn_register_scheme(tb->context,
- "Tweedledum", baton2, tb->pool,
&type2);
+ status = serf_authn_register_scheme(tb->context, "Tweedledum", baton2,
+ SERF_AUTHN_FLAG_NONE,
+ NULL, NULL, NULL, NULL,
+ tb->pool, &type2);
CuAssertIntEquals(tc, APR_SUCCESS, status);
CuAssertTrue(tc, type2 != SERF_AUTHN_NONE);
CuAssertTrue(tc, type2 != type1);
@@ -585,13 +591,17 @@ static void test_authn_register_twice(Cu
CuAssertIntEquals(tc, APR_SUCCESS, status);
/* Register an authentication scheme */
- status = serf_authn_register_scheme(tb->context,
- "Tweens", baton, tb->pool, &type);
+ status = serf_authn_register_scheme(tb->context, "Tweens", baton,
+ SERF_AUTHN_FLAG_NONE,
+ NULL, NULL, NULL, NULL,
+ tb->pool, &type);
CuAssertIntEquals(tc, APR_SUCCESS, status);
CuAssertTrue(tc, type != SERF_AUTHN_NONE);
- status = serf_authn_register_scheme(tb->context,
- "Tweens", baton, tb->pool, &epyt);
+ status = serf_authn_register_scheme(tb->context, "Tweens", baton,
+ SERF_AUTHN_FLAG_NONE,
+ NULL, NULL, NULL, NULL,
+ tb->pool, &epyt);
CuAssertIntEquals(tc, APR_EEXIST, status);
CuAssertTrue(tc, epyt == SERF_AUTHN_NONE);
@@ -615,6 +625,213 @@ static void test_authn_unregister_unknow
CuAssertIntEquals(tc, APR_ENOENT, status);
}
+
+typedef struct user_authn_baton user_authn_t;
+struct user_authn_baton {
+ const char *name;
+ int all_count;
+ int init_conn_count;
+ int handle_count;
+ int setup_request_count;
+ int validate_response_count;
+};
+
+#define USER_AUTHN_COUNT(baton, callback) \
+ user_authn_t *const b = (baton); \
+ do { \
+ ++b->callback##_count; \
+ ++b->all_count; \
+ } while(0)
+
+static user_authn_t *user_authn_make_baton(const char* name, apr_pool_t *pool)
+{
+ user_authn_t *baton = apr_pcalloc(pool, sizeof(*baton));
+ baton->name = apr_pstrdup(pool, name);
+ return baton;
+}
+
+typedef struct user_authn_cache user_authn_baton_t;
+struct user_authn_cache {
+ const char *header;
+ const char *value;
+};
+
+static const char *const user_authn_prefix = "Tweedle";
+
+static apr_status_t user_authn_init_conn(void *baton, int code,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool,
+ void **authn_baton)
+{
+ USER_AUTHN_COUNT(baton, init_conn);
+
+ if (strncmp(user_authn_prefix, b->name, strlen(user_authn_prefix)) != 0)
+ return SERF_ERROR_AUTHN_INITALIZATION_FAILED;
+
+ *authn_baton = apr_pcalloc(result_pool, sizeof(user_authn_baton_t));
+ return APR_SUCCESS;
+}
+
+static apr_status_t user_authn_handle(void *baton,
+ int code,
+ serf_request_t *request,
+ serf_bucket_t *response,
+ const char *auth_hdr,
+ const char *auth_attr,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ USER_AUTHN_COUNT(baton, handle);
+ return APR_SUCCESS;
+}
+
+static apr_status_t user_authn_setup_request(void *baton,
+ int peer,
+ int code,
+ serf_connection_t *conn,
+ serf_request_t *request,
+ const char *method,
+ const char *uri,
+ serf_bucket_t *headers,
+ apr_pool_t *scratch_pool)
+{
+ USER_AUTHN_COUNT(baton, setup_request);
+ return APR_SUCCESS;
+}
+
+static apr_status_t user_authn_validate_response(void *baton,
+ int peer,
+ int code,
+ serf_connection_t *conn,
+ serf_request_t *request,
+ serf_bucket_t *response,
+ apr_pool_t *scratch_pool)
+{
+ USER_AUTHN_COUNT(baton, validate_response);
+ return APR_SUCCESS;
+}
+#undef USER_AUTHN_COUNT
+
+static apr_status_t
+user_authn_credentials_callback(char **username,
+ char **password,
+ serf_request_t *request, void *baton,
+ int code, const char *authn_type,
+ const char *scope,
+ apr_pool_t *pool)
+{
+ handler_baton_t *handler_ctx = baton;
+ test_baton_t *tb = handler_ctx->tb;
+
+ tb->result_flags |= TEST_RESULT_AUTHNCB_CALLED;
+
+ if (code != SERF_AUTHN_CODE_HOST)
+ return REPORT_TEST_SUITE_ERROR();
+ if (strncmp(user_authn_prefix, authn_type, strlen(user_authn_prefix)) != 0)
+ return REPORT_TEST_SUITE_ERROR();
+ if (strcmp("Alice", scope) != 0)
+ return REPORT_TEST_SUITE_ERROR();
+
+ *username = NULL;
+ *password = apr_pstrdup(pool, authn_type);
+
+ return APR_SUCCESS;
+}
+
+static void user_authentication(CuTest *tc, int close_conn)
+{
+ test_baton_t *tb = tc->testBaton;
+ handler_baton_t handler_ctx[2];
+ int num_requests_sent;
+ apr_status_t status;
+ int typedee, typedum;
+ user_authn_t *const tdee = user_authn_make_baton("TweedleDee", tb->pool);
+ user_authn_t *const tdum = user_authn_make_baton("TweedleDum", tb->pool);
+
+ status = setup_test_context(tb, tb->pool);
+ CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+ status = serf_authn_register_scheme(tb->context, tdee->name, tdee,
+ SERF_AUTHN_FLAG_CREDS
+ | SERF_AUTHN_FLAG_PIPE,
+ user_authn_init_conn,
+ user_authn_handle,
+ user_authn_setup_request,
+ user_authn_validate_response,
+ tb->pool, &typedee);
+ CuAssertIntEquals(tc, APR_SUCCESS, status);
+ CuAssertTrue(tc, typedee != SERF_AUTHN_NONE);
+
+ status = serf_authn_register_scheme(tb->context, tdum->name, tdum,
+ SERF_AUTHN_FLAG_CREDS
+ | SERF_AUTHN_FLAG_PIPE,
+ user_authn_init_conn,
+ user_authn_handle,
+ user_authn_setup_request,
+ user_authn_validate_response,
+ tb->pool, &typedum);
+ CuAssertIntEquals(tc, APR_SUCCESS, status);
+ CuAssertTrue(tc, typedum != SERF_AUTHN_NONE);
+ CuAssertTrue(tc, typedum != typedee);
+
+ /* Test that a request is retried and authentication
+ headers are set correctly. */
+ num_requests_sent = 1;
+
+ /* Set up a test context with a server */
+ setup_test_mock_server(tb);
+ status = setup_test_client_context(tb, NULL, tb->pool);
+ CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+ serf_config_authn_types(tb->context, typedee | typedum);
+ serf_config_credentials_callback(tb->context,
user_authn_credentials_callback);
+
+ /* Use non-standard case WWW-Authenticate header and scheme name to test
+ for case insensitive comparisons. */
+ Given(tb->mh)
+ GETRequest(URLEqualTo("/"), HeaderNotSet("Authorization"))
+ Respond(WithCode(SERF_AUTHN_CODE_HOST),WithChunkedBody("1"),
+ WithHeader("www-Authenticate", "tweeDlEdee scope=Alice"),
+ OnConditionThat(close_conn, WithConnectionCloseHeader))
+ GETRequest(URLEqualTo("/"),
+ HeaderEqualTo("Authorization", "TweedleDee TweedleDee"))
+ Respond(WithCode(200),WithChunkedBody(""))
+ Expect
+ AllRequestsReceivedInOrder
+ EndGiven
+
+ create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
+ status = run_client_and_mock_servers_loops(tb, num_requests_sent,
+ handler_ctx, tb->pool);
+ CuAssertIntEquals(tc, APR_SUCCESS, status);
+ CuAssertTrue(tc, tb->result_flags & TEST_RESULT_AUTHNCB_CALLED);
+ Verify(tb->mh)
+ CuAssertTrue(tc, VerifyAllExpectationsOk);
+ EndVerify
+
+ CuAssertIntEquals(tc, 4, tdee->all_count);
+ CuAssertIntEquals(tc, 0, tdum->all_count);
+
+ status = serf_authn_unregister_scheme(tb->context,
+ typedum, tdum->name, tb->pool);
+ CuAssertIntEquals(tc, APR_SUCCESS, status);
+ status = serf_authn_unregister_scheme(tb->context,
+ typedee, tdee->name, tb->pool);
+ CuAssertIntEquals(tc, APR_SUCCESS, status);
+}
+
+static void test_user_authentication(CuTest *tc)
+{
+ user_authentication(tc, 0 /* don't close connection */);
+}
+
+static void test_user_authentication_keepalive_off(CuTest *tc)
+{
+ user_authentication(tc, 1);
+}
+
+
+
/*****************************************************************************/
CuSuite *test_auth(void)
{
@@ -635,5 +852,8 @@ CuSuite *test_auth(void)
SUITE_ADD_TEST(suite, test_authn_register_two);
SUITE_ADD_TEST(suite, test_authn_register_twice);
SUITE_ADD_TEST(suite, test_authn_unregister_unknown);
+ SUITE_ADD_TEST(suite, test_user_authentication);
+ /* SUITE_ADD_TEST(suite, test_user_authentication_keepalive_off); */
+
return suite;
}
Modified: serf/branches/user-defined-authn/test/test_util.c
URL:
http://svn.apache.org/viewvc/serf/branches/user-defined-authn/test/test_util.c?rev=1926453&r1=1926452&r2=1926453&view=diff
==============================================================================
--- serf/branches/user-defined-authn/test/test_util.c (original)
+++ serf/branches/user-defined-authn/test/test_util.c Mon Jun 16 03:19:00 2025
@@ -427,17 +427,18 @@ setup_test_context(test_baton_t *tb, apr
serf_log_output_t *output;
apr_status_t status = APR_SUCCESS;
- if (!tb->context)
+ if (!tb->context) {
tb->context = serf_context_create(pool);
- if (TEST_VERBOSE) {
- status = serf_logging_create_stream_output(&output, tb->context,
- SERF_LOG_DEBUG,
- SERF_LOGCOMP_ALL,
- SERF_LOG_DEFAULT_LAYOUT,
- stderr, pool);
- if (status == APR_SUCCESS)
- status = serf_logging_add_output(tb->context, output);
+ if (TEST_VERBOSE) {
+ status = serf_logging_create_stream_output(&output, tb->context,
+ SERF_LOG_DEBUG,
+ SERF_LOGCOMP_ALL,
+ SERF_LOG_DEFAULT_LAYOUT,
+ stderr, pool);
+ if (status == APR_SUCCESS)
+ status = serf_logging_add_output(tb->context, output);
+ }
}
return status;