Honour MellonProbeDiscoveryIdP order when sending probes

git-svn-id: https://modmellon.googlecode.com/svn/trunk/mod_mellon2@139 a716ebb1-153a-0410-b759-cfb97c6a1b53
This commit is contained in:
manu@netbsd.org 2011-12-05 19:06:44 +00:00
parent c7ebc20d0a
commit 08c4663f33
4 changed files with 125 additions and 56 deletions

4
NEWS
View File

@ -1,3 +1,7 @@
Version 0.4.1
* Honour MellonProbeDiscoveryIdP order when sending probes
Version 0.4.0
---------------------------------------------------------------------------

View File

@ -210,7 +210,7 @@ typedef struct am_dir_cfg_rec {
/* 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;

View File

@ -77,6 +77,7 @@ static const apr_size_t post_size = 1024 * 1024 * 1024;
*/
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).
@ -86,7 +87,6 @@ static const int post_count = 100;
* 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.
@ -117,6 +117,47 @@ static const char *am_set_hash_string_slot(cmd_parms *cmd,
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
@ -1009,7 +1050,7 @@ const command_rec auth_mellon_commands[] = {
),
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."
@ -1098,7 +1139,7 @@ void *auth_mellon_dir_config(apr_pool_t *p, char *d)
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);
@ -1293,10 +1334,10 @@ void *auth_mellon_dir_merge(apr_pool_t *p, void *base, void *add)
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)) {

View File

@ -2577,6 +2577,38 @@ static int am_handle_login(request_rec *r)
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:
@ -2588,10 +2620,8 @@ static int am_handle_login(request_rec *r)
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;
GList *idp_list;
GList *iter;
char *return_to;
char *idp_param;
char *redirect_url;
@ -2650,75 +2680,69 @@ static int am_handle_probe_discovery(request_rec *r) {
/*
* 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
*/
idp_list = g_hash_table_get_keys(server->providers);
for (iter = idp_list; iter != NULL; iter = iter->next) {
void *dontcare;
const char *ping_url;
apr_size_t len;
long status;
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;
idp = iter->data;
ping_url = idp;
header = apr_table_elts(cfg->probe_discovery_idp);
elts = (apr_table_entry_t *)header->elts;
/*
* 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);
for (i = 0; i < header->nelts; i++) {
idp = elts[i].key;
url = elts[i].val;
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 (am_probe_url(r, url, timeout) == OK) {
disco_idp = idp;
break;
}
}
} else {
GList *iter;
GList *idp_list;
const char *idp;
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;
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);
}
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);