Add support for loading federation metadata files.
Patch originally created by Emmanuel Dreyfus, some changes by me. git-svn-id: https://modmellon.googlecode.com/svn/trunk/mod_mellon2@129 a716ebb1-153a-0410-b759-cfb97c6a1b53
This commit is contained in:
parent
433634737d
commit
b68c7c641d
18
README
18
README
|
@ -357,11 +357,20 @@ MellonPostCount 100
|
|||
# metadata for the IdP you are authenticating against. This
|
||||
# directive is required. Mutliple IdP metadata can be configured
|
||||
# by using multiple MellonIdPMetadataFile directives.
|
||||
#
|
||||
# If your lasso library is recent enough (higher than 2.3.5),
|
||||
# then MellonIdPMetadataFile will accept an XML file containing
|
||||
# descriptors for multiple IdP. An optional validating chain can
|
||||
# be supplied as a second argument to MellonIdPMetadataFile. If
|
||||
# ommitted, no metadata validation will take place.
|
||||
#
|
||||
# Default: None set.
|
||||
MellonIdPMetadataFile /etc/apache2/mellon/idp-metadata.xml
|
||||
|
||||
# MellonIdPMetadataGlob is a glob(3) pattern enabled alternative
|
||||
# to MellonIdPMetadataFile.
|
||||
# to MellonIdPMetadataFile. Like MellonIdPMetadataFile it will
|
||||
# accept an optional validating chain if lasso is recent enough.
|
||||
#
|
||||
# Default: None set.
|
||||
#MellonIdPMetadataGlob /etc/apache2/mellon/*-metadata.xml
|
||||
|
||||
|
@ -378,6 +387,13 @@ MellonPostCount 100
|
|||
# Default: None set.
|
||||
MellonIdPCAFile /etc/apache2/mellon/ca.pem
|
||||
|
||||
# MellonIdPIgnore lists IdP entityId that should not loaded
|
||||
# from XML federation metadata files. This is usefull if an
|
||||
# IdP cause bugs. Multiple entityId may be specified through
|
||||
# single MellonIdPIgnore, and multiple MellonIdPIgnore are allowed.
|
||||
# Default: None set.
|
||||
#MellonIdPIgnore "https://bug.example.net/saml/idp"
|
||||
|
||||
# MellonDiscoveryURL is the URL for IdP discovery service.
|
||||
# This is used for selecting among multiple configured IdP.
|
||||
# On initiali user authentication, it is redirected to the
|
||||
|
|
|
@ -151,6 +151,11 @@ typedef struct {
|
|||
const char *directive;
|
||||
} am_cond_t;
|
||||
|
||||
typedef struct am_metadata {
|
||||
const char *file; /* Metadata file with one or many IdP */
|
||||
const char *chain; /* Validating chain */
|
||||
} am_metadata_t;
|
||||
|
||||
typedef struct am_dir_cfg_rec {
|
||||
/* enable_mellon is used to enable auth_mellon for a location.
|
||||
*/
|
||||
|
@ -183,9 +188,10 @@ typedef struct am_dir_cfg_rec {
|
|||
const char *sp_metadata_file;
|
||||
const char *sp_private_key_file;
|
||||
const char *sp_cert_file;
|
||||
apr_array_header_t *idp_metadata_files;
|
||||
apr_array_header_t *idp_metadata;
|
||||
const char *idp_public_key_file;
|
||||
const char *idp_ca_file;
|
||||
GList *idp_ignore;
|
||||
|
||||
/* metadata autogeneration helper */
|
||||
apr_hash_t *sp_org_name;
|
||||
|
|
|
@ -163,37 +163,41 @@ static const char *am_set_filestring_slot(cmd_parms *cmd,
|
|||
|
||||
|
||||
/* This function handles configuration directives which use
|
||||
* a glob pattern
|
||||
* a glob pattern, with a second optional argument
|
||||
*
|
||||
* 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.
|
||||
* const char *glob_pat glob(3) pattern
|
||||
* const char *option Optional argument
|
||||
*
|
||||
* 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)
|
||||
static const char *am_set_glob_fn12(cmd_parms *cmd,
|
||||
void *struct_ptr,
|
||||
const char *glob_pat,
|
||||
const char *option)
|
||||
{
|
||||
const char *(*take_argv)(cmd_parms *, void *, const char *);
|
||||
const char *(*take_argv)(cmd_parms *, void *, const char *, 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);
|
||||
directory = am_filepath_dirname(cmd->pool, glob_pat);
|
||||
|
||||
if (apr_match_glob(arg, &files, cmd->pool) != 0)
|
||||
return take_argv(cmd, struct_ptr, arg);
|
||||
if (glob_pat == NULL || *glob_pat == '\0')
|
||||
return apr_psprintf(cmd->pool,
|
||||
"%s takes one or two arguments",
|
||||
cmd->cmd->name);
|
||||
|
||||
if (apr_match_glob(glob_pat, &files, cmd->pool) != 0)
|
||||
return take_argv(cmd, struct_ptr, glob_pat, option);
|
||||
|
||||
for (i = 0; i < files->nelts; i++) {
|
||||
const char *path;
|
||||
|
@ -201,7 +205,7 @@ static const char *am_set_glob_fn(cmd_parms *cmd,
|
|||
path = apr_pstrcat(cmd->pool, directory, "/",
|
||||
((const char **)(files->elts))[i], NULL);
|
||||
|
||||
error = take_argv(cmd, struct_ptr, path);
|
||||
error = take_argv(cmd, struct_ptr, path, option);
|
||||
|
||||
if (error != NULL)
|
||||
return error;
|
||||
|
@ -218,28 +222,88 @@ static const char *am_set_glob_fn(cmd_parms *cmd,
|
|||
* 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.
|
||||
* const char *metadata Path to metadata file for one or multiple IdP
|
||||
* const char *chain Optional path to validating chain
|
||||
*
|
||||
* Returns:
|
||||
* NULL on success or an error string on failure.
|
||||
*/
|
||||
static const char *am_set_idp_string_slot(cmd_parms *cmd,
|
||||
void *struct_ptr,
|
||||
const char *arg)
|
||||
const char *metadata,
|
||||
const char *chain)
|
||||
{
|
||||
server_rec *s = cmd->server;
|
||||
apr_pool_t *pconf = s->process->pconf;
|
||||
am_dir_cfg_rec *cfg = (am_dir_cfg_rec *)struct_ptr;
|
||||
const char **filename_slot;
|
||||
|
||||
filename_slot = apr_array_push(cfg->idp_metadata_files);
|
||||
*filename_slot = apr_pstrdup(pconf, arg);
|
||||
#ifndef HAVE_lasso_server_load_metadata
|
||||
if (chain != NULL)
|
||||
return apr_psprintf(cmd->pool, "Cannot specify validating chain "
|
||||
"for %s since lasso library lacks "
|
||||
"lasso_server_load_metadata()", cmd->cmd->name);
|
||||
#endif /* HAVE_lasso_server_load_metadata */
|
||||
|
||||
am_metadata_t *idp_metadata = apr_array_push(cfg->idp_metadata);
|
||||
idp_metadata->file = apr_pstrdup(pconf, metadata);
|
||||
idp_metadata->chain = apr_pstrdup(pconf, chain);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* This function handles configuration directives which set an
|
||||
* idp federation blacklist slot in the module configuration.
|
||||
*
|
||||
* 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.
|
||||
* int argc Number of blacklisted providerId.
|
||||
* char *const argv[] List of blacklisted providerId.
|
||||
*
|
||||
* Returns:
|
||||
* NULL on success, or errror string
|
||||
*/
|
||||
static const char *am_set_idp_ignore_slot(cmd_parms *cmd,
|
||||
void *struct_ptr,
|
||||
int argc,
|
||||
char *const argv[])
|
||||
{
|
||||
#ifdef HAVE_lasso_server_load_metadata
|
||||
server_rec *s = cmd->server;
|
||||
apr_pool_t *pconf = s->process->pconf;
|
||||
am_dir_cfg_rec *cfg = (am_dir_cfg_rec *)struct_ptr;
|
||||
GList *new_idp_ignore;
|
||||
int i;
|
||||
|
||||
if (argc < 1)
|
||||
return apr_psprintf(cmd->pool, "%s takes at least one arguments",
|
||||
cmd->cmd->name);
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
new_idp_ignore = apr_palloc(pconf, sizeof(GList));
|
||||
new_idp_ignore->data = apr_pstrdup(pconf, argv[i]);
|
||||
|
||||
/* Prepend it to the list. */
|
||||
new_idp_ignore->next = cfg->idp_ignore;
|
||||
if (cfg->idp_ignore != NULL)
|
||||
cfg->idp_ignore->prev = new_idp_ignore;
|
||||
cfg->idp_ignore = new_idp_ignore;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
#else /* HAVE_lasso_server_load_metadata */
|
||||
|
||||
return apr_psprintf(cmd->pool, "Cannot use %s since lasso library lacks "
|
||||
"lasso_server_load_metadata()", cmd->cmd->name);
|
||||
|
||||
#endif /* HAVE_lasso_server_load_metadata */
|
||||
}
|
||||
|
||||
|
||||
/* This function handles configuration directives which set a string
|
||||
* slot in the module configuration.
|
||||
*
|
||||
|
@ -861,19 +925,21 @@ const command_rec auth_mellon_commands[] = {
|
|||
OR_AUTHCFG,
|
||||
"Full path to pem file with certificate for the SP."
|
||||
),
|
||||
AP_INIT_TAKE1(
|
||||
AP_INIT_TAKE12(
|
||||
"MellonIdPMetadataFile",
|
||||
am_set_idp_string_slot,
|
||||
NULL,
|
||||
OR_AUTHCFG,
|
||||
"Full path to xml metadata file for the IdP."
|
||||
"Full path to xml metadata file for IdP, "
|
||||
"with optional validating chain."
|
||||
),
|
||||
AP_INIT_TAKE1(
|
||||
AP_INIT_TAKE12(
|
||||
"MellonIdPMetadataGlob",
|
||||
am_set_glob_fn,
|
||||
am_set_glob_fn12,
|
||||
am_set_idp_string_slot,
|
||||
OR_AUTHCFG,
|
||||
"Full path to xml metadata files for the IdP, with glob(3) patterns."
|
||||
"Full path to xml metadata files for IdP, with glob(3) patterns. "
|
||||
"An optional validating chain can be supplied."
|
||||
),
|
||||
AP_INIT_TAKE1(
|
||||
"MellonIdPPublicKeyFile",
|
||||
|
@ -889,6 +955,13 @@ const command_rec auth_mellon_commands[] = {
|
|||
OR_AUTHCFG,
|
||||
"Full path to pem file with CA chain for the IdP."
|
||||
),
|
||||
AP_INIT_TAKE_ARGV(
|
||||
"MellonIdPIgnore",
|
||||
am_set_idp_ignore_slot,
|
||||
NULL,
|
||||
OR_AUTHCFG,
|
||||
"List of IdP entityId to ignore."
|
||||
),
|
||||
AP_INIT_TAKE12(
|
||||
"MellonOrganizationName",
|
||||
am_set_langstring_slot,
|
||||
|
@ -1017,9 +1090,10 @@ void *auth_mellon_dir_config(apr_pool_t *p, char *d)
|
|||
dir->sp_metadata_file = NULL;
|
||||
dir->sp_private_key_file = NULL;
|
||||
dir->sp_cert_file = NULL;
|
||||
dir->idp_metadata_files = apr_array_make(p, 0, sizeof(const char *));
|
||||
dir->idp_metadata = apr_array_make(p, 0, sizeof(am_metadata_t));
|
||||
dir->idp_public_key_file = NULL;
|
||||
dir->idp_ca_file = NULL;
|
||||
dir->idp_ignore = NULL;
|
||||
dir->login_path = default_login_path;
|
||||
dir->discovery_url = NULL;
|
||||
dir->probe_discovery_timeout = -1; /* -1 means no probe discovery */
|
||||
|
@ -1141,9 +1215,9 @@ void *auth_mellon_dir_merge(apr_pool_t *p, void *base, void *add)
|
|||
add_cfg->sp_cert_file :
|
||||
base_cfg->sp_cert_file);
|
||||
|
||||
new_cfg->idp_metadata_files = (add_cfg->idp_metadata_files->nelts > 0 ?
|
||||
add_cfg->idp_metadata_files :
|
||||
base_cfg->idp_metadata_files);
|
||||
new_cfg->idp_metadata = (add_cfg->idp_metadata->nelts ?
|
||||
add_cfg->idp_metadata :
|
||||
base_cfg->idp_metadata);
|
||||
|
||||
new_cfg->idp_public_key_file = (add_cfg->idp_public_key_file ?
|
||||
add_cfg->idp_public_key_file :
|
||||
|
@ -1153,6 +1227,10 @@ void *auth_mellon_dir_merge(apr_pool_t *p, void *base, void *add)
|
|||
add_cfg->idp_ca_file :
|
||||
base_cfg->idp_ca_file);
|
||||
|
||||
new_cfg->idp_ignore = add_cfg->idp_ignore != NULL ?
|
||||
add_cfg->idp_ignore :
|
||||
base_cfg->idp_ignore;
|
||||
|
||||
new_cfg->sp_org_name = apr_hash_copy(p,
|
||||
(apr_hash_count(add_cfg->sp_org_name) > 0) ?
|
||||
add_cfg->sp_org_name :
|
||||
|
|
|
@ -214,34 +214,64 @@ static char *am_generate_metadata(apr_pool_t *p, request_rec *r)
|
|||
static guint am_server_add_providers(request_rec *r)
|
||||
{
|
||||
am_dir_cfg_rec *cfg = am_get_dir_cfg(r);
|
||||
const char *idp_metadata_file;
|
||||
const char *idp_public_key_file;
|
||||
apr_size_t index;
|
||||
|
||||
if (cfg->idp_metadata_files->nelts == 1)
|
||||
if (cfg->idp_metadata->nelts == 1)
|
||||
idp_public_key_file = cfg->idp_public_key_file;
|
||||
else
|
||||
idp_public_key_file = NULL;
|
||||
|
||||
for (index = 0; index < cfg->idp_metadata_files->nelts; index++) {
|
||||
int ret;
|
||||
idp_metadata_file = APR_ARRAY_IDX(cfg->idp_metadata_files, index,
|
||||
const char *);
|
||||
for (index = 0; index < cfg->idp_metadata->nelts; index++) {
|
||||
const am_metadata_t *idp_metadata;
|
||||
int error;
|
||||
#ifdef HAVE_lasso_server_load_metadata
|
||||
GList *loaded_idp = NULL;
|
||||
#endif /* HAVE_lasso_server_load_metadata */
|
||||
|
||||
ret = lasso_server_add_provider(cfg->server, LASSO_PROVIDER_ROLE_IDP,
|
||||
idp_metadata_file,
|
||||
idp_public_key_file,
|
||||
cfg->idp_ca_file);
|
||||
if (ret != 0) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||
"Error adding IdP from \"%s\" to lasso server object.",
|
||||
idp_metadata_file);
|
||||
idp_metadata = &APR_ARRAY_IDX(cfg->idp_metadata, index, const am_metadata_t);
|
||||
|
||||
#ifdef HAVE_lasso_server_load_metadata
|
||||
error = lasso_server_load_metadata(cfg->server,
|
||||
LASSO_PROVIDER_ROLE_IDP,
|
||||
idp_metadata->file,
|
||||
idp_metadata->chain,
|
||||
cfg->idp_ignore,
|
||||
&loaded_idp,
|
||||
LASSO_SERVER_LOAD_METADATA_FLAG_DEFAULT);
|
||||
if (error == 0) {
|
||||
GList *idx;
|
||||
|
||||
for (idx = loaded_idp; idx != NULL; idx = idx->next) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
|
||||
"loaded IdP \"%s\" from \"%s\".",
|
||||
(char *)idx->data, idp_metadata->file);
|
||||
}
|
||||
}
|
||||
|
||||
if (loaded_idp != NULL)
|
||||
g_free(loaded_idp);
|
||||
|
||||
#else /* HAVE_lasso_server_load_metadata */
|
||||
error = lasso_server_add_provider(cfg->server,
|
||||
LASSO_PROVIDER_ROLE_IDP,
|
||||
idp_metadata->file,
|
||||
idp_public_key_file,
|
||||
cfg->idp_ca_file);
|
||||
#endif /* HAVE_lasso_server_load_metadata */
|
||||
|
||||
if (error != 0) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||
"Error adding metadata \"%s\" to "
|
||||
"lasso server objects: %s.",
|
||||
idp_metadata->file, lasso_strerror(error));
|
||||
}
|
||||
}
|
||||
|
||||
return g_hash_table_size(cfg->server->providers);
|
||||
}
|
||||
|
||||
|
||||
static LassoServer *am_get_lasso_server(request_rec *r)
|
||||
{
|
||||
am_dir_cfg_rec *cfg = am_get_dir_cfg(r);
|
||||
|
|
|
@ -46,6 +46,8 @@ PKG_CHECK_MODULES(LASSO, lasso)
|
|||
saved_LIBS=$LIBS; LIBS="$LIBS $LASSO_LIBS";
|
||||
AC_CHECK_LIB(lasso, lasso_server_new_from_buffers,
|
||||
LASSO_CFLAGS="$LASSO_CFLAGS -DHAVE_lasso_server_new_from_buffers")
|
||||
AC_CHECK_LIB(lasso, lasso_server_load_metadata,
|
||||
LASSO_CFLAGS="$LASSO_CFLAGS -DHAVE_lasso_server_load_metadata")
|
||||
LIBS=$saved_LIBS;
|
||||
AC_SUBST(LASSO_CFLAGS)
|
||||
AC_SUBST(LASSO_LIBS)
|
||||
|
|
Loading…
Reference in New Issue