Update to mod_auth_mellon 0.4.0 plus upstream patch:
* Honour MellonProbeDiscoveryIdP order when sending probes * Allow MellonUser variable to be translated through MellonSetEnv * A /mellon/probeDisco endpoint replaces the builtin:get-metadata IdP dicovery URL scheme * New MellonCond directive to enable attribute filtering beyond MellonRequire functionalities. * New MellonIdPMetadataGlob directive to load mulitple IdP metadata using a glob(3) pattern. * Support for running behind reverse proxy. * MellonCookieDomain and MellonCookiePath options to configure cookie settings. * Support for loading federation metadata files. * Several bugfixes.
This commit is contained in:
parent
45f789517c
commit
b8c0859d81
9 changed files with 324 additions and 1359 deletions
|
@ -1,4 +1,4 @@
|
|||
$NetBSD: CHANGES-2011,v 1.3174 2011/12/06 07:07:45 hiramatsu Exp $
|
||||
$NetBSD: CHANGES-2011,v 1.3175 2011/12/06 09:58:00 manu Exp $
|
||||
|
||||
Changes to the packages collection and infrastructure in 2011:
|
||||
|
||||
|
@ -5007,3 +5007,4 @@ Changes to the packages collection and infrastructure in 2011:
|
|||
Updated comms/kermit to 9.0.302nb1 [sbd 2011-12-06]
|
||||
Updated www/p5-Dancer to 1.3080 [hiramatsu 2011-12-06]
|
||||
Updated devel/p5-Date-Manip to 6.25 [hiramatsu 2011-12-06]
|
||||
Updated www/ap2-auth-mellon to 0.4.0nb1 [manu 2011-12-06]
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
# $NetBSD: Makefile,v 1.17 2011/05/07 05:15:21 manu Exp $
|
||||
# $NetBSD: Makefile,v 1.18 2011/12/06 09:58:01 manu Exp $
|
||||
#
|
||||
|
||||
PKGNAME= ${APACHE_PKG_PREFIX}-${DISTNAME:S/mod_//:S/_/-/}
|
||||
DISTNAME= mod_auth_mellon-0.3.0
|
||||
PKGREVISION= 3
|
||||
DISTNAME= mod_auth_mellon-0.4.0
|
||||
PKGREVISION= 1
|
||||
CATEGORIES= www security
|
||||
MASTER_SITES= http://modmellon.googlecode.com/files/
|
||||
|
||||
|
@ -17,6 +17,7 @@ PKG_DESTDIR_SUPPORT= user-destdir
|
|||
GNU_CONFIGURE= YES
|
||||
USE_LIBTOOL= YES
|
||||
USE_TOOLS+= pkg-config
|
||||
CFLAGS+= -DLASSO_SERVER_LOAD_METADATA_FLAG_DEFAULT=0
|
||||
|
||||
APACHE_MODULE= YES
|
||||
APACHE_MODULE_NAME= auth_mellon_module
|
||||
|
@ -25,10 +26,10 @@ PKG_APACHE_ACCEPTED= apache22
|
|||
BUILDLINK_API_DEPENDS.apache+= apache>=2.0.47
|
||||
|
||||
SUBST_CLASSES+= pthflags
|
||||
SUBST_MESSAGES= Convert -pthread flag to apxs style
|
||||
SUBST_MESSAGES= Remove -pthread flag
|
||||
SUBST_STAGE.pthflags= post-configure
|
||||
SUBST_FILES.pthflags= Makefile
|
||||
SUBST_SED.pthflags= -e 's| -pthread | ${"${PTHREAD_CFLAGS:M-pthread}":?-Wc,-pthread:} ${"${PTHREAD_LDFLAGS:M-pthread}":?-Wl,-pthread:} |g'
|
||||
SUBST_SED.pthflags= -e 's| -pthread | |g'
|
||||
|
||||
INSTALLATION_DIRS+= lib/httpd
|
||||
|
||||
|
@ -39,6 +40,7 @@ do-install:
|
|||
-n auth_mellon mod_auth_mellon.la
|
||||
|
||||
.include "../../security/lasso/buildlink3.mk"
|
||||
.include "../../mk/pthread.buildlink3.mk"
|
||||
.include "../../www/curl/buildlink3.mk"
|
||||
|
||||
.include "../../mk/bsd.pkg.mk"
|
||||
|
|
|
@ -1,11 +1,6 @@
|
|||
$NetBSD: distinfo,v 1.10 2011/05/07 05:15:21 manu Exp $
|
||||
$NetBSD: distinfo,v 1.11 2011/12/06 09:58:01 manu Exp $
|
||||
|
||||
SHA1 (mod_auth_mellon-0.3.0.tar.gz) = 658dda51652f491552f2ecc84572ed7750f914ff
|
||||
RMD160 (mod_auth_mellon-0.3.0.tar.gz) = 69237b1ec266018a86e7134a4662b491af3c261e
|
||||
Size (mod_auth_mellon-0.3.0.tar.gz) = 92252 bytes
|
||||
SHA1 (patch-ac) = 7976528d9c77b8e30accf60edc958db53ac5e8fb
|
||||
SHA1 (patch-ad) = a1bebae20bfbb99bd71d68de19901eaef6c52dbd
|
||||
SHA1 (patch-ae) = d51040b6d827940a2c3cf8928dee175efa946e37
|
||||
SHA1 (patch-af) = 0803665a14df8582ac20d950a070f73d794b08ea
|
||||
SHA1 (patch-ag) = c1ef8704268d99b01d1e96fc2da9be74a7726b9d
|
||||
SHA1 (patch-ah) = 6287c038aee79e66539dda12ff447dfd5d9529bf
|
||||
SHA1 (mod_auth_mellon-0.4.0.tar.gz) = d09f7bbefe32c2eaa624612584eab1ea8e89820a
|
||||
RMD160 (mod_auth_mellon-0.4.0.tar.gz) = 92ef003ae22c43ef81d22f5027486244e76e3d3f
|
||||
Size (mod_auth_mellon-0.4.0.tar.gz) = 103708 bytes
|
||||
SHA1 (patch-ai) = a7a4f729301bff79cb39d441f9fa48993cdc2899
|
||||
|
|
|
@ -1,515 +0,0 @@
|
|||
$NetBSD: patch-ac,v 1.1 2011/04/04 08:46:42 manu Exp $
|
||||
|
||||
Add MellonCond directive (pulled up from upstream)
|
||||
|
||||
Index: auth_mellon_util.c
|
||||
===================================================================
|
||||
--- auth_mellon_util.c (revision 113)
|
||||
+++ auth_mellon_util.c (working copy)
|
||||
@@ -51,7 +51,7 @@
|
||||
|
||||
|
||||
/* This function checks if the user has access according
|
||||
- * to the MellonRequire directives.
|
||||
+ * to the MellonRequire and MellonCond directives.
|
||||
*
|
||||
* Parameters:
|
||||
* request_rec *r The current request.
|
||||
@@ -63,51 +63,105 @@
|
||||
int am_check_permissions(request_rec *r, am_cache_entry_t *session)
|
||||
{
|
||||
am_dir_cfg_rec *dir_cfg;
|
||||
- apr_hash_index_t *idx;
|
||||
- const char *key;
|
||||
- apr_array_header_t *rlist;
|
||||
int i, j;
|
||||
- int rlist_ok;
|
||||
- const char **re;
|
||||
+ int skip_or = 0;
|
||||
|
||||
dir_cfg = am_get_dir_cfg(r);
|
||||
|
||||
- /* Iterate over all require-directives. */
|
||||
- for(idx = apr_hash_first(r->pool, dir_cfg->require);
|
||||
- idx != NULL;
|
||||
- idx = apr_hash_next(idx)) {
|
||||
+ /* Iterate over all cond-directives */
|
||||
+ for (i = 0; i < dir_cfg->cond->nelts; i++) {
|
||||
+ am_cond_t *ce;
|
||||
+ const char *value = NULL;
|
||||
+ int match = 0;
|
||||
|
||||
- /* Get current require directive. key will be the name
|
||||
- * of the attribute, and rlist is a list of all allowed values.
|
||||
+ ce = &((am_cond_t *)(dir_cfg->cond->elts))[i];
|
||||
+
|
||||
+ /*
|
||||
+ * Rule with ignore flog?
|
||||
*/
|
||||
- apr_hash_this(idx, (const void **)&key, NULL, (void **)&rlist);
|
||||
+ if (ce->flags & AM_COND_FLAG_IGN)
|
||||
+ continue;
|
||||
|
||||
- /* Reset status to 0 before search. */
|
||||
- rlist_ok = 0;
|
||||
+ /*
|
||||
+ * We matched a [OR] rule, skip the next rules
|
||||
+ * until we have one without [OR].
|
||||
+ */
|
||||
+ if (skip_or) {
|
||||
+ if (!(ce->flags & AM_COND_FLAG_OR))
|
||||
+ skip_or = 0;
|
||||
|
||||
- re = (const char **)rlist->elts;
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
|
||||
+ "Skip %s, [OR] rule matched previously",
|
||||
+ ce->directive);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * look for a match on each value for this attribute,
|
||||
+ * stop on first match.
|
||||
+ */
|
||||
+ for (j = 0; (j < session->size) && !match; j++) {
|
||||
+ const char *varname = NULL;
|
||||
|
||||
- /* rlist is an array of all the valid values for this attribute. */
|
||||
- for(i = 0; i < rlist->nelts && !rlist_ok; i++) {
|
||||
+ /*
|
||||
+ * if MAP flag is set, check for remapped
|
||||
+ * attribute name with mellonSetEnv
|
||||
+ */
|
||||
+ if (ce->flags & AM_COND_FLAG_MAP)
|
||||
+ varname = apr_hash_get(dir_cfg->envattr,
|
||||
+ session->env[j].varname,
|
||||
+ APR_HASH_KEY_STRING);
|
||||
|
||||
- /* Search for a matching attribute in the session data. */
|
||||
- for(j = 0; j < session->size && !rlist_ok; j++) {
|
||||
- if(strcmp(session->env[j].varname, key) == 0 &&
|
||||
- strcmp(session->env[j].value, re[i]) == 0) {
|
||||
- /* We found a attribute with the correct name
|
||||
- * and value.
|
||||
- */
|
||||
- rlist_ok = 1;
|
||||
- }
|
||||
+ /*
|
||||
+ * Otherwise or if not found, use the attribute name
|
||||
+ * sent by the IdP.
|
||||
+ */
|
||||
+ if (varname == NULL)
|
||||
+ varname = session->env[j].varname;
|
||||
+
|
||||
+ if (strcmp(varname, ce->varname) != 0)
|
||||
+ continue;
|
||||
+
|
||||
+ value = session->env[j].value;
|
||||
+
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
|
||||
+ "Evaluate %s vs \"%s\"",
|
||||
+ ce->directive, value);
|
||||
+
|
||||
+ if (value == NULL) {
|
||||
+ match = 0; /* can not happen */
|
||||
+ } else if (ce->flags & AM_COND_FLAG_REG) {
|
||||
+ match = !ap_regexec(ce->regex, value, 0, NULL, 0);
|
||||
+ } else if (ce->flags & AM_COND_FLAG_NC) {
|
||||
+ match = !strcasecmp(ce->str, value);
|
||||
+ } else {
|
||||
+ match = !strcmp(ce->str, value);
|
||||
}
|
||||
}
|
||||
|
||||
- if(!rlist_ok) {
|
||||
- ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
|
||||
- "Client failed to match required attribute \"%s\".",
|
||||
- key);
|
||||
+ if (ce->flags & AM_COND_FLAG_NOT)
|
||||
+ match = !match;
|
||||
+
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
|
||||
+ "%s: %smatch", ce->directive,
|
||||
+ (match == 0) ? "no ": "");
|
||||
+
|
||||
+ /*
|
||||
+ * If no match, we stop here, except if it is an [OR] condition
|
||||
+ */
|
||||
+ if (!match & !(ce->flags & AM_COND_FLAG_OR)) {
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r,
|
||||
+ "Client failed to match %s",
|
||||
+ ce->directive);
|
||||
return HTTP_FORBIDDEN;
|
||||
}
|
||||
+
|
||||
+ /*
|
||||
+ * Match on [OR] condition means we skip until a rule
|
||||
+ * without [OR],
|
||||
+ */
|
||||
+ if (match && (ce->flags & AM_COND_FLAG_OR))
|
||||
+ skip_or = 1;
|
||||
}
|
||||
|
||||
return OK;
|
||||
Index: README
|
||||
===================================================================
|
||||
--- README (revision 113)
|
||||
+++ README (working copy)
|
||||
@@ -152,9 +152,9 @@
|
||||
# "auth": We will populate the environment with information about
|
||||
# the user if he is authorized. If he is authenticated
|
||||
# (logged in), but not authorized (according to the
|
||||
- # MellonRequire directives, then we will return a 403
|
||||
- # Forbidden error. If he isn't authenticated then we will
|
||||
- # redirect him to the login page of the IdP.
|
||||
+ # MellonRequire and MellonCond directives, then we will
|
||||
+ # return a 403 Forbidden error. If he isn't authenticated
|
||||
+ # then we will redirect him to the login page of the IdP.
|
||||
#
|
||||
# Default: MellonEnable "off"
|
||||
MellonEnable "auth"
|
||||
@@ -221,14 +221,45 @@
|
||||
# Note that the attribute name is the name we received from the
|
||||
# IdP.
|
||||
#
|
||||
- # If you don't list any MellonRequire directives, then any user
|
||||
- # authenticated by the IdP will have access to this service. If
|
||||
- # you list several MellonRequire directives, then all of them
|
||||
- # will have to match.
|
||||
+ # If you don't list any MellonRequire directives (and any
|
||||
+ # MellonCond directives, see below), then any user authenticated
|
||||
+ # by the IdP will have access to this service. If you list several
|
||||
+ # MellonRequire directives, then all of them will have to match.
|
||||
+ # If you use multiple MellonRequire directive on the same
|
||||
+ # attribute, the last overrides the previous ones.
|
||||
#
|
||||
# Default: None set.
|
||||
MellonRequire "eduPersonAffiliation" "student" "employee"
|
||||
|
||||
+ # MellonCond provides the same function as MellonRequire, with
|
||||
+ # extra functionnality (MellonRequire is retained for backward
|
||||
+ # compatibility). The syntax is
|
||||
+ # 'MellonCond <attribute name> <value> [<options>]'
|
||||
+ #
|
||||
+ # <options> is an optional, comma-separated list of option
|
||||
+ # encloseed with brackets. Here is an example: [NOT,NC]
|
||||
+ # The valid options are:
|
||||
+ # OR If this MellonCond evaluted to false, then the
|
||||
+ # next one will be checked. If it evalutes to true,
|
||||
+ # then the overall check succeeds.
|
||||
+ # NOT This MellonCond evaluates to true if the attribute
|
||||
+ # does not match the value.
|
||||
+ # REG Value to check is a regular expression.
|
||||
+ # NC Perform case insensitive match.
|
||||
+ # MAP Attempt to search an attribute with name remapped by
|
||||
+ # MellonSetEnv. Fallback to non remapped name if not
|
||||
+ # found.
|
||||
+ #
|
||||
+ # It is allowed to have multiple MellonCond on the same
|
||||
+ # attribute, and to mix MellonCond and MellonRequire.
|
||||
+ # Note that this can create tricky situations, since the OR
|
||||
+ # option has effect on a following MellonRequire directive.
|
||||
+ #
|
||||
+ # Default: none set
|
||||
+ # MellonCond "mail" "@example\.net$" [OR,REG]
|
||||
+ # MellonCond "mail" "@example\.com$" [OR,REG]
|
||||
+ # MellonCond "uid" "superuser"
|
||||
+
|
||||
# MellonEndpointPath selects which directory mod_auth_mellon
|
||||
# should assume contains the SAML 2.0 endpoints. Any request to
|
||||
# this directory will be handled by mod_auth_mellon.
|
||||
Index: auth_mellon.h
|
||||
===================================================================
|
||||
--- auth_mellon.h (revision 113)
|
||||
+++ auth_mellon.h (working copy)
|
||||
@@ -124,6 +124,30 @@
|
||||
am_decoder_feide,
|
||||
} am_decoder_t;
|
||||
|
||||
+typedef enum {
|
||||
+ AM_COND_FLAG_NULL = 0x00, /* No flags */
|
||||
+ AM_COND_FLAG_OR = 0x01, /* Or with next condition */
|
||||
+ AM_COND_FLAG_NOT = 0x02, /* Negate this condition */
|
||||
+ AM_COND_FLAG_REG = 0x04, /* Condition is regex */
|
||||
+ AM_COND_FLAG_NC = 0x08, /* Case insensitive match */
|
||||
+ AM_COND_FLAG_MAP = 0x10, /* Try to use attribute name from MellonSetEnv */
|
||||
+ AM_COND_FLAG_IGN = 0x20, /* Condition is to be ignored */
|
||||
+ AM_COND_FLAG_REQ = 0x40, /* Condition was configure using MellonRequire */
|
||||
+} am_cond_flag_t;
|
||||
+
|
||||
+/* Not counting AM_COND_FLAG_NULL */
|
||||
+#define AM_COND_FLAG_COUNT 7
|
||||
+
|
||||
+extern const char *am_cond_options[];
|
||||
+
|
||||
+typedef struct {
|
||||
+ const char *varname;
|
||||
+ int flags;
|
||||
+ const char *str;
|
||||
+ ap_regex_t *regex;
|
||||
+ const char *directive;
|
||||
+} am_cond_t;
|
||||
+
|
||||
typedef struct am_dir_cfg_rec {
|
||||
/* enable_mellon is used to enable auth_mellon for a location.
|
||||
*/
|
||||
@@ -136,7 +160,7 @@
|
||||
|
||||
const char *varname;
|
||||
int secure;
|
||||
- apr_hash_t *require;
|
||||
+ apr_array_header_t *cond;
|
||||
apr_hash_t *envattr;
|
||||
const char *userattr;
|
||||
const char *idpattr;
|
||||
Index: auth_mellon_config.c
|
||||
===================================================================
|
||||
--- auth_mellon_config.c (revision 113)
|
||||
+++ auth_mellon_config.c (working copy)
|
||||
@@ -422,7 +422,136 @@
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+/* This function decodes MellonCond flags, such as [NOT,REG]
|
||||
+ *
|
||||
+ * Parameters:
|
||||
+ * const char *arg Pointer to the flags string
|
||||
+ *
|
||||
+ * Returns:
|
||||
+ * flags, or -1 on error
|
||||
+ */
|
||||
+const char *am_cond_options[] = {
|
||||
+ "OR", /* AM_EXPIRE_FLAG_OR */
|
||||
+ "NOT", /* AM_EXPIRE_FLAG_NOT */
|
||||
+ "REG", /* AM_EXPIRE_FLAG_REG */
|
||||
+ "NC", /* AM_EXPIRE_FLAG_NC */
|
||||
+ "MAP", /* AM_EXPIRE_FLAG_MAP */
|
||||
+ "IGN", /* AM_EXPIRE_FLAG_IGN */
|
||||
+ "REQ", /* AM_EXPIRE_FLAG_REQ */
|
||||
+};
|
||||
|
||||
+static int am_cond_flags(const char *arg)
|
||||
+{
|
||||
+ int flags = AM_COND_FLAG_NULL;
|
||||
+
|
||||
+ /* Skip inital [ */
|
||||
+ if (arg[0] == '[')
|
||||
+ arg++;
|
||||
+ else
|
||||
+ return -1;
|
||||
+
|
||||
+ do {
|
||||
+ apr_size_t i;
|
||||
+
|
||||
+ for (i = 0; i < AM_COND_FLAG_COUNT; i++) {
|
||||
+ apr_size_t optlen = strlen(am_cond_options[i]);
|
||||
+
|
||||
+ if (strncmp(arg, am_cond_options[i], optlen) == 0) {
|
||||
+ /* Make sure we have a separator next */
|
||||
+ if (arg[optlen] && !strchr("]\t ,", (int)arg[optlen]))
|
||||
+ return -1;
|
||||
+
|
||||
+ flags |= (1 << i);
|
||||
+ arg += optlen;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ /* no match */
|
||||
+ if (i == AM_COND_FLAG_COUNT)
|
||||
+ return -1;
|
||||
+
|
||||
+ /* skip spaces, tabs and commas */
|
||||
+ arg += strspn(arg, " \t,");
|
||||
+
|
||||
+ /* Garbage after ] is ignored */
|
||||
+ if (*arg == ']')
|
||||
+ return flags;
|
||||
+ }
|
||||
+ } while (*arg);
|
||||
+
|
||||
+ /* Missing trailing ] */
|
||||
+ return -1;
|
||||
+}
|
||||
+
|
||||
+/* This function handles the MellonCond configuration directive, which
|
||||
+ * allows the user to restrict access based on attributes received from
|
||||
+ * the IdP.
|
||||
+ *
|
||||
+ * Parameters:
|
||||
+ * cmd_parms *cmd The command structure for the MellonCond
|
||||
+ * configuration directive.
|
||||
+ * void *struct_ptr Pointer to the current directory configuration.
|
||||
+ * const char *attribute Pointer to the attribute name
|
||||
+ * const char *value Pointer to the attribute value or regex
|
||||
+ * const char *options Pointer to options
|
||||
+ *
|
||||
+ * Returns:
|
||||
+ * NULL on success or an error string on failure.
|
||||
+ */
|
||||
+static const char *am_set_cond_slot(cmd_parms *cmd,
|
||||
+ void *struct_ptr,
|
||||
+ const char *attribute,
|
||||
+ const char *value,
|
||||
+ const char *options)
|
||||
+{
|
||||
+ am_dir_cfg_rec *d = struct_ptr;
|
||||
+ am_cond_t *element;
|
||||
+
|
||||
+ if (*attribute == '\0' || *value == '\0')
|
||||
+ return apr_pstrcat(cmd->pool, cmd->cmd->name,
|
||||
+ " takes two or three arguments", NULL);
|
||||
+
|
||||
+ element = (am_cond_t *)apr_array_push(d->cond);
|
||||
+ element->varname = attribute;
|
||||
+ element->flags = AM_COND_FLAG_NULL;
|
||||
+ element->str = NULL;
|
||||
+ element->regex = NULL;
|
||||
+ element->directive = apr_pstrcat(cmd->pool, cmd->directive->directive,
|
||||
+ " ", cmd->directive->args, NULL);
|
||||
+
|
||||
+ /* Handle optional flags */
|
||||
+ if (*options != '\0') {
|
||||
+ int flags;
|
||||
+
|
||||
+ flags = am_cond_flags(options);
|
||||
+ if (flags == -1)
|
||||
+ return apr_psprintf(cmd->pool, "%s - invalid flags %s",
|
||||
+ cmd->cmd->name, options);
|
||||
+
|
||||
+ element->flags = flags;
|
||||
+ }
|
||||
+
|
||||
+ if (element->flags & AM_COND_FLAG_REG) {
|
||||
+ int regex_flags = AP_REG_EXTENDED|AP_REG_NOSUB;
|
||||
+
|
||||
+ if (element->flags & AM_COND_FLAG_NC)
|
||||
+ regex_flags |= AP_REG_ICASE;
|
||||
+
|
||||
+ element->regex = ap_pregcomp(cmd->pool, value, regex_flags);
|
||||
+ if (element->regex == NULL)
|
||||
+ return apr_psprintf(cmd->pool, "%s - invalid regex %s",
|
||||
+ cmd->cmd->name, value);
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * We keep the string also for regex, so that we can
|
||||
+ * print it for debug purpose.
|
||||
+ */
|
||||
+ element->str = value;
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
/* This function handles the MellonRequire configuration directive, which
|
||||
* allows the user to restrict access based on attributes received from
|
||||
* the IdP.
|
||||
@@ -440,10 +569,11 @@
|
||||
void *struct_ptr,
|
||||
const char *arg)
|
||||
{
|
||||
- apr_array_header_t *r;
|
||||
am_dir_cfg_rec *d = struct_ptr;
|
||||
char *attribute, *value;
|
||||
- const char **element;
|
||||
+ int i;
|
||||
+ am_cond_t *element;
|
||||
+ am_cond_t *first_element;
|
||||
|
||||
attribute = ap_getword_conf(cmd->pool, &arg);
|
||||
value = ap_getword_conf(cmd->pool, &arg);
|
||||
@@ -453,20 +583,47 @@
|
||||
" takes at least two arguments", NULL);
|
||||
}
|
||||
|
||||
+ /*
|
||||
+ * MellonRequire overwrites previous conditions on this attribute
|
||||
+ * We just tag the am_cond_t with the ignore flag, as it is
|
||||
+ * easier (and probably faster) than to really remove it.
|
||||
+ */
|
||||
+ for (i = 0; i < d->cond->nelts; i++) {
|
||||
+ am_cond_t *ce = &((am_cond_t *)(d->cond->elts))[i];
|
||||
+
|
||||
+ if ((strcmp(ce->varname, attribute) == 0) &&
|
||||
+ (ce->flags & AM_COND_FLAG_REQ))
|
||||
+ ce->flags |= AM_COND_FLAG_IGN;
|
||||
+ }
|
||||
+
|
||||
+ first_element = NULL;
|
||||
do {
|
||||
- r = (apr_array_header_t *)apr_hash_get(d->require, attribute,
|
||||
- APR_HASH_KEY_STRING);
|
||||
+ element = (am_cond_t *)apr_array_push(d->cond);
|
||||
+ element->varname = attribute;
|
||||
+ element->flags = AM_COND_FLAG_OR|AM_COND_FLAG_REQ;
|
||||
+ element->str = value;
|
||||
+ element->regex = NULL;
|
||||
|
||||
- if (r == NULL) {
|
||||
- r = apr_array_make(cmd->pool, 2, sizeof(const char *));
|
||||
- apr_hash_set(d->require, attribute, APR_HASH_KEY_STRING, r);
|
||||
+ /*
|
||||
+ * When multiple values are given, we track the first one
|
||||
+ * in order to retreive the directive
|
||||
+ */
|
||||
+ if (first_element == NULL) {
|
||||
+ element->directive = apr_pstrcat(cmd->pool,
|
||||
+ cmd->directive->directive, " ",
|
||||
+ cmd->directive->args, NULL);
|
||||
+ first_element = element;
|
||||
+ } else {
|
||||
+ element->directive = first_element->directive;
|
||||
}
|
||||
|
||||
- element = (const char **)apr_array_push(r);
|
||||
- *element = value;
|
||||
-
|
||||
} while (*(value = ap_getword_conf(cmd->pool, &arg)) != '\0');
|
||||
|
||||
+ /*
|
||||
+ * Remove OR flag on last element
|
||||
+ */
|
||||
+ element->flags &= ~AM_COND_FLAG_OR;
|
||||
+
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -650,6 +807,15 @@
|
||||
" for the attribute. The syntax is:"
|
||||
" MellonRequire <attribute> <value1> [value2....]."
|
||||
),
|
||||
+ AP_INIT_TAKE23(
|
||||
+ "MellonCond",
|
||||
+ am_set_cond_slot,
|
||||
+ NULL,
|
||||
+ OR_AUTHCFG,
|
||||
+ "Attribute requirements for authorization. Allows you to restrict"
|
||||
+ " access based on attributes received from the IdP. The syntax is:"
|
||||
+ " MellonRequire <attribute> <value> [<options>]."
|
||||
+ ),
|
||||
AP_INIT_TAKE1(
|
||||
"MellonSessionLength",
|
||||
ap_set_int_slot,
|
||||
@@ -795,7 +961,7 @@
|
||||
|
||||
dir->varname = default_cookie_name;
|
||||
dir->secure = default_secure_cookie;
|
||||
- dir->require = apr_hash_make(p);
|
||||
+ dir->cond = apr_array_make(p, 0, sizeof(am_cond_t));
|
||||
dir->envattr = apr_hash_make(p);
|
||||
dir->userattr = default_user_attribute;
|
||||
dir->idpattr = NULL;
|
||||
@@ -871,10 +1037,10 @@
|
||||
base_cfg->secure);
|
||||
|
||||
|
||||
- new_cfg->require = apr_hash_copy(p,
|
||||
- (apr_hash_count(add_cfg->require) > 0) ?
|
||||
- add_cfg->require :
|
||||
- base_cfg->require);
|
||||
+ new_cfg->cond = apr_array_copy(p,
|
||||
+ (!apr_is_empty_array(add_cfg->cond)) ?
|
||||
+ add_cfg->cond :
|
||||
+ base_cfg->cond);
|
||||
|
||||
new_cfg->envattr = apr_hash_copy(p,
|
||||
(apr_hash_count(add_cfg->envattr) > 0) ?
|
|
@ -1,523 +0,0 @@
|
|||
$NetBSD: patch-ae,v 1.1 2011/04/04 08:46:42 manu Exp $
|
||||
|
||||
Replace buildtin: diescovery URL by the discoProbe endpoint (pulled from
|
||||
upstream)
|
||||
|
||||
Index: auth_mellon_handler.c
|
||||
===================================================================
|
||||
--- auth_mellon_handler.c (revision 112)
|
||||
+++ auth_mellon_handler.c (working copy)
|
||||
@@ -226,34 +226,7 @@
|
||||
return provider_id;
|
||||
}
|
||||
|
||||
-/* This returns built-in IdP discovery timeout
|
||||
- *
|
||||
- * Parameters:
|
||||
- * request_rec *r The request we received.
|
||||
- *
|
||||
- * Returns:
|
||||
- * the timeout, -1 if not enabled.
|
||||
- */
|
||||
-static long am_builtin_discovery_timeout(request_rec *r)
|
||||
-{
|
||||
- am_dir_cfg_rec *cfg = am_get_dir_cfg(r);
|
||||
- const char *builtin = "builtin:get-metadata";
|
||||
- const char *timeout = "?timeout=";
|
||||
- const char *cp;
|
||||
- const long default_timeout = 1L;
|
||||
|
||||
- if ((cfg->discovery_url == NULL) ||
|
||||
- (strncmp(cfg->discovery_url, builtin, strlen(builtin)) != 0))
|
||||
- return -1;
|
||||
-
|
||||
- cp = cfg->discovery_url + strlen(builtin);
|
||||
- if (strncmp(cp, timeout, strlen(timeout)) != 0)
|
||||
- return default_timeout;
|
||||
-
|
||||
- cp += strlen(timeout);
|
||||
- return atoi(cp);
|
||||
-}
|
||||
-
|
||||
/* This function selects an IdP and returns its provider_id
|
||||
*
|
||||
* Parameters:
|
||||
@@ -267,8 +240,6 @@
|
||||
am_dir_cfg_rec *cfg = am_get_dir_cfg(r);
|
||||
const char *idp_provider_id;
|
||||
const char *idp_metadata_file;
|
||||
- apr_hash_index_t *index;
|
||||
- long timeout;
|
||||
|
||||
/*
|
||||
* If we have a single IdP, return that one.
|
||||
@@ -308,47 +279,6 @@
|
||||
return idp_provider_id;
|
||||
}
|
||||
|
||||
- /*
|
||||
- * If built-in IdP discovery is not configured, return default.
|
||||
- */
|
||||
- timeout = am_builtin_discovery_timeout(r);
|
||||
- if (timeout == -1)
|
||||
- return am_first_idp(r);
|
||||
-
|
||||
- /*
|
||||
- * Otherwise, proceed with built-in IdP discovery:
|
||||
- * send probes for all configures IdP to check availability.
|
||||
- * The first to answer is chosen. On error, use default.
|
||||
- */
|
||||
- for (index = apr_hash_first(r->pool, cfg->idp_metadata_files);
|
||||
- index;
|
||||
- index = apr_hash_next(index)) {
|
||||
- void *buffer;
|
||||
- apr_size_t len;
|
||||
- apr_ssize_t slen;
|
||||
- long status;
|
||||
-
|
||||
- apr_hash_this(index,
|
||||
- (const void **)&idp_provider_id,
|
||||
- &slen,
|
||||
- (void *)&idp_metadata_file);
|
||||
-
|
||||
- status = 0;
|
||||
- if (am_httpclient_get(r, idp_provider_id, &buffer, &len,
|
||||
- timeout, &status) != OK)
|
||||
- continue;
|
||||
-
|
||||
- if (status != HTTP_OK) {
|
||||
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||
- "Cannot probe %s: IdP returned HTTP %ld",
|
||||
- idp_provider_id, status);
|
||||
- continue;
|
||||
- }
|
||||
-
|
||||
- /* We got some succes */
|
||||
- return idp_provider_id;
|
||||
- }
|
||||
-
|
||||
/*
|
||||
* No IdP answered, use default
|
||||
* Perhaps we should redirect to an error page instead.
|
||||
@@ -2506,7 +2436,6 @@
|
||||
|
||||
/* Check if IdP discovery is in use and no IdP was selected yet */
|
||||
if ((cfg->discovery_url != NULL) &&
|
||||
- (am_builtin_discovery_timeout(r) == -1) && /* no built-in discovery */
|
||||
(am_extract_query_parameter(r->pool, r->args, "IdP") == NULL)) {
|
||||
char *discovery_url;
|
||||
char *return_url;
|
||||
@@ -2536,8 +2465,7 @@
|
||||
/* If IdP discovery is in use and we have an IdP selected,
|
||||
* set the relay_state
|
||||
*/
|
||||
- if ((cfg->discovery_url != NULL) &&
|
||||
- (am_builtin_discovery_timeout(r) == -1)) { /* no built-in discovery */
|
||||
+ if (cfg->discovery_url != NULL) {
|
||||
char *return_url;
|
||||
|
||||
return_url = am_extract_query_parameter(r->pool, r->args, "ReturnTo");
|
||||
@@ -2615,7 +2543,151 @@
|
||||
return am_send_authn_request(r, idp, return_to, is_passive);
|
||||
}
|
||||
|
||||
+/* This function handles requests to the probe discovery handler
|
||||
+ *
|
||||
+ * Parameters:
|
||||
+ * request_rec *r The request.
|
||||
+ *
|
||||
+ * Returns:
|
||||
+ * OK on success, or an error if any of the steps fail.
|
||||
+ */
|
||||
+static int am_handle_probe_discovery(request_rec *r) {
|
||||
+ am_dir_cfg_rec *cfg = am_get_dir_cfg(r);
|
||||
+ const char *idp = NULL;
|
||||
+ int timeout;
|
||||
+ apr_hash_index_t *index;
|
||||
+ char *return_to;
|
||||
+ char *idp_param;
|
||||
+ char *redirect_url;
|
||||
+ int ret;
|
||||
|
||||
+ /*
|
||||
+ * If built-in IdP discovery is not configured, return error.
|
||||
+ * For now we only have the get-metadata metadata method, so this
|
||||
+ * information is not saved in configuration nor it is checked here.
|
||||
+ */
|
||||
+ timeout = cfg->probe_discovery_timeout;
|
||||
+ if (timeout == -1) {
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||
+ "probe discovery handler invoked but not "
|
||||
+ "configured. Plase set MellonProbeDiscoveryTimeout.");
|
||||
+ return HTTP_INTERNAL_SERVER_ERROR;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * Check for mandatory arguments early to avoid sending
|
||||
+ * probles for nothing.
|
||||
+ */
|
||||
+ return_to = am_extract_query_parameter(r->pool, r->args, "return");
|
||||
+ if(return_to == NULL) {
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||
+ "Missing required return parameter.");
|
||||
+ return HTTP_BAD_REQUEST;
|
||||
+ }
|
||||
+
|
||||
+ ret = am_urldecode(return_to);
|
||||
+ if (ret != OK) {
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, ret, r,
|
||||
+ "Could not urldecode return value.");
|
||||
+ return HTTP_BAD_REQUEST;
|
||||
+ }
|
||||
+
|
||||
+ idp_param = am_extract_query_parameter(r->pool, r->args, "returnIDParam");
|
||||
+ if(idp_param == NULL) {
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||
+ "Missing required returnIDParam parameter.");
|
||||
+ return HTTP_BAD_REQUEST;
|
||||
+ }
|
||||
+
|
||||
+ ret = am_urldecode(idp_param);
|
||||
+ if (ret != OK) {
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, ret, r,
|
||||
+ "Could not urldecode returnIDParam value.");
|
||||
+ return HTTP_BAD_REQUEST;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * Proceed with built-in IdP discovery.
|
||||
+ *
|
||||
+ * Send probes for all configured IdP to check availability.
|
||||
+ * The first to answer is chosen, but the list of usable
|
||||
+ * IdP can be restricted in configuration.
|
||||
+ */
|
||||
+ for (index = apr_hash_first(r->pool, cfg->idp_metadata_files);
|
||||
+ index;
|
||||
+ index = apr_hash_next(index)) {
|
||||
+ void *dontcare;
|
||||
+ const char *ping_url;
|
||||
+ apr_size_t len;
|
||||
+ apr_ssize_t slen;
|
||||
+ long status;
|
||||
+
|
||||
+ apr_hash_this(index, (const void **)&idp,
|
||||
+ &slen, (void *)&dontcare);
|
||||
+ ping_url = idp;
|
||||
+
|
||||
+ /*
|
||||
+ * If a list of IdP was given for probe discovery,
|
||||
+ * skip any IdP that does not match.
|
||||
+ */
|
||||
+ if (apr_hash_count(cfg->probe_discovery_idp) != 0) {
|
||||
+ char *value = apr_hash_get(cfg->probe_discovery_idp,
|
||||
+ idp, APR_HASH_KEY_STRING);
|
||||
+
|
||||
+ if (value == NULL) {
|
||||
+ /* idp not in list, try the next one */
|
||||
+ idp = NULL;
|
||||
+ continue;
|
||||
+ } else {
|
||||
+ /* idp in list, use the value as the ping url */
|
||||
+ ping_url = value;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ status = 0;
|
||||
+ if (am_httpclient_get(r, ping_url, &dontcare, &len,
|
||||
+ timeout, &status) != OK)
|
||||
+ continue;
|
||||
+
|
||||
+ if (status != HTTP_OK) {
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||
+ "Cannot probe %s: \"%s\" returned HTTP %ld",
|
||||
+ idp, ping_url, status);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ /* We got some succes */
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
|
||||
+ "probeDiscovery using %s", idp);
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * On failure, try default
|
||||
+ */
|
||||
+ if (idp == NULL) {
|
||||
+ idp = am_first_idp(r);
|
||||
+ if (idp == NULL) {
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||
+ "probeDiscovery found no usable IdP.");
|
||||
+ return HTTP_INTERNAL_SERVER_ERROR;
|
||||
+ } else {
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, "probeDiscovery "
|
||||
+ "failed, trying default IdP %s", idp);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ redirect_url = apr_psprintf(r->pool, "%s%s%s=%s", return_to,
|
||||
+ strchr(return_to, '?') ? "&" : "?",
|
||||
+ am_urlencode(r->pool, idp_param),
|
||||
+ am_urlencode(r->pool, idp));
|
||||
+
|
||||
+ apr_table_setn(r->headers_out, "Location", redirect_url);
|
||||
+
|
||||
+ return HTTP_SEE_OTHER;
|
||||
+}
|
||||
+
|
||||
+
|
||||
/* This function takes a request for an endpoint and passes it on to the
|
||||
* correct handler function.
|
||||
*
|
||||
@@ -2656,6 +2728,8 @@
|
||||
return am_handle_logout(r);
|
||||
} else if(!strcmp(endpoint, "login")) {
|
||||
return am_handle_login(r);
|
||||
+ } else if(!strcmp(endpoint, "probeDisco")) {
|
||||
+ return am_handle_probe_discovery(r);
|
||||
} else {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||
"Endpoint \"%s\" not handled by mod_auth_mellon.",
|
||||
Index: auth_mellon.h
|
||||
===================================================================
|
||||
--- auth_mellon.h (revision 112)
|
||||
+++ auth_mellon.h (working copy)
|
||||
@@ -174,6 +174,8 @@
|
||||
|
||||
/* IdP discovery service */
|
||||
const char *discovery_url;
|
||||
+ int probe_discovery_timeout;
|
||||
+ apr_hash_t *probe_discovery_idp;
|
||||
|
||||
/* Mutex to prevent us from creating several lasso server objects. */
|
||||
apr_thread_mutex_t *server_mutex;
|
||||
Index: README
|
||||
===================================================================
|
||||
--- README (revision 112)
|
||||
+++ README (working copy)
|
||||
@@ -321,8 +321,17 @@
|
||||
# The IdP discovery must redirect the user to the return URL,
|
||||
# with retueniDParam set to the selected IdP providerID.
|
||||
#
|
||||
- # Alternatively, a simple built-in IdP discovery can be used,
|
||||
- # by specifying "builtin:get-metadata?timeout=1"
|
||||
+ # The builtin:get-metadata discovery URL is not supported anymore
|
||||
+ # starting with 0.3.1. See MellonProbeDiscoveryTimeout for
|
||||
+ # a replacement.
|
||||
+ #
|
||||
+ # Default: None set.
|
||||
+ MellonDiscoveryURL "http://www.example.net/idp-discovery"
|
||||
+
|
||||
+ # MellonProbeDiscoveryTimeout sets the timeout of the
|
||||
+ # IdP probe discovery service, which is available on the
|
||||
+ # probeDisco endoint.
|
||||
+ #
|
||||
# This will cause the SP to send HTTP GET requests on the
|
||||
# configured IdP PorviderID URL. Theses URL should be used to
|
||||
# publish metadata, though this is not mandatory. If the IdP
|
||||
@@ -330,9 +339,17 @@
|
||||
# If the PorviderID URL requires SSL, MellonIdPCAFile is used
|
||||
# as a trusted CA bundle.
|
||||
#
|
||||
- # Default: None set.
|
||||
- MellonDiscoveryURL "http://www.example.net/idp-discovery"
|
||||
+ # Default: unset, which means the feature is disabled
|
||||
+ # MellonProbeDiscoveryTimeout 1
|
||||
|
||||
+ # MellonProbeDiscoveryIdP can be used to restrict the
|
||||
+ # list of IdP queried by the IdP probe discovery service.
|
||||
+ #
|
||||
+ # Default unset, which means that all configured IdP are
|
||||
+ # queried.
|
||||
+ # MellonProbeDiscoveryIdP http://idp1.example.com/saml/metadata
|
||||
+ # MellonProbeDiscoveryIdP http://idp2.example.net/saml/metadata
|
||||
+
|
||||
# This option will make the SAML authentication assertion
|
||||
# available in the MELLON_SAML_RESPONSE environement
|
||||
# variable. This assertion holds a verifiable signature
|
||||
@@ -476,7 +493,39 @@
|
||||
This will return the user to "https://www.example.org/logged_out.html"
|
||||
after the logout operation has completed.
|
||||
|
||||
+===========================================================================
|
||||
+ Probe IdP discovery
|
||||
+===========================================================================
|
||||
|
||||
+mod_auth_mellon has an IdP probe discovery service that sends HTTP GET
|
||||
+to IdP and picks the first that answers. This can be used as a poor
|
||||
+man's failover setup that redirects to your organisation internal IdP.
|
||||
+Here is a sample configuration:
|
||||
+
|
||||
+ MellonEndpointPath "/saml"
|
||||
+ (...)
|
||||
+ MellonDiscoveryUrl "/saml/probeDisco"
|
||||
+ MellonProbeDiscoveryTimeout 1
|
||||
+
|
||||
+The SP will sends HTTP GET to each configured IdP providerId URL until
|
||||
+it gets an HTTP 200 response within the 1 second timeout. It will then
|
||||
+proceed with that IdP.
|
||||
+
|
||||
+If you are in a federation, then your IdP login page will need to provide
|
||||
+an IdP selection feature aimed at users from other institutions (after
|
||||
+such a choice, the user would be redirected to the SP's /saml/login
|
||||
+endpoint, with ReturnTo and IdP set appropriately). In such a setup,
|
||||
+you will want to configure external IdP in mod_auth_mellon, but not
|
||||
+use them for IdP probe discovery. The MellonProbeDiscoveryIdP
|
||||
+directive can be used to limit the usable IdP for probe discovery:
|
||||
+
|
||||
+ MellonEndpointPath "/saml"
|
||||
+ (...)
|
||||
+ MellonDiscoveryUrl "/saml/probeDisco"
|
||||
+ MellonProbeDiscoveryTimeout 1
|
||||
+ MellonProbeDiscoveryIdP "https://idp1.example.net/saml/metadata"
|
||||
+ MellonProbeDiscoveryIdP "https://idp2.example.net/saml/metadata"
|
||||
+
|
||||
===========================================================================
|
||||
Contributors
|
||||
===========================================================================
|
||||
Index: auth_mellon_config.c
|
||||
===================================================================
|
||||
--- auth_mellon_config.c (revision 112)
|
||||
+++ auth_mellon_config.c (working copy)
|
||||
@@ -76,6 +76,47 @@
|
||||
*/
|
||||
static const int post_count = 100;
|
||||
|
||||
+/* This function handles configuration directives which set a
|
||||
+ * multivalued string slot in the module configuration (the destination
|
||||
+ * strucure is a hash).
|
||||
+ *
|
||||
+ * Parameters:
|
||||
+ * cmd_parms *cmd The command structure for this configuration
|
||||
+ * directive.
|
||||
+ * void *struct_ptr Pointer to the current directory configuration.
|
||||
+ * NULL if we are not in a directory configuration.
|
||||
+ * This value isn't used by this function.
|
||||
+ * const char *key The string argument following this configuration
|
||||
+ * directive in the configuraion file.
|
||||
+ * const char *value Optional value to be stored in the hash.
|
||||
+ *
|
||||
+ * Returns:
|
||||
+ * NULL on success or an error string on failure.
|
||||
+ */
|
||||
+static const char *am_set_hash_string_slot(cmd_parms *cmd,
|
||||
+ void *struct_ptr,
|
||||
+ const char *key,
|
||||
+ const char *value)
|
||||
+{
|
||||
+ server_rec *s = cmd->server;
|
||||
+ apr_pool_t *pconf = s->process->pconf;
|
||||
+ am_dir_cfg_rec *cfg = (am_dir_cfg_rec *)struct_ptr;
|
||||
+ int offset;
|
||||
+ apr_hash_t **hash;
|
||||
+
|
||||
+ /*
|
||||
+ * If no value is given, we just store the key in the hash.
|
||||
+ */
|
||||
+ if (value == NULL || *value == '\0')
|
||||
+ value = key;
|
||||
+
|
||||
+ offset = (int)(long)cmd->info;
|
||||
+ hash = (apr_hash_t **)((char *)cfg + offset);
|
||||
+ apr_hash_set(*hash, apr_pstrdup(pconf, key), APR_HASH_KEY_STRING, value);
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
/* This function handles configuration directives which set a file
|
||||
* slot in the module configuration. If lasso is recent enough, it
|
||||
* attempts to read the file immediatly.
|
||||
@@ -133,10 +174,10 @@
|
||||
* NULL on success or an error string on failure.
|
||||
*
|
||||
*/
|
||||
-static const char *am_get_proovider_id(apr_pool_t *p,
|
||||
- server_rec *s,
|
||||
- const char *file,
|
||||
- const char **provider)
|
||||
+static const char *am_get_provider_id(apr_pool_t *p,
|
||||
+ server_rec *s,
|
||||
+ const char *file,
|
||||
+ const char **provider)
|
||||
{
|
||||
char *data;
|
||||
apr_xml_parser *xp;
|
||||
@@ -195,7 +236,7 @@
|
||||
* Returns:
|
||||
* NULL on success or an error string on failure.
|
||||
*/
|
||||
-static const char *ap_set_idp_string_slot(cmd_parms *cmd,
|
||||
+static const char *am_set_idp_string_slot(cmd_parms *cmd,
|
||||
void *struct_ptr,
|
||||
const char *arg)
|
||||
{
|
||||
@@ -205,8 +246,8 @@
|
||||
const char *error;
|
||||
const char *provider_id;
|
||||
|
||||
- if ((error = am_get_proovider_id(cmd->pool, s,
|
||||
- arg, &provider_id)) != NULL)
|
||||
+ if ((error = am_get_provider_id(cmd->pool, s,
|
||||
+ arg, &provider_id)) != NULL)
|
||||
return apr_psprintf(cmd->pool, "%s - %s", cmd->cmd->name, error);
|
||||
|
||||
apr_hash_set(cfg->idp_metadata_files,
|
||||
@@ -649,8 +690,8 @@
|
||||
),
|
||||
AP_INIT_TAKE1(
|
||||
"MellonIdPMetadataFile",
|
||||
- ap_set_idp_string_slot,
|
||||
- NULL,
|
||||
+ am_set_idp_string_slot,
|
||||
+ NULL,
|
||||
OR_AUTHCFG,
|
||||
"Full path to xml metadata file for the IdP."
|
||||
),
|
||||
@@ -705,6 +746,21 @@
|
||||
"The URL of IdP discovery service. Default is unset."
|
||||
),
|
||||
AP_INIT_TAKE1(
|
||||
+ "MellonProbeDiscoveryTimeout",
|
||||
+ ap_set_int_slot,
|
||||
+ (void *)APR_OFFSETOF(am_dir_cfg_rec, probe_discovery_timeout),
|
||||
+ OR_AUTHCFG,
|
||||
+ "The timeout of IdP probe discovery service. "
|
||||
+ "Default is 1s"
|
||||
+ ),
|
||||
+ AP_INIT_TAKE12(
|
||||
+ "MellonProbeDiscoveryIdP",
|
||||
+ am_set_hash_string_slot,
|
||||
+ (void *)APR_OFFSETOF(am_dir_cfg_rec, probe_discovery_idp),
|
||||
+ OR_AUTHCFG,
|
||||
+ "An IdP that can be used for IdP probe discovery."
|
||||
+ ),
|
||||
+ AP_INIT_TAKE1(
|
||||
"MellonEndpointPath",
|
||||
am_set_endpoint_path,
|
||||
NULL,
|
||||
@@ -760,6 +816,8 @@
|
||||
dir->idp_ca_file = NULL;
|
||||
dir->login_path = default_login_path;
|
||||
dir->discovery_url = NULL;
|
||||
+ dir->probe_discovery_timeout = -1; /* -1 means no probe discovery */
|
||||
+ dir->probe_discovery_idp = apr_hash_make(p);
|
||||
|
||||
dir->sp_org_name = apr_hash_make(p);
|
||||
dir->sp_org_display_name = apr_hash_make(p);
|
||||
@@ -903,6 +961,16 @@
|
||||
add_cfg->discovery_url :
|
||||
base_cfg->discovery_url);
|
||||
|
||||
+ new_cfg->probe_discovery_timeout =
|
||||
+ (add_cfg->probe_discovery_timeout != -1 ?
|
||||
+ add_cfg->probe_discovery_timeout :
|
||||
+ base_cfg->probe_discovery_timeout);
|
||||
+
|
||||
+ new_cfg->probe_discovery_idp = apr_hash_copy(p,
|
||||
+ (apr_hash_count(add_cfg->probe_discovery_idp) > 0) ?
|
||||
+ add_cfg->probe_discovery_idp :
|
||||
+ base_cfg->probe_discovery_idp);
|
||||
+
|
||||
apr_thread_mutex_create(&new_cfg->server_mutex,
|
||||
APR_THREAD_MUTEX_DEFAULT, p);
|
||||
new_cfg->server = NULL;
|
|
@ -1,65 +0,0 @@
|
|||
$NetBSD: patch-af,v 1.1 2011/04/04 08:46:42 manu Exp $
|
||||
|
||||
Make remapped attribute usable for MellonUser
|
||||
|
||||
--- auth_mellon_cache.c.orig 2011-02-28 17:12:42.000000000 +0100
|
||||
+++ auth_mellon_cache.c 2011-02-28 17:59:02.000000000 +0100
|
||||
@@ -367,21 +367,8 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- if(t->user[0] != '\0') {
|
||||
- /* We have a user-"name". Set r->user and r->ap_auth_type. */
|
||||
- r->user = apr_pstrdup(r->pool, t->user);
|
||||
- r->ap_auth_type = apr_pstrdup(r->pool, "Mellon");
|
||||
- } else {
|
||||
- /* We don't have a user-"name". Log error. */
|
||||
- ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r,
|
||||
- "Didn't find the attribute \"%s\" in the attributes"
|
||||
- " which were received from the IdP. Cannot set a user"
|
||||
- " for this request without a valid user attribute.",
|
||||
- d->userattr);
|
||||
- }
|
||||
-
|
||||
/* Allocate a set of counters for duplicate variables in the list. */
|
||||
counters = apr_hash_make(r->pool);
|
||||
|
||||
/* Populate the subprocess environment with the attributes we
|
||||
@@ -398,8 +385,13 @@
|
||||
}
|
||||
|
||||
value = t->env[i].value;
|
||||
|
||||
+ /*
|
||||
+ * If we find a variable remapping to MellonUser, use it.
|
||||
+ */
|
||||
+ if ((t->user[0] == '\0') && (strcmp(varname, d->userattr) == 0))
|
||||
+ strcpy(t->user, value);
|
||||
|
||||
/* Find the number of times this variable has been set. */
|
||||
count = apr_hash_get(counters, varname, APR_HASH_KEY_STRING);
|
||||
if(count == NULL) {
|
||||
@@ -425,8 +417,22 @@
|
||||
/* Increase the count. */
|
||||
++(*count);
|
||||
}
|
||||
|
||||
+ if(t->user[0] != '\0') {
|
||||
+ /* We have a user-"name". Set r->user and r->ap_auth_type. */
|
||||
+ r->user = apr_pstrdup(r->pool, t->user);
|
||||
+ r->ap_auth_type = apr_pstrdup(r->pool, "Mellon");
|
||||
+ } else {
|
||||
+ /* We don't have a user-"name". Log error. */
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r,
|
||||
+ "Didn't find the attribute \"%s\" in the attributes"
|
||||
+ " which were received from the IdP. Cannot set a user"
|
||||
+ " for this request without a valid user attribute.",
|
||||
+ d->userattr);
|
||||
+ }
|
||||
+
|
||||
+
|
||||
/* Populate with the session? */
|
||||
if (d->dump_session) {
|
||||
char *session;
|
||||
int srclen, dstlen;
|
|
@ -1,149 +0,0 @@
|
|||
$NetBSD: patch-ag,v 1.1 2011/04/04 08:46:42 manu Exp $
|
||||
|
||||
Add the MellonIdPMetadataGlob directive (pulled from upstream)
|
||||
|
||||
Index: auth_mellon_util.c
|
||||
===================================================================
|
||||
--- auth_mellon_util.c (revision 116)
|
||||
+++ auth_mellon_util.c (working copy)
|
||||
@@ -838,6 +838,31 @@
|
||||
return ret;
|
||||
}
|
||||
|
||||
+/* This returns the directroy part of a path, a la dirname(3)
|
||||
+ *
|
||||
+ * Parameters:
|
||||
+ * apr_pool_t p Pool to allocate memory from
|
||||
+ * const char *path Path to extract directory from
|
||||
+ *
|
||||
+ * Returns:
|
||||
+ * The directory part of path
|
||||
+ */
|
||||
+const char *am_filepath_dirname(apr_pool_t *p, const char *path)
|
||||
+{
|
||||
+ char *cp;
|
||||
+
|
||||
+ /*
|
||||
+ * Try Unix and then Windows style. Borrowed from
|
||||
+ * apr_match_glob(), it seems it cannot be made more
|
||||
+ * portable.
|
||||
+ */
|
||||
+ if (((cp = strrchr(path, (int)'/')) == NULL) &&
|
||||
+ ((cp = strrchr(path, (int)'\\')) == NULL))
|
||||
+ return ".";
|
||||
+
|
||||
+ return apr_pstrndup(p, path, cp - path);
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* malloc a buffer and fill it with a given file
|
||||
*
|
||||
Index: auth_mellon.h
|
||||
===================================================================
|
||||
--- auth_mellon.h (revision 116)
|
||||
+++ auth_mellon.h (working copy)
|
||||
@@ -52,6 +52,7 @@
|
||||
#include "apr_file_io.h"
|
||||
#include "apr_xml.h"
|
||||
#include "apr_lib.h"
|
||||
+#include "apr_fnmatch.h"
|
||||
|
||||
#include "ap_config.h"
|
||||
#include "httpd.h"
|
||||
@@ -296,6 +297,7 @@
|
||||
int am_postdir_cleanup(request_rec *s);
|
||||
char *am_htmlencode(request_rec *r, const char *str);
|
||||
int am_save_post(request_rec *r, const char **relay_state);
|
||||
+const char *am_filepath_dirname(apr_pool_t *p, const char *path);
|
||||
const char *am_strip_cr(request_rec *r, const char *str);
|
||||
const char *am_add_cr(request_rec *r, const char *str);
|
||||
const char *am_xstrtok(request_rec *r, const char *str,
|
||||
Index: README
|
||||
===================================================================
|
||||
--- README (revision 116)
|
||||
+++ README (working copy)
|
||||
@@ -349,6 +349,11 @@
|
||||
# Default: None set.
|
||||
MellonIdPMetadataFile /etc/apache2/mellon/idp-metadata.xml
|
||||
|
||||
+ # MellonIdPMetadataGlob is a glob(3) pattern enabled alternative
|
||||
+ # to MellonIdPMetadataFile.
|
||||
+ # Default: None set.
|
||||
+ #MellonIdPMetadataGlob /etc/apache2/mellon/*-metadata.xml
|
||||
+
|
||||
# MellonIdpPublicKeyFile is the full path of the public key of the
|
||||
# IdP. This parameter is optional if the public key is embedded
|
||||
# in the IdP's metadata file, or if a certificate authority is
|
||||
Index: auth_mellon_config.c
|
||||
===================================================================
|
||||
--- auth_mellon_config.c (revision 116)
|
||||
+++ auth_mellon_config.c (working copy)
|
||||
@@ -222,6 +222,54 @@
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+/* This function handles configuration directives which use
|
||||
+ * a glob pattern
|
||||
+ *
|
||||
+ * Parameters:
|
||||
+ * cmd_parms *cmd The command structure for this configuration
|
||||
+ * directive.
|
||||
+ * void *struct_ptr Pointer to the current directory configuration.
|
||||
+ * NULL if we are not in a directory configuration.
|
||||
+ * const char *arg The string argument following this configuration
|
||||
+ * directive in the configuraion file.
|
||||
+ *
|
||||
+ * Returns:
|
||||
+ * NULL on success or an error string on failure.
|
||||
+ */
|
||||
+static const char *am_set_glob_fn(cmd_parms *cmd,
|
||||
+ void *struct_ptr,
|
||||
+ const char *arg)
|
||||
+{
|
||||
+ const char *(*take_argv)(cmd_parms *, void *, const char *);
|
||||
+ apr_array_header_t *files;
|
||||
+ const char *error;
|
||||
+ const char *directory;
|
||||
+ int i;
|
||||
+
|
||||
+ take_argv = cmd->info;
|
||||
+ directory = am_filepath_dirname(cmd->pool, arg);
|
||||
+
|
||||
+ if (arg == NULL || *arg == '\0')
|
||||
+ return apr_psprintf(cmd->pool, "%s takes one argument", cmd->cmd->name);
|
||||
+
|
||||
+ if (apr_match_glob(arg, &files, cmd->pool) != 0)
|
||||
+ return take_argv(cmd, struct_ptr, arg);
|
||||
+
|
||||
+ for (i = 0; i < files->nelts; i++) {
|
||||
+ const char *path;
|
||||
+
|
||||
+ path = apr_pstrcat(cmd->pool, directory, "/",
|
||||
+ ((const char **)(files->elts))[i], NULL);
|
||||
+
|
||||
+ error = take_argv(cmd, struct_ptr, path);
|
||||
+
|
||||
+ if (error != NULL)
|
||||
+ return error;
|
||||
+ }
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
/* This function handles configuration directives which set an
|
||||
* idp related slot in the module configuration.
|
||||
*
|
||||
@@ -872,6 +920,13 @@
|
||||
"Full path to xml metadata file for the IdP."
|
||||
),
|
||||
AP_INIT_TAKE1(
|
||||
+ "MellonIdPMetadataGlob",
|
||||
+ am_set_glob_fn,
|
||||
+ am_set_idp_string_slot,
|
||||
+ OR_AUTHCFG,
|
||||
+ "Full path to xml metadata files for the IdP, with glob(3) patterns."
|
||||
+ ),
|
||||
+ AP_INIT_TAKE1(
|
||||
"MellonIdPPublicKeyFile",
|
||||
ap_set_string_slot,
|
||||
(void *)APR_OFFSETOF(am_dir_cfg_rec, idp_public_key_file),
|
|
@ -1,91 +0,0 @@
|
|||
$NetBSD: patch-ah,v 1.1 2011/05/07 05:15:21 manu Exp $
|
||||
|
||||
Unbreak SP initiated SLO with lasso >= 2.3.5
|
||||
|
||||
--- auth_mellon_handler.c.orig 2011-05-07 06:31:46.000000000 +0200
|
||||
+++ auth_mellon_handler.c 2011-05-07 06:57:03.000000000 +0200
|
||||
@@ -774,8 +774,9 @@
|
||||
gint res;
|
||||
char *redirect_to;
|
||||
LassoProfile *profile;
|
||||
LassoSession *session;
|
||||
+ GList *assertion_list;
|
||||
LassoNode *assertion_n;
|
||||
LassoSaml2Assertion *assertion;
|
||||
LassoSaml2AuthnStatement *authnStatement;
|
||||
LassoSamlp2LogoutRequest *request;
|
||||
@@ -822,42 +823,46 @@
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
|
||||
- /* We need to set the SessionIndex in the LogoutRequest to the
|
||||
- * SessionIndex we received during the login operation.
|
||||
- */
|
||||
-
|
||||
profile = LASSO_PROFILE(logout);
|
||||
- session = lasso_profile_get_session(profile);
|
||||
|
||||
- /* We currently only look at the first assertion in the list
|
||||
- * lasso_session_get_assertions returns.
|
||||
+ /* We need to set the SessionIndex in the LogoutRequest to the SessionIndex
|
||||
+ * we received during the login operation. This is not needed since release
|
||||
+ * 2.3.0.
|
||||
*/
|
||||
- assertion_n = lasso_session_get_assertions(
|
||||
- session, profile->remote_providerID)->data;
|
||||
- if(LASSO_IS_SAML2_ASSERTION(assertion_n) == FALSE) {
|
||||
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||
- "No assertions found for the current session.");
|
||||
- lasso_logout_destroy(logout);
|
||||
- return HTTP_INTERNAL_SERVER_ERROR;
|
||||
- }
|
||||
-
|
||||
- assertion = LASSO_SAML2_ASSERTION(assertion_n);
|
||||
+ if (lasso_check_version(2, 3, 0, LASSO_CHECK_VERSION_NUMERIC) == 0) {
|
||||
+ session = lasso_profile_get_session(profile);
|
||||
+ assertion_list = lasso_session_get_assertions(
|
||||
+ session, profile->remote_providerID);
|
||||
+ if(! assertion_list ||
|
||||
+ LASSO_IS_SAML2_ASSERTION(assertion_list->data) == FALSE) {
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||
+ "No assertions found for the current session.");
|
||||
+ lasso_logout_destroy(logout);
|
||||
+ return HTTP_INTERNAL_SERVER_ERROR;
|
||||
+ }
|
||||
+ /* We currently only look at the first assertion in the list
|
||||
+ * lasso_session_get_assertions returns.
|
||||
+ */
|
||||
+ assertion_n = assertion_list->data;
|
||||
|
||||
- /* We assume that the first authnStatement contains the data we want. */
|
||||
- authnStatement = LASSO_SAML2_AUTHN_STATEMENT(assertion->AuthnStatement->data);
|
||||
+ assertion = LASSO_SAML2_ASSERTION(assertion_n);
|
||||
|
||||
- if(!authnStatement) {
|
||||
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||
- "No AuthnStatement found in the current assertion.");
|
||||
- lasso_logout_destroy(logout);
|
||||
- return HTTP_INTERNAL_SERVER_ERROR;
|
||||
- }
|
||||
+ /* We assume that the first authnStatement contains the data we want. */
|
||||
+ authnStatement = LASSO_SAML2_AUTHN_STATEMENT(assertion->AuthnStatement->data);
|
||||
|
||||
- if(authnStatement->SessionIndex) {
|
||||
- request = LASSO_SAMLP2_LOGOUT_REQUEST(profile->request);
|
||||
- request->SessionIndex = g_strdup(authnStatement->SessionIndex);
|
||||
+ if(!authnStatement) {
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||
+ "No AuthnStatement found in the current assertion.");
|
||||
+ lasso_logout_destroy(logout);
|
||||
+ return HTTP_INTERNAL_SERVER_ERROR;
|
||||
+ }
|
||||
+
|
||||
+ if(authnStatement->SessionIndex) {
|
||||
+ request = LASSO_SAMLP2_LOGOUT_REQUEST(profile->request);
|
||||
+ request->SessionIndex = g_strdup(authnStatement->SessionIndex);
|
||||
+ }
|
||||
}
|
||||
|
||||
|
||||
/* Set the RelayState parameter to the return url (if we have one). */
|
310
www/ap2-auth-mellon/patches/patch-ai
Normal file
310
www/ap2-auth-mellon/patches/patch-ai
Normal file
|
@ -0,0 +1,310 @@
|
|||
$NetBSD: patch-ai,v 1.1 2011/12/06 09:58:01 manu Exp $
|
||||
|
||||
Honour MellonProbeDiscoveryIdP order when sending probes (from upstream)
|
||||
|
||||
--- auth_mellon.h.orig 2011-05-18 12:39:00.000000000 +0200
|
||||
+++ auth_mellon.h 2011-12-06 09:54:08.000000000 +0100
|
||||
@@ -209,9 +209,9 @@
|
||||
|
||||
/* IdP discovery service */
|
||||
const char *discovery_url;
|
||||
int probe_discovery_timeout;
|
||||
- apr_hash_t *probe_discovery_idp;
|
||||
+ apr_table_t *probe_discovery_idp;
|
||||
|
||||
/* The configuration record we "inherit" the lasso server object from. */
|
||||
struct am_dir_cfg_rec *inherit_server_from;
|
||||
/* Mutex to prevent us from creating several lasso server objects. */
|
||||
--- auth_mellon_config.c.orig 2011-05-18 12:39:00.000000000 +0200
|
||||
+++ auth_mellon_config.c 2011-12-06 09:54:08.000000000 +0100
|
||||
@@ -76,8 +76,9 @@
|
||||
* the MellonPostCount configuration directive if you change this.
|
||||
*/
|
||||
static const int post_count = 100;
|
||||
|
||||
+#if unused
|
||||
/* This function handles configuration directives which set a
|
||||
* multivalued string slot in the module configuration (the destination
|
||||
* strucure is a hash).
|
||||
*
|
||||
@@ -85,9 +86,8 @@
|
||||
* cmd_parms *cmd The command structure for this configuration
|
||||
* directive.
|
||||
* void *struct_ptr Pointer to the current directory configuration.
|
||||
* NULL if we are not in a directory configuration.
|
||||
- * This value isn't used by this function.
|
||||
* const char *key The string argument following this configuration
|
||||
* directive in the configuraion file.
|
||||
* const char *value Optional value to be stored in the hash.
|
||||
*
|
||||
@@ -116,8 +116,49 @@
|
||||
apr_hash_set(*hash, apr_pstrdup(pconf, key), APR_HASH_KEY_STRING, value);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
+#endif /* unused */
|
||||
+
|
||||
+/* This function handles configuration directives which set a
|
||||
+ * multivalued string slot in the module configuration (the destination
|
||||
+ * strucure is a table).
|
||||
+ *
|
||||
+ * Parameters:
|
||||
+ * cmd_parms *cmd The command structure for this configuration
|
||||
+ * directive.
|
||||
+ * void *struct_ptr Pointer to the current directory configuration.
|
||||
+ * NULL if we are not in a directory configuration.
|
||||
+ * const char *key The string argument following this configuration
|
||||
+ * directive in the configuraion file.
|
||||
+ * const char *value Optional value to be stored in the hash.
|
||||
+ *
|
||||
+ * Returns:
|
||||
+ * NULL on success or an error string on failure.
|
||||
+ */
|
||||
+static const char *am_set_table_string_slot(cmd_parms *cmd,
|
||||
+ void *struct_ptr,
|
||||
+ const char *key,
|
||||
+ const char *value)
|
||||
+{
|
||||
+ server_rec *s = cmd->server;
|
||||
+ apr_pool_t *pconf = s->process->pconf;
|
||||
+ am_dir_cfg_rec *cfg = (am_dir_cfg_rec *)struct_ptr;
|
||||
+ int offset;
|
||||
+ apr_table_t **table;
|
||||
+
|
||||
+ /*
|
||||
+ * If no value is given, we just store the key in the hash.
|
||||
+ */
|
||||
+ if (value == NULL || *value == '\0')
|
||||
+ value = key;
|
||||
+
|
||||
+ offset = (int)(long)cmd->info;
|
||||
+ table = (apr_table_t **)((char *)cfg + offset);
|
||||
+ apr_table_set(*table, apr_pstrdup(pconf, key), value);
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
|
||||
/* This function handles configuration directives which set a file
|
||||
* slot in the module configuration. If lasso is recent enough, it
|
||||
* attempts to read the file immediatly.
|
||||
@@ -1008,9 +1049,9 @@
|
||||
"Default is 1s"
|
||||
),
|
||||
AP_INIT_TAKE12(
|
||||
"MellonProbeDiscoveryIdP",
|
||||
- am_set_hash_string_slot,
|
||||
+ am_set_table_string_slot,
|
||||
(void *)APR_OFFSETOF(am_dir_cfg_rec, probe_discovery_idp),
|
||||
OR_AUTHCFG,
|
||||
"An IdP that can be used for IdP probe discovery."
|
||||
),
|
||||
@@ -1097,9 +1138,9 @@
|
||||
dir->idp_ignore = NULL;
|
||||
dir->login_path = default_login_path;
|
||||
dir->discovery_url = NULL;
|
||||
dir->probe_discovery_timeout = -1; /* -1 means no probe discovery */
|
||||
- dir->probe_discovery_idp = apr_hash_make(p);
|
||||
+ dir->probe_discovery_idp = apr_table_make(p, 0);
|
||||
|
||||
dir->sp_org_name = apr_hash_make(p);
|
||||
dir->sp_org_display_name = apr_hash_make(p);
|
||||
dir->sp_org_url = apr_hash_make(p);
|
||||
@@ -1292,12 +1333,12 @@
|
||||
(add_cfg->probe_discovery_timeout != -1 ?
|
||||
add_cfg->probe_discovery_timeout :
|
||||
base_cfg->probe_discovery_timeout);
|
||||
|
||||
- new_cfg->probe_discovery_idp = apr_hash_copy(p,
|
||||
- (apr_hash_count(add_cfg->probe_discovery_idp) > 0) ?
|
||||
- add_cfg->probe_discovery_idp :
|
||||
- base_cfg->probe_discovery_idp);
|
||||
+ new_cfg->probe_discovery_idp = apr_table_copy(p,
|
||||
+ (!apr_is_empty_table(add_cfg->probe_discovery_idp)) ?
|
||||
+ add_cfg->probe_discovery_idp :
|
||||
+ base_cfg->probe_discovery_idp);
|
||||
|
||||
|
||||
if (cfg_can_inherit_lasso_server(add_cfg)) {
|
||||
new_cfg->inherit_server_from = base_cfg->inherit_server_from;
|
||||
--- auth_mellon_handler.c.orig 2011-05-18 12:39:00.000000000 +0200
|
||||
+++ auth_mellon_handler.c 2011-12-06 10:40:20.000000000 +0100
|
||||
@@ -2572,8 +2572,40 @@
|
||||
|
||||
return am_send_authn_request(r, idp, return_to, is_passive);
|
||||
}
|
||||
|
||||
+/* This function probes an URL (HTTP GET)
|
||||
+ *
|
||||
+ * Parameters:
|
||||
+ * request_rec *r The request.
|
||||
+ * const char *url The URL
|
||||
+ * int timeout Timeout in seconds
|
||||
+ *
|
||||
+ * Returns:
|
||||
+ * OK on success, or an error if any of the steps fail.
|
||||
+ */
|
||||
+static int am_probe_url(request_rec *r, const char *url, int timeout)
|
||||
+{
|
||||
+ void *dontcare;
|
||||
+ apr_size_t len;
|
||||
+ long status;
|
||||
+ int error;
|
||||
+
|
||||
+ status = 0;
|
||||
+ if ((error = am_httpclient_get(r, url, &dontcare, &len,
|
||||
+ timeout, &status)) != OK)
|
||||
+ return error;
|
||||
+
|
||||
+ if (status != HTTP_OK) {
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||
+ "Probe on \"%s\" returned HTTP %ld",
|
||||
+ url, status);
|
||||
+ return status;
|
||||
+ }
|
||||
+
|
||||
+ return OK;
|
||||
+}
|
||||
+
|
||||
/* This function handles requests to the probe discovery handler
|
||||
*
|
||||
* Parameters:
|
||||
* request_rec *r The request.
|
||||
@@ -2583,11 +2615,10 @@
|
||||
*/
|
||||
static int am_handle_probe_discovery(request_rec *r) {
|
||||
am_dir_cfg_rec *cfg = am_get_dir_cfg(r);
|
||||
LassoServer *server;
|
||||
- const char *idp = NULL;
|
||||
+ const char *disco_idp = NULL;
|
||||
int timeout;
|
||||
- GHashTableIter iter;
|
||||
char *return_to;
|
||||
char *idp_param;
|
||||
char *redirect_url;
|
||||
int ret;
|
||||
@@ -2644,82 +2675,77 @@
|
||||
|
||||
/*
|
||||
* Proceed with built-in IdP discovery.
|
||||
*
|
||||
- * Send probes for all configured IdP to check availability.
|
||||
- * The first to answer is chosen, but the list of usable
|
||||
- * IdP can be restricted in configuration.
|
||||
+ * First try sending probes to IdP configured for discovery.
|
||||
+ * Second send probes for all configured IdP
|
||||
+ * The first to answer is chosen.
|
||||
+ * If none answer, use the first configured IdP
|
||||
*/
|
||||
- g_hash_table_iter_init(&iter, server->providers);
|
||||
- while (g_hash_table_iter_next(&iter, (void**)&idp, NULL)) {
|
||||
- void *dontcare;
|
||||
- const char *ping_url;
|
||||
- apr_size_t len;
|
||||
- long status;
|
||||
-
|
||||
- ping_url = idp;
|
||||
-
|
||||
- /*
|
||||
- * If a list of IdP was given for probe discovery,
|
||||
- * skip any IdP that does not match.
|
||||
- */
|
||||
- if (apr_hash_count(cfg->probe_discovery_idp) != 0) {
|
||||
- char *value = apr_hash_get(cfg->probe_discovery_idp,
|
||||
- idp, APR_HASH_KEY_STRING);
|
||||
-
|
||||
- if (value == NULL) {
|
||||
- /* idp not in list, try the next one */
|
||||
- continue;
|
||||
- } else {
|
||||
- /* idp in list, use the value as the ping url */
|
||||
- ping_url = value;
|
||||
+ if (!apr_is_empty_table(cfg->probe_discovery_idp)) {
|
||||
+ const apr_array_header_t *header;
|
||||
+ apr_table_entry_t *elts;
|
||||
+ const char *url;
|
||||
+ const char *idp;
|
||||
+ int i;
|
||||
+
|
||||
+ header = apr_table_elts(cfg->probe_discovery_idp);
|
||||
+ elts = (apr_table_entry_t *)header->elts;
|
||||
+
|
||||
+ for (i = 0; i < header->nelts; i++) {
|
||||
+ idp = elts[i].key;
|
||||
+ url = elts[i].val;
|
||||
+
|
||||
+ if (am_probe_url(r, url, timeout) == OK) {
|
||||
+ disco_idp = idp;
|
||||
+ break;
|
||||
}
|
||||
}
|
||||
-
|
||||
- status = 0;
|
||||
- if (am_httpclient_get(r, ping_url, &dontcare, &len,
|
||||
- timeout, &status) != OK)
|
||||
- continue;
|
||||
-
|
||||
- if (status != HTTP_OK) {
|
||||
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||
- "Cannot probe %s: \"%s\" returned HTTP %ld",
|
||||
- idp, ping_url, status);
|
||||
- continue;
|
||||
+ } else {
|
||||
+ GList *iter;
|
||||
+ GList *idp_list;
|
||||
+ const char *idp;
|
||||
+
|
||||
+ idp_list = g_hash_table_get_keys(server->providers);
|
||||
+ for (iter = idp_list; iter != NULL; iter = iter->next) {
|
||||
+ idp = iter->data;
|
||||
+
|
||||
+ if (am_probe_url(r, idp, timeout) == OK) {
|
||||
+ disco_idp = idp;
|
||||
+ break;
|
||||
+ }
|
||||
}
|
||||
-
|
||||
- /* We got some succes */
|
||||
- ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
|
||||
- "probeDiscovery using %s", idp);
|
||||
- break;
|
||||
+ g_list_free(idp_list);
|
||||
}
|
||||
|
||||
/*
|
||||
* On failure, try default
|
||||
*/
|
||||
- if (idp == NULL) {
|
||||
- idp = am_first_idp(r);
|
||||
- if (idp == NULL) {
|
||||
+ if (disco_idp == NULL) {
|
||||
+ disco_idp = am_first_idp(r);
|
||||
+ if (disco_idp == NULL) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||
"probeDiscovery found no usable IdP.");
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
} else {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, "probeDiscovery "
|
||||
- "failed, trying default IdP %s", idp);
|
||||
+ "failed, trying default IdP %s", disco_idp);
|
||||
}
|
||||
+ } else {
|
||||
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
|
||||
+ "probeDiscovery using %s", disco_idp);
|
||||
}
|
||||
|
||||
redirect_url = apr_psprintf(r->pool, "%s%s%s=%s", return_to,
|
||||
strchr(return_to, '?') ? "&" : "?",
|
||||
am_urlencode(r->pool, idp_param),
|
||||
- am_urlencode(r->pool, idp));
|
||||
+ am_urlencode(r->pool, disco_idp));
|
||||
|
||||
apr_table_setn(r->headers_out, "Location", redirect_url);
|
||||
|
||||
return HTTP_SEE_OTHER;
|
||||
}
|
||||
|
||||
-
|
||||
/* This function takes a request for an endpoint and passes it on to the
|
||||
* correct handler function.
|
||||
*
|
||||
* Parameters:
|
Loading…
Reference in a new issue