From 2989ee8b72ddb3995e5a4686c988385d05493365 Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Tue, 7 Jul 2009 20:05:29 +0000 Subject: Implement simple AX attribute exchange. * Does not yet handle setting attributes from the cookie. --- module/mod_auth_singleid.c | 130 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 124 insertions(+), 6 deletions(-) (limited to 'module/mod_auth_singleid.c') diff --git a/module/mod_auth_singleid.c b/module/mod_auth_singleid.c index 2e46586..d2e53e8 100644 --- a/module/mod_auth_singleid.c +++ b/module/mod_auth_singleid.c @@ -73,6 +73,7 @@ extern module AP_MODULE_DECLARE_DATA auth_singleid_module; #define VALID_NAME "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-." +#define VALID_ALIAS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-" enum { NONE = 0, @@ -90,10 +91,35 @@ typedef struct sid_context { int user_match; ap_regex_t *converter; sid_storage_t *store; + sid_attribute_t *attributes; } sid_context_t; #define SID_AUTHTYPE "SingleID" +/* ------------------------------------------------------------------------------- + * UTILITY + */ + +static void +strupcase(char *str) +{ + while (*str) { + *str = apr_toupper(*str); + ++str; + } +} + +static char* +safe_get_token (apr_pool_t *pool, const char **line, int accept_white) +{ + /* HACK: ap_get_token() endless loop if string starts with delim */ + const char *orig = *line; + char *result = ap_get_token (pool, line, accept_white); + if (orig == *line && orig[0]) + (*line)++; + return result; +} + /* ------------------------------------------------------------------------------- * SHARED MEMORY and LOCKING */ @@ -344,6 +370,67 @@ set_cookie_name (cmd_parms *cmd, void *config, const char *val) return NULL; } +static const char* +set_attribute (cmd_parms *cmd, void *config, const char *val) +{ + sid_context_t *ctx = config; + sid_attribute_t attr, *at; + const char *flag; + char *end; + + memset (&attr, 0, sizeof (attr)); + attr.count = 1; + + /* First word is the alias */ + attr.alias = ap_getword_conf (cmd->pool, &val); + if (!attr.alias || strspn (attr.alias, VALID_ALIAS) != strlen (attr.alias)) + return "Invalid attribute alias"; + + /* Check if we already have this alias */ + for (at = ctx->attributes; at; at = at->next) { + if (strcasecmp (at->alias, attr.alias) == 0) + return "Duplicate attribute alias"; + } + + /* Next word is the url */ + attr.url = ap_getword_conf (cmd->pool, &val); + if (!attr.url || !ap_is_url (attr.url)) + return "Invalid attribute URL"; + + /* Now come all the various flags */ + for (;;) { + flag = ap_getword_conf (cmd->pool, &val); + if (!flag || !flag[0]) + break; + + if (strcasecmp (flag, "required") == 0) { + attr.required = 1; + + } else if (strcasecmp (flag, "unlimited") == 0) { + attr.count = 0; + + } else { + attr.count = strtol (flag, &end, 10); + if (*end != '\0') { + if (attr.count != 0) + return "Invalid attribute count"; + else + return "Unrecognized value or flag"; + } + if (attr.count <= 0) + return "Attribute count must a number greater than zero or 'unlimited'"; + } + } + + /* Instantiate the copy */ + attr.next = ctx->attributes; + at = apr_pcalloc (cmd->pool, sizeof (attr)); + memcpy (at, &attr, sizeof (attr)); + ctx->attributes = at; + + return NULL; +} + static const command_rec command_table[] = { AP_INIT_TAKE1 ("SingleIdentifier", set_identifier, NULL, OR_AUTHCFG, "The OpenID identifier we should perform ID selection on when authenticating" ), @@ -355,6 +442,8 @@ static const command_rec command_table[] = { "Set the cookie name used once user has logged in via OpenID"), AP_INIT_RAW_ARGS ("SingleUserMatch", set_user_match, NULL, OR_AUTHCFG, "How to convert an OpenID identifier into a user name" ), + AP_INIT_RAW_ARGS ("SingleAttribute", set_attribute, NULL, OR_AUTHCFG, + "Specify an attribute exchange url and alias."), { NULL } }; @@ -399,8 +488,11 @@ session_cookie_value (request_rec *r, const char *name) if (cookies == NULL) return NULL; + while (cookies[0] == ',' || cookies[0] == ';') + ++cookies; + while (*cookies) { - pair = ap_get_token (r->pool, &cookies, 1); + pair = safe_get_token (r->pool, &cookies, 1); if (!pair) break; if (pair[0] == '$') @@ -463,16 +555,16 @@ session_load_info (sid_context_t *ctx, request_rec *r) if (!value) return NULL; - sig = ap_get_token (r->pool, &value, 0); + sig = safe_get_token (r->pool, &value, 0); if (!session_validate_sig (r->pool, sig, value)) return NULL; /* The version of the session info, only 1 supported for now */ - token = ap_get_token (r->pool, &value, 0); + token = safe_get_token (r->pool, &value, 0); if (strcmp (token, "1") != 0) return NULL; - token = ap_get_token (r->pool, &value, 0); + token = safe_get_token (r->pool, &value, 0); expiry = strtol (token, &end, 10); if (*end != '\0') return NULL; @@ -482,7 +574,7 @@ session_load_info (sid_context_t *ctx, request_rec *r) return NULL; /* The identifier */ - identifier = ap_get_token (r->pool, &value, 0); + identifier = safe_get_token (r->pool, &value, 0); len = strlen (identifier); if (identifier[0] == '"' && identifier[len - 1] == '"') { identifier[len - 1] = 0; @@ -652,6 +744,31 @@ sid_request_authenticated (sid_request_t *req, const char *identifier) session_send_info (ctx, req->rec, sess); } +void +sid_request_attribute_values (sid_request_t *req, sid_attribute_t *attr, const char **values) +{ + const char **val; + char buf[64]; + char *name; + int i = 0; + + /* Setup all the values */ + for (i = 0, val = values; *val; ++val, ++i) { + snprintf (buf, sizeof (buf), "AX_VALUE_%s_%d", attr->alias, i); + name = apr_pstrdup (req->rec->pool, buf); + strupcase (name); + apr_table_setn (req->rec->subprocess_env, name, + apr_pstrdup (req->rec->pool, *val)); + } + + /* Put in the count */ + snprintf (buf, sizeof (buf), "AX_COUNT_%s", attr->alias); + name = apr_pstrdup (req->rec->pool, buf); + strupcase (name); + snprintf (buf, sizeof (buf), "%d", i); + apr_table_set (req->rec->subprocess_env, name, apr_pstrdup (req->rec->pool, buf)); +} + /* --------------------------------------------------------------------------------------- * MAIN HOOKS */ @@ -720,7 +837,8 @@ hook_authenticate (request_rec* r) req.rec = r; /* Do the OpenID magic */ - sid_consumer_authenticate (&req, ctx->store, ctx->trust_root, ctx->identifier); + sid_consumer_authenticate (&req, ctx->store, ctx->trust_root, + ctx->identifier, ctx->attributes); return req.result; } -- cgit v1.2.3