[core] make lasso_server_load_metadata load any metadata file

The new code can load metadata file with a EntityDescriptor root node,
and with nested EntitiesDescriptor.

Idea and prototype by Olav Morken.
This commit is contained in:
Benjamin Dauvergne 2011-04-04 11:50:45 +02:00
parent 31a623aeee
commit cad3d305a9
5 changed files with 112 additions and 38 deletions

View File

@ -301,6 +301,8 @@ lasso_strerror(int error_code)
return "Failed to add new provider (protocol mismatch). It means that you tried to add a provider supporting a protocol imcompatible with the protocol declared for your #LassoServer, for example metadata for ID-FF 1.2 with metadata for SAML 2.0.";
case LASSO_SERVER_ERROR_INVALID_XML:
return "Parsed XML is invalid.";
case LASSO_SERVER_ERROR_NO_PROVIDER_LOADED:
return "When loading a metadata file it indicates that no provider could be loaded. It could be because the file is not well formed, or because there is no provider for the role sought.";
case LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND:
return "The identifier of a provider is unknown to #LassoServer. To register a provider in a #LassoServer object, you must use the methods lasso_server_add_provider() or lasso_server_add_provider_from_buffer().";
case LASSO_SERVER_ERROR_SET_ENCRYPTION_PRIVATE_KEY_FAILED:

View File

@ -263,6 +263,15 @@ LASSO_EXPORT const char* lasso_strerror(int error_code);
* Parsed XML is invalid.
*/
#define LASSO_SERVER_ERROR_INVALID_XML -205
/**
* LASSO_SERVER_ERROR_NO_PROVIDER_LOADED
*
* When loading a metadata file it indicates that no provider could be loaded.
* It could be because the file is not well formed, or because there is no provider for the
* role sought.
*
*/
#define LASSO_SERVER_ERROR_NO_PROVIDER_LOADED 206
/* Single Logout */
/**

View File

@ -803,7 +803,8 @@ lasso_server_load_metadata(LassoServer *server, LassoProviderRole role, const gc
EMPTY_URI, &uri_references));
}
if (lasso_strisequal((char*)root->ns->href, LASSO_SAML2_METADATA_HREF)) {
lasso_check_good_rc(lasso_saml20_server_load_federation(server, role, root, blacklisted_entity_ids, loaded_entity_ids));
lasso_check_good_rc(lasso_saml20_server_load_metadata(server, role, root,
blacklisted_entity_ids, loaded_entity_ids));
} else {
goto_cleanup_with_rc(LASSO_ERROR_UNIMPLEMENTED);
}

View File

@ -102,51 +102,113 @@ _lasso_test_idp_descriptor(xmlNode *node) {
BAD_CAST LASSO_SAML2_METADATA_HREF) != NULL;
}
lasso_error_t
lasso_saml20_server_load_federation(LassoServer *server, LassoProviderRole role, xmlNode *root_node, GList *blacklisted_entity_ids, GList **loaded_entity_ids)
static lasso_error_t
lasso_saml20_server_load_metadata_entity(LassoServer *server, LassoProviderRole role,
xmlNode *entity, GList *blacklisted_entity_ids, GList **loaded_end)
{
LassoProvider *provider = NULL;
if (role == LASSO_PROVIDER_ROLE_IDP && ! _lasso_test_idp_descriptor(entity)) {
return 0;
}
if (role == LASSO_PROVIDER_ROLE_SP && ! _lasso_test_sp_descriptor(entity)) {
return 0;
}
provider = lasso_provider_new_from_xmlnode(role, entity);
if (provider) {
char *name = g_strdup(provider->ProviderID);
if (g_list_find_custom(blacklisted_entity_ids, name,
(GCompareFunc) g_strcmp0)) {
lasso_release_gobject(provider);
return LASSO_SERVER_ERROR_NO_PROVIDER_LOADED;
}
if (*loaded_end) {
GList *l = *loaded_end;
l->next = g_new0(GList, 1);
l->next->data = g_strdup(name);
*loaded_end = l->next;
}
g_hash_table_insert(server->providers, name, provider);
return 0;
} else {
return LASSO_SERVER_ERROR_NO_PROVIDER_LOADED;
}
}
static lasso_error_t lasso_saml20_server_load_metadata_child(LassoServer *server,
LassoProviderRole role, xmlNode *child, GList *blacklisted_entity_ids,
GList **loaded_end);
static lasso_error_t
lasso_saml20_server_load_metadata_entities(LassoServer *server, LassoProviderRole role, xmlNode *entities,
GList *blacklisted_entity_ids, GList **loaded_end)
{
xmlNode *child;
lasso_error_t rc = 0;
GList loaded = { .data = NULL, .next = NULL };
GList *loaded_end = &loaded;
gboolean at_least_one = FALSE;
child = xmlSecGetNextElementNode(root_node->children);
/* first parse the providers... */
child = xmlSecGetNextElementNode(entities->children);
while (child) {
LassoProvider *provider = NULL;
lasso_error_t rc = 0;
if (! xmlSecCheckNodeName(child,
BAD_CAST LASSO_SAML2_METADATA_ELEMENT_ENTITY_DESCRIPTOR,
BAD_CAST LASSO_SAML2_METADATA_HREF)) {
goto next;
rc = lasso_saml20_server_load_metadata_child(server, role, child,
blacklisted_entity_ids, loaded_end);
if (rc == 0) {
at_least_one = TRUE;
}
if (role == LASSO_PROVIDER_ROLE_IDP && ! _lasso_test_idp_descriptor(child)) {
goto next;
}
if (role == LASSO_PROVIDER_ROLE_SP && ! _lasso_test_sp_descriptor(child)) {
goto next;
}
provider = lasso_provider_new_from_xmlnode(role, child);
if (provider) {
char *name = g_strdup(provider->ProviderID);
if (g_list_find_custom(blacklisted_entity_ids, name,
(GCompareFunc) g_strcmp0)) {
lasso_release_gobject(provider);
goto next;
}
if (loaded_entity_ids) {
loaded_end->next = g_new0(GList, 1);
loaded_end->next->data = g_strdup(name);
loaded_end = loaded_end->next;
}
g_hash_table_insert(server->providers, name, provider);
}
next:
child = xmlSecGetNextElementNode(child->next);
}
return at_least_one ? 0 : LASSO_SERVER_ERROR_NO_PROVIDER_LOADED;
}
static lasso_error_t
lasso_saml20_server_load_metadata_child(LassoServer *server, LassoProviderRole role, xmlNode *child,
GList *blacklisted_entity_ids, GList **loaded_end)
{
if (xmlSecCheckNodeName(child,
BAD_CAST LASSO_SAML2_METADATA_ELEMENT_ENTITY_DESCRIPTOR,
BAD_CAST LASSO_SAML2_METADATA_HREF)) {
return lasso_saml20_server_load_metadata_entity(server, role, child,
blacklisted_entity_ids, loaded_end);
} else if (xmlSecCheckNodeName(child,
BAD_CAST LASSO_SAML2_METADATA_ELEMENT_ENTITIES_DESCRIPTOR,
BAD_CAST LASSO_SAML2_METADATA_HREF)) {
return lasso_saml20_server_load_metadata_entities(server, role, child,
blacklisted_entity_ids, loaded_end);
}
return LASSO_SERVER_ERROR_INVALID_XML;
}
/**
* lasso_saml20_server_load_metadata:
* @server: a #LassoServer object
* @role: the role of providers to load
* @root_node: the root node a SAML 2.0 metadata file
* @blacklisted_entity_ids: a list of entity IDs of provider to skip
* @loaded_entity_ids: an out parameter to return the list of the loaded providers entity IDs
*
* Load the SAML 2.0 providers present in the given metadata as pointed to by the @root_node
* parameter. If at least one provider is loaded the call is deemed successful.
*
* Return value: 0 if at least one provider has been loaded, LASSO_SERVER_ERROR_NO_PROVIDER_LOADED
* otherwise.
*/
lasso_error_t
lasso_saml20_server_load_metadata(LassoServer *server, LassoProviderRole role, xmlNode *root_node,
GList *blacklisted_entity_ids, GList **loaded_entity_ids)
{
lasso_error_t rc = 0;
GList loaded = { .data = NULL, .next = NULL };
GList *loaded_end = NULL;
if (loaded_entity_ids) {
loaded_end = &loaded;
}
rc = lasso_saml20_server_load_metadata_child(server, role,
root_node, blacklisted_entity_ids, &loaded_end);
if (loaded_entity_ids) {
lasso_release_list_of_strings(*loaded_entity_ids);
*loaded_entity_ids = loaded.next;
}
return rc;

View File

@ -33,7 +33,7 @@ extern "C" {
#include "../id-ff/server.h"
int lasso_saml20_server_load_affiliation(LassoServer *server, xmlNode *node);
lasso_error_t lasso_saml20_server_load_federation(LassoServer *server, LassoProviderRole role,
lasso_error_t lasso_saml20_server_load_metadata(LassoServer *server, LassoProviderRole role,
xmlNode *root_node, GList *blacklisted_entity_ids, GList **loaded_entity_ids);
#ifdef __cplusplus