SAML 2.0&ID-FF 1.2: simplify and complete metadata loading for multi-role support

This commit is contained in:
Benjamin Dauvergne 2010-03-27 16:52:04 +00:00
parent 16d4b4df24
commit c07cd3898c
16 changed files with 1011 additions and 547 deletions

View File

@ -149,6 +149,13 @@ LassoEncryptionSymKeyType
lasso_provider_verify_single_node_signature
lasso_provider_get_default_name_id_format
lasso_provider_get_sp_name_qualifier
lasso_provider_get_idp_supported_attributes
lasso_provider_get_valid_until
lasso_provider_get_cache_duration
lasso_provider_get_metadata_one_for_role
lasso_provider_get_metadata_list_for_role
lasso_provider_get_metadata_keys_for_role
lasso_provider_get_roles
<SUBSECTION Standard>
LASSO_PROVIDER
LASSO_IS_PROVIDER

View File

@ -203,7 +203,8 @@ LASSO_EXPORT gint lasso_profile_set_soap_fault_response(LassoProfile *profile, c
LASSO_EXPORT void lasso_profile_set_signature_verify_hint(LassoProfile *profile,
LassoProfileSignatureVerifyHint signature_verify_hint);
LASSO_EXPORT LassoProfileSignatureVerifyHint lasso_profile_get_signature_verify_hint(LassoProfile *profile);
LASSO_EXPORT LassoProviderRole lasso_profile_sso_role_with(LassoProfile *profile, const char *remote_provider_id);
LASSO_EXPORT LassoProviderRole lasso_profile_sso_role_with(LassoProfile *profile,
const char *remote_provider_id);
#ifdef __cplusplus
}

View File

@ -26,7 +26,27 @@
* SECTION:provider
* @short_description: Service or identity provider
*
* It holds all the data about a provider.
* <para>The #LassoProvider object holds metadata about a provider. Metadata are sorted into descriptors,
* each descriptor being assigned a role. We refer you to <CiteTitle>Liberty Metadata Description
* and Discovery
Specification </CiteTitle> and <CiteTitle>Metadata for the OASIS Security Assertion Markup Language
(SAML) V2.0</CiteTitle>.</para>
<para>Roles are represented by the enumeration #LassoProviderRole, you can access descriptors
content using lasso_provider_get_metadata_list_by_role() and lasso_provider_get_metadata_by_role().
Descriptors resources are flattened inside a simple hashtable. For example to get the URL(s) for the
SAML 2.0 single logout response endpoint using binding HTTP-POST of the SP descriptor of a provider
called x, you would call:</para>
<programlisting>
GList *urls = lasso_provider_get_metadata_list_by_role(x, LASSO_PROVIDER_ROLE_SP, "SingleLogoutService HTTP-POST ResponseLocation");
</programlisting>
<para>A provider usually possess a default role stored in the #LassoProvider.role field, which is
initialized by the lasso_server_add_provider() method when registering a new remote provider to our
current provider. The methods lasso_provider_get_metadata() and lasso_provider_get_metadata_list()
use this default role to access descriptors.</para>
**/
#include "../xml/private.h"
@ -62,14 +82,19 @@ static char *protocol_md_nodename[LASSO_MD_PROTOCOL_TYPE_LAST] = {
"SingleSignOnProtocolProfile"
};
static char *protocol_roles[LASSO_PROVIDER_ROLE_LAST] = {
NULL, "sp", "idp",
NULL, "idp", "sp",
"authn-authority", "pdp", "attribute-authority"
};
char *protocol_methods[LASSO_HTTP_METHOD_LAST] = {
"", "", "", "",
"", "-http", "-soap"
};
static gboolean lasso_provider_load_metadata_from_doc(LassoProvider *provider, xmlDoc *doc);
static gboolean _lasso_provider_load_metadata_from_doc(LassoProvider *provider, xmlDoc *doc);
static int _lasso_provider_get_role_index(LassoProviderRole role);
void _lasso_provider_add_metadata_value_for_role(LassoProvider *provider,
LassoProviderRole role, const char *name, const char *value);
typedef int LassoProviderRoleIndex;
/*****************************************************************************/
/* public methods */
@ -87,28 +112,115 @@ static gboolean lasso_provider_load_metadata_from_doc(LassoProvider *provider, x
* string must be freed by the caller.
**/
gchar*
lasso_provider_get_assertion_consumer_service_url(const LassoProvider *provider, const char *service_id)
lasso_provider_get_assertion_consumer_service_url(LassoProvider *provider, const char *service_id)
{
char *name = NULL;
char *assertion_consumer_service_url = NULL;
if (service_id == NULL)
service_id = provider->private_data->default_assertion_consumer;
name = g_strdup_printf("AssertionConsumerServiceURL %s", service_id);
assertion_consumer_service_url = lasso_provider_get_metadata_one_for_role(provider, LASSO_PROVIDER_ROLE_SP, name);
g_free(name);
return assertion_consumer_service_url;
}
static LassoProviderRoleIndex
_lasso_provider_get_role_index(LassoProviderRole role) {
switch (role) {
case LASSO_PROVIDER_ROLE_IDP:
return 1;
case LASSO_PROVIDER_ROLE_SP:
return 2;
case LASSO_PROVIDER_ROLE_AUTHN_AUTHORITY:
return 3;
case LASSO_PROVIDER_ROLE_AUTHZ_AUTHORITY:
return 4;
case LASSO_PROVIDER_ROLE_ATTRIBUTE_AUTHORITY:
return 5;
default:
return 0;
}
}
void
_lasso_provider_add_metadata_value_for_role(LassoProvider *provider, LassoProviderRole role, const char *name, const char *value)
{
GHashTable *descriptor;
GList *l;
char *sid = (char*)service_id;
char *name;
GHashTable *descriptor;
char *symbol;
LassoProviderRoleIndex role_index;
g_return_val_if_fail(LASSO_IS_PROVIDER(provider), NULL);
if (sid == NULL)
sid = provider->private_data->default_assertion_consumer;
g_return_if_fail(LASSO_IS_PROVIDER(provider) && name && value);
role_index = _lasso_provider_get_role_index(role);
g_return_if_fail ( role_index);
descriptor = provider->private_data->Descriptors; /* default to SP */
g_return_if_fail (descriptor);
l = (GList*)lasso_provider_get_metadata_list_for_role(provider, role, name);
lasso_list_add_string(l, value);
symbol = g_strdup_printf("%s %s", protocol_roles[role_index], name);
g_hash_table_insert(descriptor, symbol, l);
}
descriptor = provider->private_data->Descriptors;
/**
* lasso_provider_get_metadata_list_for_role:
* @provider: a #LassoProvider
* @role: a #LassoProviderRole value
* @name: the element name
*
* Extracts zero to many elements from the @provider descriptor for the given @role.
*
* Return value:(transfer none)(element-type string): a #GList with the elements. This GList is internally
* allocated and points to internally allocated strings. It must
* not be freed, modified or stored.
**/
GList*
lasso_provider_get_metadata_list_for_role(const LassoProvider *provider, LassoProviderRole role, const char *name)
{
GList *l;
GHashTable *descriptor;
char *symbol;
LassoProviderRoleIndex role_index;
g_return_val_if_fail(LASSO_IS_PROVIDER(provider) && name, NULL);
role_index = _lasso_provider_get_role_index(role);
if (! role_index)
return NULL;
descriptor = provider->private_data->Descriptors; /* default to SP */
if (descriptor == NULL)
return NULL;
name = g_strdup_printf("AssertionConsumerServiceURL %s", sid);
l = g_hash_table_lookup(descriptor, name);
g_free(name);
if (l == NULL)
return NULL;
symbol = g_strdup_printf("%s %s", protocol_roles[role_index], name);
l = g_hash_table_lookup(descriptor, symbol);
g_free(symbol);
return g_strdup(l->data);
return l;
}
/**
* lasso_provider_get_metadata_one_for_role:
* @provider: a #LassoProvider object
* @role: a #LassoProviderRole value
* @name: a metadata information name
*
* Return the given information extracted from the metadata of the given #LassoProvider for the
* given @role descriptor.
*
* Retun value: a newly allocated string or NULL. If non-NULL must be freed by the caller.
*/
char*
lasso_provider_get_metadata_one_for_role(LassoProvider *provider, LassoProviderRole role, const char *name)
{
const GList *l;
l = lasso_provider_get_metadata_list_for_role(provider, role, name);
if (l)
return g_strdup(l->data);
return NULL;
}
/**
@ -122,24 +234,11 @@ lasso_provider_get_assertion_consumer_service_url(const LassoProvider *provider,
* string must be freed by the caller.
**/
gchar*
lasso_provider_get_metadata_one(const LassoProvider *provider, const char *name)
lasso_provider_get_metadata_one(LassoProvider *provider, const char *name)
{
GList *l;
GHashTable *descriptor;
g_return_val_if_fail(LASSO_IS_PROVIDER(provider), NULL);
descriptor = provider->private_data->Descriptors; /* default to SP */
if (descriptor == NULL)
return NULL;
l = g_hash_table_lookup(descriptor, name);
if (l)
return g_strdup(l->data);
return NULL;
return lasso_provider_get_metadata_one_for_role(provider, provider->role, name);
}
/**
* lasso_provider_get_metadata_list:
* @provider: a #LassoProvider
@ -151,18 +250,12 @@ lasso_provider_get_metadata_one(const LassoProvider *provider, const char *name)
* allocated and points to internally allocated strings. It must
* not be freed, modified or stored.
**/
const GList*
lasso_provider_get_metadata_list(const LassoProvider *provider, const char *name)
GList*
lasso_provider_get_metadata_list(LassoProvider *provider, const char *name)
{
GHashTable *descriptor;
g_return_val_if_fail(LASSO_IS_PROVIDER(provider), NULL);
descriptor = provider->private_data->Descriptors;
return g_hash_table_lookup(descriptor, name);
return lasso_provider_get_metadata_list_for_role(provider, provider->role, name);
}
/**
* lasso_provider_get_first_http_method:
* @provider: (transfer none): a #LassoProvider
@ -176,7 +269,7 @@ lasso_provider_get_metadata_list(const LassoProvider *provider, const char *name
**/
LassoHttpMethod
lasso_provider_get_first_http_method(LassoProvider *provider,
const LassoProvider *remote_provider, const LassoMdProtocolType protocol_type)
LassoProvider *remote_provider, LassoMdProtocolType protocol_type)
{
char *protocol_profile_prefix;
const GList *local_supported_profiles;
@ -245,7 +338,7 @@ lasso_provider_get_first_http_method(LassoProvider *provider,
* Return value: %TRUE if it is appropriate
**/
gboolean
lasso_provider_accept_http_method(LassoProvider *provider, const LassoProvider *remote_provider,
lasso_provider_accept_http_method(LassoProvider *provider, LassoProvider *remote_provider,
LassoMdProtocolType protocol_type, LassoHttpMethod http_method,
gboolean initiate_profile)
{
@ -302,7 +395,7 @@ lasso_provider_accept_http_method(LassoProvider *provider, const LassoProvider *
* Return value: %TRUE if it is supported
**/
gboolean
lasso_provider_has_protocol_profile(const LassoProvider *provider,
lasso_provider_has_protocol_profile(LassoProvider *provider,
LassoMdProtocolType protocol_type, const char *protocol_profile)
{
const GList *supported;
@ -339,7 +432,6 @@ lasso_provider_get_base64_succinct_id(const LassoProvider *provider)
return ret;
}
/**
* lasso_provider_get_organization
* @provider: a #LassoProvider
@ -375,6 +467,14 @@ static struct XmlSnippet schema_snippets[] = {
static LassoNodeClass *parent_class = NULL;
/**
* lasso_provider_get_public_key:
* @provider: a #LassoProvider object
*
* Return the public key associated with this provider.
*
* Return value: an #xmlSecKey object.
*/
xmlSecKey*
lasso_provider_get_public_key(const LassoProvider *provider)
{
@ -403,56 +503,47 @@ lasso_provider_get_encryption_public_key(const LassoProvider *provider)
}
static void
load_descriptor(xmlNode *xmlnode, GHashTable *descriptor, LassoProvider *provider)
_lasso_provider_load_endpoint_type(LassoProvider *provider, xmlNode *endpoint,
LassoProviderRole role)
{
char *name = (char*)endpoint->name;
xmlChar *value = NULL;
if (strcmp(name, "AssertionConsumerServiceURL") == 0) {
char *isDefault = (char*)xmlGetProp(endpoint, (xmlChar*)"isDefault");
char *id = (char*)xmlGetProp(endpoint, (xmlChar*)"id");
name = g_strdup_printf("%s %s", name, id);
if (isDefault) {
if (strcmp(isDefault, "true") == 0 || strcmp(isDefault, "1") == 0)
lasso_assign_string(provider->private_data->default_assertion_consumer,
id);
xmlFree(isDefault);
}
xmlFree(id);
} else {
name = g_strdup_printf("%s", (char*)name);
}
value = xmlNodeGetContent(endpoint);
_lasso_provider_add_metadata_value_for_role(provider, role, name, (char*)value);
lasso_release_string(name);
xmlFree(value);
}
static void
_lasso_provider_load_descriptor(LassoProvider *provider, xmlNode *xmlnode, LassoProviderRole role)
{
xmlNode *t;
GList *elements;
char *name;
xmlChar *value;
xmlChar *use;
t = xmlnode->children;
t = xmlSecGetNextElementNode(xmlnode->children);
while (t) {
if (t->type != XML_ELEMENT_NODE) {
t = t->next;
continue;
}
if (strcmp((char*)t->name, "KeyDescriptor") == 0) {
use = xmlGetProp(t, (xmlChar*)"use");
if (use == NULL || strcmp((char*)use, "signing") == 0) {
provider->private_data->signing_key_descriptor = xmlCopyNode(t, 1);
}
if (use == NULL || strcmp((char*)use, "encryption") == 0) {
provider->private_data->encryption_key_descriptor =
xmlCopyNode(t, 1);
}
if (use) {
xmlFree(use);
}
t = t->next;
continue;
}
if (strcmp((char*)t->name, "AssertionConsumerServiceURL") == 0) {
char *isDefault = (char*)xmlGetProp(t, (xmlChar*)"isDefault");
char *id = (char*)xmlGetProp(t, (xmlChar*)"id");
name = g_strdup_printf("%s %s", t->name, id);
if (isDefault) {
if (strcmp(isDefault, "true") == 0 || strcmp(isDefault, "1") == 0)
lasso_assign_string(provider->private_data->default_assertion_consumer,
id);
xmlFree(isDefault);
}
xmlFree(id);
if (xmlSecCheckNodeName(t,
BAD_CAST "KeyDescriptor",
BAD_CAST LASSO_METADATA_HREF)) {
_lasso_provider_load_key_descriptor(provider, t);
} else {
name = g_strdup((char*)t->name);
_lasso_provider_load_endpoint_type(provider, t, role);
}
elements = g_hash_table_lookup(descriptor, name);
value = xmlNodeGetContent(t);
elements = g_list_append(elements, g_strdup((char*)value));
// Do not mix g_free strings with xmlFree strings
xmlFree(value);
g_hash_table_insert(descriptor, name, elements);
t = t->next;
t = xmlSecGetNextElementNode(t->next);
}
}
@ -461,8 +552,20 @@ get_xmlNode(LassoNode *node, gboolean lasso_dump)
{
xmlNode *xmlnode;
LassoProvider *provider = LASSO_PROVIDER(node);
char *roles[LASSO_PROVIDER_ROLE_LAST] = { "None", "SP", "IdP", "AuthnAuthority", "PDP", "AttributeAuthority"};
char *encryption_mode[] = { "None", "NameId", "Assertion", "Both" };
char *roles[LASSO_PROVIDER_ROLE_LAST] = {
"None",
"SP",
"IdP",
"AuthnAuthority",
"PDP",
"AttributeAuthority"
};
char *encryption_mode[] = {
"None",
"NameId",
"Assertion",
"Both"
};
xmlnode = parent_class->get_xmlNode(node, lasso_dump);
@ -479,12 +582,39 @@ get_xmlNode(LassoNode *node, gboolean lasso_dump)
return xmlnode;
}
void
_lasso_provider_load_key_descriptor(LassoProvider *provider, xmlNode *key_descriptor)
{
LassoProviderPrivate *private_data;
xmlChar *use;
g_return_if_fail(LASSO_IS_PROVIDER(provider));
g_return_if_fail(provider->private_data);
private_data = provider->private_data;
use = xmlGetProp(key_descriptor, (xmlChar*)"use");
if (use == NULL || g_strcmp0((char*)use, "signing") == 0) {
lasso_assign_xml_node(private_data->signing_key_descriptor, key_descriptor);
}
if (use == NULL || strcmp((char*)use, "encryption") == 0) {
lasso_assign_xml_node(private_data->encryption_key_descriptor, key_descriptor);
}
lasso_release_xml_string(use);
}
static int
init_from_xml(LassoNode *node, xmlNode *xmlnode)
{
LassoProvider *provider = LASSO_PROVIDER(node);
char *roles[LASSO_PROVIDER_ROLE_LAST] = { "None", "SP", "IdP", "AuthnAuthority", "PDP", "AttributeAuthority"};
static char * const roles[LASSO_PROVIDER_ROLE_LAST] = {
"None",
"SP",
"IdP",
"AuthnAuthority",
"PDP",
"AttributeAuthority"
};
xmlChar *s;
int i;
@ -497,16 +627,16 @@ init_from_xml(LassoNode *node, xmlNode *xmlnode)
/* Load provider role */
s = xmlGetProp(xmlnode, (xmlChar*)"ProviderRole");
provider->role = LASSO_PROVIDER_ROLE_NONE;
i = LASSO_PROVIDER_ROLE_NONE;
while (i < LASSO_PROVIDER_ROLE_LAST) {
if (strcmp((char*)s, roles[i]) == 0) {
provider->role = i;
break;
if (s) {
i = LASSO_PROVIDER_ROLE_NONE;
while (i < LASSO_PROVIDER_ROLE_LAST) {
if (strcmp((char*)s, roles[i]) == 0) {
provider->role = i;
break;
}
i++;
}
i++;
}
if (s != NULL) {
xmlFree(s);
lasso_release_xml_string(s);
}
/* Load encryption mode */
@ -540,6 +670,67 @@ init_from_xml(LassoNode *node, xmlNode *xmlnode)
return 0;
}
static void*
_lasso_provider_get_pdata_thing(LassoProvider *provider, ptrdiff_t offset)
{
LassoProviderPrivate *pdata;
lasso_return_val_if_fail(LASSO_IS_PROVIDER(provider), NULL);
pdata = provider->private_data;
if (pdata)
return G_STRUCT_MEMBER_P(pdata, offset);
return NULL;
}
/**
* lasso_provider_get_idp_supported_attributes:
* @provider: a #LassoProvider object
*
* If the provider supports the IDP SSO role, then return the list of Attribute definition that this
* provider declared supporting.
*
* Return value:(transfer none)(element-type LassoNode): a list of #LassoSaml2Attribute or #LassoSamlAttribute
*/
GList*
lasso_provider_get_idp_supported_attributes(LassoProvider *provider)
{
return _lasso_provider_get_pdata_thing(provider, G_STRUCT_OFFSET(LassoProviderPrivate,
attributes));
}
/**
* lasso_provider_get_valid_until:
* @provider: a #LassoProvider object
*
* Return the time after which the metadata for this provider will become invalid. This is an
* ISO-8601 formatted string.
*
* Return value:(transfer none): an internally allocated string, you can copy it but not store it.
*/
char*
lasso_provider_get_valid_until(LassoProvider *provider)
{
return _lasso_provider_get_pdata_thing(provider,
G_STRUCT_OFFSET(LassoProviderPrivate, valid_until));
}
/**
* lasso_provider_get_cache_duration:
* @provider: a #LassoProvider object
*
* Return the time during which the metadata for this provider can be kept.
*
* Return value:(transfer none): an internally allocated string, you can copy it but not store it.
*/
char*
lasso_provider_get_cache_duration(LassoProvider *provider)
{
return _lasso_provider_get_pdata_thing(provider,
G_STRUCT_OFFSET(LassoProviderPrivate, cache_duration));
}
/*****************************************************************************/
/* overridden parent class methods */
/*****************************************************************************/
@ -727,7 +918,7 @@ _lasso_provider_load_metadata_from_buffer(LassoProvider *provider, const gchar *
if (doc == NULL) {
return FALSE;
}
goto_cleanup_if_fail_with_rc (lasso_provider_load_metadata_from_doc(provider, doc), FALSE);
goto_cleanup_if_fail_with_rc (_lasso_provider_load_metadata_from_doc(provider, doc), FALSE);
lasso_assign_string(provider->metadata_filename, metadata);
cleanup:
lasso_release_doc(doc);
@ -774,7 +965,7 @@ lasso_provider_load_metadata(LassoProvider *provider, const gchar *path)
}
static gboolean
lasso_provider_load_metadata_from_doc(LassoProvider *provider, xmlDoc *doc)
_lasso_provider_load_metadata_from_doc(LassoProvider *provider, xmlDoc *doc)
{
xmlXPathContext *xpathCtx;
xmlXPathObject *xpathObj;
@ -833,8 +1024,8 @@ lasso_provider_load_metadata_from_doc(LassoProvider *provider, xmlDoc *doc)
xpathObj = xmlXPathEvalExpression((xmlChar*)xpath_idp, xpathCtx);
if (xpathObj && xpathObj->nodesetval && xpathObj->nodesetval->nodeNr == 1) {
load_descriptor(xpathObj->nodesetval->nodeTab[0],
provider->private_data->Descriptors, provider);
_lasso_provider_load_descriptor(provider, xpathObj->nodesetval->nodeTab[0],
LASSO_PROVIDER_ROLE_IDP);
if (provider->private_data->conformance < LASSO_PROTOCOL_LIBERTY_1_2) {
/* lookup ProviderID */
node = xpathObj->nodesetval->nodeTab[0]->children;
@ -853,8 +1044,8 @@ lasso_provider_load_metadata_from_doc(LassoProvider *provider, xmlDoc *doc)
xpathObj = xmlXPathEvalExpression((xmlChar*)xpath_sp, xpathCtx);
if (xpathObj && xpathObj->nodesetval && xpathObj->nodesetval->nodeNr == 1) {
load_descriptor(xpathObj->nodesetval->nodeTab[0],
provider->private_data->Descriptors, provider);
_lasso_provider_load_descriptor(provider, xpathObj->nodesetval->nodeTab[0],
LASSO_PROVIDER_ROLE_SP);
if (provider->private_data->conformance < LASSO_PROTOCOL_LIBERTY_1_2) {
/* lookup ProviderID */
node = xpathObj->nodesetval->nodeTab[0]->children;
@ -890,8 +1081,9 @@ lasso_provider_load_metadata_from_doc(LassoProvider *provider, xmlDoc *doc)
* Help to factorize common code.
*/
static LassoProvider*
lasso_provider_new_helper(LassoProviderRole role, const char *metadata,
const char *public_key, const char *ca_cert_chain, gboolean (*loader)(LassoProvider *provider, const gchar *metadata))
_lasso_provider_new_helper(LassoProviderRole role, const char *metadata,
const char *public_key, const char *ca_cert_chain, gboolean (*loader)(
LassoProvider *provider, const gchar *metadata))
{
LassoProvider *provider;
@ -936,7 +1128,7 @@ LassoProvider*
lasso_provider_new(LassoProviderRole role, const char *metadata,
const char *public_key, const char *ca_cert_chain)
{
return lasso_provider_new_helper(role, metadata, public_key, ca_cert_chain,
return _lasso_provider_new_helper(role, metadata, public_key, ca_cert_chain,
lasso_provider_load_metadata);
}
@ -955,7 +1147,7 @@ LassoProvider*
lasso_provider_new_from_buffer(LassoProviderRole role, const char *metadata,
const char *public_key, const char *ca_cert_chain)
{
return lasso_provider_new_helper(role, metadata, public_key, ca_cert_chain,
return _lasso_provider_new_helper(role, metadata, public_key, ca_cert_chain,
lasso_provider_load_metadata_from_buffer);
}
@ -1321,7 +1513,7 @@ lasso_provider_verify_query_signature(LassoProvider *provider, const char *messa
* Return value:(transfer full)(allow-none): a NameIDFormat URI or NULL, the returned value must be freed by the caller.
*/
gchar*
lasso_provider_get_default_name_id_format(const LassoProvider *provider)
lasso_provider_get_default_name_id_format(LassoProvider *provider)
{
return lasso_provider_get_metadata_one(provider, "NameIDFormat");
}
@ -1384,3 +1576,84 @@ lasso_provider_verify_single_node_signature (LassoProvider *provider, LassoNode
}
return lasso_verify_signature(xmlnode, NULL, id_attr_name, NULL, xmlseckey, NO_SINGLE_REFERENCE, NULL);
}
struct AddForRoleHelper {
GList *l;
LassoProviderRole role;
};
static void
_add_for_role(gpointer key, G_GNUC_UNUSED gpointer data, struct AddForRoleHelper *helper)
{
char role_prefix[64];
int l;
l = sprintf(role_prefix, "%s ", protocol_roles[helper->role]);
if (key && strncmp(key, role_prefix, l) == 0) {
lasso_list_add_string(helper->l, ((char*)key) + l);
}
}
/**
* lasso_provider_get_metadata_keys_for_role:
* @provider: a #LassoProvider object
* @role: a #LassoProviderRole value
*
* Returns the list of metadata keys existing for the given provider.
*
* Return value:(element-type utf8)(transfer full): a newly allocated list of strings
*/
GList*
lasso_provider_get_metadata_keys_for_role(LassoProvider *provider, LassoProviderRole role)
{
struct AddForRoleHelper helper = { NULL, role };
lasso_return_val_if_fail(LASSO_IS_PROVIDER(provider), NULL);
lasso_return_val_if_fail(provider->private_data != NULL, NULL);
lasso_return_val_if_fail(role > LASSO_PROVIDER_ROLE_NONE && role < LASSO_PROVIDER_ROLE_LAST, NULL);
g_hash_table_foreach(provider->private_data->Descriptors, (GHFunc)_add_for_role, &helper);
return helper.l;
}
/**
* lasso_provider_get_roles:
* @provider: a #LassoProvider object
*
* Return the bitmask of the supported roles.
*
* Return value: a #LassoProviderRole enumeration value.
*/
LassoProviderRole
lasso_provider_get_roles(LassoProvider *provider)
{
lasso_return_val_if_fail(LASSO_IS_PROVIDER(provider) && provider->private_data, LASSO_PROVIDER_ROLE_NONE);
return provider->private_data->roles;
}
/**
* lasso_provider_match_conformance:
* @provider: a #LassoProvider object
* @another_provider: a #LassoProvider object
*
* Return whether the two provider support a same protocol.
* See also #LassoProtocolConformance.
*
* Return value: TRUE or FALSE.
*/
gboolean
lasso_provider_match_conformance(LassoProvider *provider, LassoProvider *another_provider)
{
lasso_return_val_if_fail(LASSO_IS_PROVIDER(provider)
&& LASSO_IS_PROVIDER(another_provider),
FALSE);
int conformance1 = lasso_provider_get_protocol_conformance(provider);
int conformance2 = lasso_provider_get_protocol_conformance(another_provider);
return (conformance1 & conformance2) != 0;
}

View File

@ -118,10 +118,12 @@ typedef enum {
* assertion providing authorization about a principal acessing a resource,
* @LASSO_PROVIDER_ROLE_ATTRIBUTE_AUTHORITY: an attribute authority, i.e. an endpoint able to return
* attributes aboute a principal,
* @LASSO_PROVIDER_ROLE_LAST: all value in the enumeration are garanteed to be < to
* @LASSO_PROVIDER_ROLE_LAST: all values in the enumeration are guaranteed to be < to
* @LASSO_PROVIDER_ROLE_LAST.
*
* #LassoProviderRole is an enumeration allowing to precise the roles handled by a provider.
* #LassoProviderRole is an enumeration allowing to enumerate the roles handled by a provider, it
* can be used in a bitmask as each value is a power of 2 (except #LASSO_PROVIDER_ROLE_ANY which is
* the full bitmask and LASSO_PROVIDER_ROLE_NONE).
**/
typedef enum {
LASSO_PROVIDER_ROLE_ANY = -1,
@ -169,6 +171,22 @@ typedef enum {
} LassoEncryptionMode;
/**
* LassoProvider:
* @ProviderID: the identifier URI of this provider
* @role: the role prescribed when this #LassoProvider was built
* @metadata_filename: file path or content of the metadata description for this provider.
* @public_key: file path or content of the public key file for this provider.
* @ca_cert_chain: file path or content of the CA cert chain used to validate signature of this
* provider (can be used instead of a public key to limit the need for metadata updates).
*
* <para>Any kind of provider, identity provider, service provider, attribute authority, authorization
* authority will be represented by a #LassoProvider object. This object will holds public keys,
* certificate chains and metadata informations. The ID-FF 1.2 and SAML 2.0 metadata files are
* flattened inside a key-value map that you can access using the functions
* lasso_provider_get_metadata_one_for_role(), lasso_provider_get_metadata_list_for_role(),
* lasso_provider_get_metadata_keys_for_role().</para>
*/
struct _LassoProvider {
LassoNode parent;
@ -193,21 +211,21 @@ LASSO_EXPORT LassoProvider* lasso_provider_new(LassoProviderRole role, const cha
const char *public_key, const char *ca_cert_chain);
LASSO_EXPORT LassoProvider* lasso_provider_new_from_buffer(LassoProviderRole role,
const char *metadata, const char *public_key, const char *ca_cert_chain);
LASSO_EXPORT gchar* lasso_provider_get_assertion_consumer_service_url(const LassoProvider *provider,
LASSO_EXPORT gchar* lasso_provider_get_assertion_consumer_service_url(LassoProvider *provider,
const char *service_id);
LASSO_EXPORT gchar* lasso_provider_get_metadata_one(const LassoProvider *provider, const char *name);
LASSO_EXPORT const GList* lasso_provider_get_metadata_list(const LassoProvider *provider, const char *name);
LASSO_EXPORT gchar* lasso_provider_get_metadata_one(LassoProvider *provider, const char *name);
LASSO_EXPORT GList* lasso_provider_get_metadata_list(LassoProvider *provider, const char *name);
LASSO_EXPORT LassoProvider* lasso_provider_new_from_dump(const gchar *dump);
LASSO_EXPORT LassoHttpMethod lasso_provider_get_first_http_method(LassoProvider *provider,
const LassoProvider *remote_provider, LassoMdProtocolType protocol_type);
LassoProvider *remote_provider, LassoMdProtocolType protocol_type);
LASSO_EXPORT gboolean lasso_provider_accept_http_method(LassoProvider *provider,
const LassoProvider *remote_provider, LassoMdProtocolType protocol_type,
LassoProvider *remote_provider, LassoMdProtocolType protocol_type,
LassoHttpMethod http_method, gboolean initiate_profile);
LASSO_EXPORT gboolean lasso_provider_has_protocol_profile(const LassoProvider *provider,
LASSO_EXPORT gboolean lasso_provider_has_protocol_profile(LassoProvider *provider,
LassoMdProtocolType protocol_type, const char *protocol_profile);
LASSO_EXPORT gchar* lasso_provider_get_base64_succinct_id(const LassoProvider *provider);
@ -225,13 +243,32 @@ LASSO_EXPORT LassoEncryptionMode lasso_provider_get_encryption_mode(LassoProvide
LASSO_EXPORT void lasso_provider_set_encryption_sym_key_type(LassoProvider *provider,
LassoEncryptionSymKeyType encryption_sym_key_type);
LASSO_EXPORT gchar* lasso_provider_get_default_name_id_format(const LassoProvider *provider);
LASSO_EXPORT gchar* lasso_provider_get_default_name_id_format(LassoProvider *provider);
LASSO_EXPORT const char* lasso_provider_get_sp_name_qualifier(LassoProvider *provider);
LASSO_EXPORT int lasso_provider_verify_single_node_signature (LassoProvider *provider,
LassoNode *node, const char *id_attr_name);
LASSO_EXPORT GList* lasso_provider_get_idp_supported_attributes(LassoProvider *provider);
LASSO_EXPORT char* lasso_provider_get_valid_until(LassoProvider *provider);
LASSO_EXPORT char* lasso_provider_get_cache_duration(LassoProvider *provider);
LASSO_EXPORT char* lasso_provider_get_metadata_one_for_role(LassoProvider *provider,
LassoProviderRole role, const char *name);
LASSO_EXPORT GList* lasso_provider_get_metadata_list_for_role(const LassoProvider *provider,
LassoProviderRole role, const char *name);
LASSO_EXPORT GList *lasso_provider_get_metadata_keys_for_role(LassoProvider *provider,
LassoProviderRole role);
LASSO_EXPORT LassoProviderRole lasso_provider_get_roles(LassoProvider *provider);
LASSO_EXPORT gboolean lasso_provider_match_conformance(LassoProvider *provider, LassoProvider *another_provider);
#ifdef __cplusplus
}
#endif /* __cplusplus */

View File

@ -46,6 +46,7 @@ struct _LassoProviderPrivate
{
gboolean dispose_has_run;
LassoProviderRole roles;
LassoProtocolConformance conformance;
GHashTable *Descriptors;
GList *attributes; /* of LassoSaml2Attribute */
@ -62,6 +63,8 @@ struct _LassoProviderPrivate
xmlSecKey *encryption_public_key;
LassoEncryptionMode encryption_mode;
LassoEncryptionSymKeyType encryption_sym_key_type;
char *valid_until;
char *cache_duration;
};
@ -76,6 +79,9 @@ xmlSecKey* lasso_provider_get_encryption_public_key(const LassoProvider *provide
LassoEncryptionSymKeyType lasso_provider_get_encryption_sym_key_type(const LassoProvider* provider);
int lasso_provider_verify_saml_signature(LassoProvider *provider, xmlNode *signed_node, xmlDoc *doc);
int lasso_provider_verify_query_signature(LassoProvider *provider, const char *message);
void _lasso_provider_load_key_descriptor(LassoProvider *provider, xmlNode *key_descriptor);
void _lasso_provider_add_metadata_value_for_role(LassoProvider *provider,
LassoProviderRole role, const char *name, const char *value);
#ifdef __cplusplus

View File

@ -24,9 +24,9 @@
#include "../id-ff/session.h"
#include "../xml/private.h"
#include "assertion_query.h"
#include "providerprivate.h"
#include "profileprivate.h"
#include "./assertion_query.h"
#include "./providerprivate.h"
#include "./profileprivate.h"
#include "../id-ff/providerprivate.h"
#include "../id-ff/profileprivate.h"
#include "../id-ff/identityprivate.h"
@ -47,6 +47,23 @@ struct _LassoAssertionQueryPrivate
LassoAssertionQueryRequestType query_request_type;
};
LassoMdProtocolType
_lasso_assertion_query_type_to_protocol_type(LassoAssertionQueryRequestType query_request_type) {
LassoMdProtocolType types[4] = {
LASSO_MD_PROTOCOL_TYPE_ASSERTION_ID_REQUEST,
LASSO_MD_PROTOCOL_TYPE_AUTHN_QUERY,
LASSO_MD_PROTOCOL_TYPE_ATTRIBUTE,
LASSO_MD_PROTOCOL_TYPE_AUTHZ, };
if (query_request_type < LASSO_ASSERTION_QUERY_REQUEST_TYPE_ASSERTION_ID &&
query_request_type > LASSO_ASSERTION_QUERY_REQUEST_TYPE_AUTHZ_DECISION) {
return -1;
}
return types[query_request_type - LASSO_ASSERTION_QUERY_REQUEST_TYPE_ASSERTION_ID];
}
/*****************************************************************************/
/* public methods */
@ -74,24 +91,16 @@ lasso_assertion_query_init_request(LassoAssertionQuery *assertion_query,
LassoAssertionQueryRequestType query_request_type)
{
LassoProfile *profile;
LassoProvider *remote_provider;
LassoFederation *federation;
LassoSamlp2RequestAbstract *request;
gint ret = 0;
LassoNode *request;
gint rc = 0;
g_return_val_if_fail(http_method == LASSO_HTTP_METHOD_ANY ||
http_method == LASSO_HTTP_METHOD_SOAP,
LASSO_PARAM_ERROR_INVALID_VALUE);
g_return_val_if_fail(LASSO_IS_ASSERTION_QUERY(assertion_query),
LASSO_PARAM_ERROR_INVALID_VALUE);
profile = LASSO_PROFILE(assertion_query);
/* verify the identity is set */
if (LASSO_IS_IDENTITY(profile->identity) == FALSE) {
return critical_error(LASSO_PROFILE_ERROR_IDENTITY_NOT_FOUND);
}
/* set the remote provider id */
profile->remote_providerID = NULL;
if (remote_provider_id) {
@ -106,7 +115,7 @@ lasso_assertion_query_init_request(LassoAssertionQuery *assertion_query,
role = LASSO_PROVIDER_ROLE_ATTRIBUTE_AUTHORITY;
break;
case LASSO_ASSERTION_QUERY_REQUEST_TYPE_AUTHZ_DECISION:
role = LASSO_PROVIDER_ROLE_PDP;
role = LASSO_PROVIDER_ROLE_AUTHZ_AUTHORITY;
break;
/* other request types should not happen or should not go there */
default:
@ -119,81 +128,40 @@ lasso_assertion_query_init_request(LassoAssertionQuery *assertion_query,
g_return_val_if_fail(profile->remote_providerID != NULL,
LASSO_PARAM_ERROR_INVALID_VALUE);
remote_provider = lasso_server_get_provider(profile->server, profile->remote_providerID);
if (LASSO_IS_PROVIDER(remote_provider) == FALSE) {
return critical_error(LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND);
}
assertion_query->private_data->query_request_type = query_request_type;
switch (query_request_type) {
case LASSO_ASSERTION_QUERY_REQUEST_TYPE_ASSERTION_ID:
profile->request = lasso_samlp2_assertion_id_request_new();
request = lasso_samlp2_assertion_id_request_new();
break;
case LASSO_ASSERTION_QUERY_REQUEST_TYPE_AUTHN:
profile->request = lasso_samlp2_authn_query_new();
request = lasso_samlp2_authn_query_new();
break;
case LASSO_ASSERTION_QUERY_REQUEST_TYPE_ATTRIBUTE:
profile->request = lasso_samlp2_attribute_query_new();
request = lasso_samlp2_attribute_query_new();
break;
case LASSO_ASSERTION_QUERY_REQUEST_TYPE_AUTHZ_DECISION:
profile->request = lasso_samlp2_authz_decision_query_new();
request = lasso_samlp2_authz_decision_query_new();
break;
default:
return critical_error(LASSO_PARAM_ERROR_INVALID_VALUE);
}
if (query_request_type != LASSO_ASSERTION_QUERY_REQUEST_TYPE_ASSERTION_ID) {
LassoSaml2NameID *nameID = NULL;
/* fill <Subject> */
LassoSamlp2SubjectQueryAbstract *subject_query;
/* Get federation */
if (profile->session) {
GList *assertions;
LassoSaml2Assertion *assertion = NULL;
assertions = lasso_session_get_assertions(profile->session,
(gchar*)profile->remote_providerID);
/* multiple assertions, take the first */
if (assertions && LASSO_IS_SAML2_ASSERTION(assertions->data)) {
assertion = (LassoSaml2Assertion*)assertions->data;
}
if (assertion && assertion->Subject) {
nameID = assertion->Subject->NameID;
}
}
if (nameID == NULL) {
federation = g_hash_table_lookup(profile->identity->federations,
profile->remote_providerID);
if (LASSO_IS_FEDERATION(federation) == FALSE) {
return critical_error(LASSO_PROFILE_ERROR_FEDERATION_NOT_FOUND);
} /* XXX: should support looking up transient id */
nameID = LASSO_SAML2_NAME_ID(lasso_profile_get_nameIdentifier(profile));
}
subject_query = LASSO_SAMLP2_SUBJECT_QUERY_ABSTRACT(profile->request);
subject_query->Subject = LASSO_SAML2_SUBJECT(lasso_saml2_subject_new());
subject_query->Subject->NameID = g_object_ref(nameID);
}
/* Setup usual request attributes */
request = LASSO_SAMLP2_REQUEST_ABSTRACT(profile->request);
request->ID = lasso_build_unique_id(32);
request->Version = g_strdup("2.0");
request->Issuer = LASSO_SAML2_NAME_ID(lasso_saml2_name_id_new_with_string(
LASSO_PROVIDER(profile->server)->ProviderID));
request->IssueInstant = lasso_get_current_time();
if (LASSO_IS_SAMLP2_SUBJECT_QUERY_ABSTRACT(request)) {
LassoSamlp2SubjectQueryAbstract *sqa;
request->sign_method = LASSO_SIGNATURE_METHOD_RSA_SHA1;
if (profile->server->certificate) {
request->sign_type = LASSO_SIGNATURE_TYPE_WITHX509;
} else {
request->sign_type = LASSO_SIGNATURE_TYPE_SIMPLE;
sqa = (LassoSamlp2SubjectQueryAbstract*)request;
sqa->Subject = (LassoSaml2Subject*)lasso_saml2_subject_new();
}
request->private_key_file = g_strdup(profile->server->private_key);
request->certificate_file = g_strdup(profile->server->certificate);
profile->http_request_method = http_method;
return ret;
lasso_check_good_rc(lasso_saml20_profile_init_request(profile,
profile->remote_providerID,
TRUE,
(LassoSamlp2RequestAbstract*)request,
http_method,
_lasso_assertion_query_type_to_protocol_type(query_request_type)));
cleanup:
lasso_release_gobject(request);
return rc;
}
@ -210,6 +178,7 @@ lasso_assertion_query_build_request_msg(LassoAssertionQuery *assertion_query)
{
LassoProfile *profile;
LassoProvider *remote_provider;
gint rc = 0;
g_return_val_if_fail(LASSO_IS_ASSERTION_QUERY(assertion_query),
LASSO_PARAM_ERROR_INVALID_VALUE);
@ -221,8 +190,31 @@ lasso_assertion_query_build_request_msg(LassoAssertionQuery *assertion_query)
if (LASSO_IS_PROVIDER(remote_provider) == FALSE) {
return critical_error(LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND);
}
/* fill and encrypt <Subject> if necessary */
if (LASSO_IS_SAMLP2_SUBJECT_QUERY_ABSTRACT(profile->request)) do {
LassoSaml2NameID *nameID = NULL;
LassoSamlp2SubjectQueryAbstract *subject_query;
subject_query = (LassoSamlp2SubjectQueryAbstract*)profile->request;
if (subject_query->Subject &&
(subject_query->Subject->NameID ||
subject_query->Subject->EncryptedID)) {
nameID = (LassoSaml2NameID*)lasso_profile_get_nameIdentifier(profile);
if (! LASSO_IS_SAML2_NAME_ID(nameID))
return LASSO_PROFILE_ERROR_MISSING_NAME_IDENTIFIER;
subject_query = LASSO_SAMLP2_SUBJECT_QUERY_ABSTRACT(profile->request);
subject_query->Subject->NameID = g_object_ref(nameID);
}
if (! subject_query->Subject)
return LASSO_PROFILE_ERROR_MISSING_SUBJECT;
lasso_check_good_rc(lasso_saml20_profile_setup_subject(profile, subject_query->Subject));
} while(FALSE);
if (profile->http_request_method == LASSO_HTTP_METHOD_SOAP) {
LassoAssertionQueryRequestType type;
const char *url;
/* XXX: support only SOAP */
static const gchar *servicepoints[LASSO_ASSERTION_QUERY_REQUEST_TYPE_LAST] = {
"AssertionIDRequestService SOAP",
@ -230,22 +222,31 @@ lasso_assertion_query_build_request_msg(LassoAssertionQuery *assertion_query)
"AuthzService SOAP",
"AttributeService SOAP"
};
static const LassoProviderRole roles[LASSO_ASSERTION_QUERY_REQUEST_TYPE_LAST] = {
LASSO_PROVIDER_ROLE_ANY,
LASSO_PROVIDER_ROLE_AUTHN_AUTHORITY,
LASSO_PROVIDER_ROLE_AUTHZ_AUTHORITY,
LASSO_PROVIDER_ROLE_ATTRIBUTE_AUTHORITY
};
type = assertion_query->private_data->query_request_type;
if (type <= LASSO_ASSERTION_QUERY_REQUEST_TYPE_ASSERTION_ID ||
if (type == LASSO_ASSERTION_QUERY_REQUEST_TYPE_ASSERTION_ID) {
return LASSO_ERROR_UNDEFINED;
}
if (type < LASSO_ASSERTION_QUERY_REQUEST_TYPE_ASSERTION_ID ||
type >= LASSO_ASSERTION_QUERY_REQUEST_TYPE_AUTHZ_DECISION) {
return LASSO_PARAM_ERROR_INVALID_VALUE;
}
profile->msg_url = lasso_provider_get_metadata_one(remote_provider,
servicepoints[type]);
lasso_saml20_profile_setup_request_signing(profile);
profile->msg_body = lasso_node_export_to_soap(profile->request);
return 0;
url = lasso_provider_get_metadata_one_for_role(remote_provider, roles[type], servicepoints[type]);
return lasso_saml20_profile_build_request_msg(&assertion_query->parent,
NULL,
LASSO_HTTP_METHOD_SOAP, url);
}
return critical_error(LASSO_PROFILE_ERROR_INVALID_HTTP_METHOD);
cleanup:
return rc;
}
/**
* lasso_assertion_query_process_request_msg:
* @assertion_query: a #LassoAssertionQuery
@ -302,63 +303,22 @@ lasso_assertion_query_validate_request(LassoAssertionQuery *assertion_query)
{
LassoProfile *profile;
LassoProvider *remote_provider;
LassoFederation *federation;
LassoSamlp2StatusResponse *response;
int rc;
g_return_val_if_fail(LASSO_IS_ASSERTION_QUERY(assertion_query),
LASSO_PARAM_ERROR_INVALID_VALUE);
profile = LASSO_PROFILE(assertion_query);
if (profile->remote_providerID) {
g_free(profile->remote_providerID);
}
response = (LassoSamlp2StatusResponse*) lasso_samlp2_response_new();
lasso_check_good_rc(lasso_saml20_profile_validate_request(profile,
FALSE,
response,
&remote_provider));
profile->remote_providerID = g_strdup(
LASSO_SAMLP2_REQUEST_ABSTRACT(profile->request)->Issuer->content);
/* get the provider */
remote_provider = lasso_server_get_provider(profile->server, profile->remote_providerID);
if (LASSO_IS_PROVIDER(remote_provider) == FALSE) {
return critical_error(LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND);
}
federation = g_hash_table_lookup(profile->identity->federations,
profile->remote_providerID);
if (LASSO_IS_FEDERATION(federation) == FALSE) {
return critical_error(LASSO_PROFILE_ERROR_FEDERATION_NOT_FOUND);
}
if (profile->response) {
lasso_node_destroy(profile->response);
}
profile->response = lasso_samlp2_response_new();
response = LASSO_SAMLP2_STATUS_RESPONSE(profile->response);
response->ID = lasso_build_unique_id(32);
response->Version = g_strdup("2.0");
response->Issuer = LASSO_SAML2_NAME_ID(lasso_saml2_name_id_new_with_string(
LASSO_PROVIDER(profile->server)->ProviderID));
response->IssueInstant = lasso_get_current_time();
response->InResponseTo = g_strdup(LASSO_SAMLP2_REQUEST_ABSTRACT(profile->request)->ID);
lasso_saml20_profile_set_response_status(profile, LASSO_SAML2_STATUS_CODE_SUCCESS, NULL);
response->sign_method = LASSO_SIGNATURE_METHOD_RSA_SHA1;
if (profile->server->certificate) {
response->sign_type = LASSO_SIGNATURE_TYPE_WITHX509;
} else {
response->sign_type = LASSO_SIGNATURE_TYPE_SIMPLE;
}
response->private_key_file = g_strdup(profile->server->private_key);
response->certificate_file = g_strdup(profile->server->certificate);
/* verify signature status */
if (profile->signature_status != 0) {
lasso_saml20_profile_set_response_status_requester(profile,
LASSO_LIB_STATUS_CODE_INVALID_SIGNATURE);
return profile->signature_status;
}
return 0;
cleanup:
lasso_release_gobject(response);
return rc;
}
@ -375,6 +335,7 @@ lasso_assertion_query_build_response_msg(LassoAssertionQuery *assertion_query)
{
LassoProfile *profile;
LassoSamlp2StatusResponse *response;
int rc;
g_return_val_if_fail(LASSO_IS_ASSERTION_QUERY(assertion_query),
LASSO_PARAM_ERROR_INVALID_VALUE);
@ -383,44 +344,23 @@ lasso_assertion_query_build_response_msg(LassoAssertionQuery *assertion_query)
if (profile->response == NULL) {
/* no response set here means request denied */
profile->response = lasso_samlp2_response_new();
response = LASSO_SAMLP2_STATUS_RESPONSE(profile->response);
response->ID = lasso_build_unique_id(32);
response->Version = g_strdup("2.0");
response->Issuer = LASSO_SAML2_NAME_ID(lasso_saml2_name_id_new_with_string(
LASSO_PROVIDER(profile->server)->ProviderID));
response->IssueInstant = lasso_get_current_time();
response->InResponseTo = g_strdup(
LASSO_SAMLP2_REQUEST_ABSTRACT(profile->request)->ID);
lasso_saml20_profile_set_response_status_responder(profile,
LASSO_SAML2_STATUS_CODE_REQUEST_DENIED);
response = (LassoSamlp2StatusResponse*) lasso_samlp2_response_new();
response->sign_method = LASSO_SIGNATURE_METHOD_RSA_SHA1;
if (profile->server->certificate) {
response->sign_type = LASSO_SIGNATURE_TYPE_WITHX509;
} else {
response->sign_type = LASSO_SIGNATURE_TYPE_SIMPLE;
}
response->private_key_file = g_strdup(profile->server->private_key);
response->certificate_file = g_strdup(profile->server->certificate);
lasso_check_good_rc(lasso_saml20_profile_init_response(
profile,
response,
LASSO_SAML2_STATUS_CODE_RESPONDER,
LASSO_SAML2_STATUS_CODE_REQUEST_DENIED));
return 0;
}
if (profile->remote_providerID == NULL || profile->response == NULL) {
/* no remote provider id set or no response set, this means
* this function got called before validate_request, probably
* because there were no identity or federation */
return critical_error(LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND);
}
/* build logout response message */
if (profile->http_request_method == LASSO_HTTP_METHOD_SOAP) {
profile->msg_url = NULL;
profile->msg_body = lasso_node_export_to_soap(profile->response);
return 0;
}
return LASSO_PROFILE_ERROR_MISSING_REQUEST;
rc = lasso_saml20_profile_build_response_msg(profile,
NULL,
profile->http_request_method,
NULL);
cleanup:
return rc;
}
@ -446,9 +386,10 @@ lasso_assertion_query_process_response_msg(
profile = &assertion_query->parent;
response = (LassoSamlp2StatusResponse*)lasso_samlp2_response_new();
rc = lasso_saml20_profile_process_any_response(profile, response, NULL, response_msg);
lasso_check_good_rc(lasso_saml20_profile_process_any_response(profile,
response, NULL, response_msg));
/* cleanup: */
cleanup:
lasso_release_gobject(response);
return rc;
}
@ -486,12 +427,6 @@ init_from_xml(LassoNode *node, xmlNode *xmlnode)
/* overridden parent class methods */
/*****************************************************************************/
static void
dispose(GObject *object)
{
G_OBJECT_CLASS(parent_class)->dispose(object);
}
static void
finalize(GObject *object)
{
@ -501,8 +436,6 @@ finalize(GObject *object)
G_OBJECT_CLASS(parent_class)->finalize(object);
}
/*****************************************************************************/
/* instance and class init functions */
/*****************************************************************************/
@ -525,12 +458,9 @@ class_init(LassoAssertionQueryClass *klass)
lasso_node_class_set_nodename(nclass, "AssertionQuery");
lasso_node_class_add_snippets(nclass, schema_snippets);
G_OBJECT_CLASS(klass)->dispose = dispose;
G_OBJECT_CLASS(klass)->finalize = finalize;
}
GType
lasso_assertion_query_get_type()
{
@ -571,8 +501,7 @@ lasso_assertion_query_new(LassoServer *server)
g_return_val_if_fail(LASSO_IS_SERVER(server), NULL);
assertion_query = g_object_new(LASSO_TYPE_ASSERTION_QUERY, NULL);
LASSO_PROFILE(assertion_query)->server = g_object_ref(server);
LASSO_PROFILE(assertion_query)->server = lasso_ref(server);
return assertion_query;
}
@ -585,5 +514,5 @@ lasso_assertion_query_new(LassoServer *server)
void
lasso_assertion_query_destroy(LassoAssertionQuery *assertion_query)
{
lasso_node_destroy(LASSO_NODE(assertion_query));
lasso_release_gobject(assertion_query);
}

View File

@ -340,6 +340,8 @@ lasso_saml20_profile_process_artifact_resolve(LassoProfile *profile, const char
LassoProvider *remote_provider;
int rc;
/* FIXME: parse only one time the message, reuse the parsed document for signature
* validation */
lasso_assign_new_gobject(profile->request, lasso_node_new_from_soap(msg));
if (profile->request == NULL) {
return critical_error(LASSO_PROFILE_ERROR_INVALID_MSG);
@ -644,7 +646,6 @@ cleanup:
return rc;
}
int
lasso_saml20_profile_process_soap_request(LassoProfile *profile,
const char *request_msg)
@ -1165,7 +1166,7 @@ lasso_saml20_profile_build_response_msg(LassoProfile *profile, char *service,
}
/* if not explicitely given, automatically determine an URI from the metadatas */
if (url == NULL && service) {
if (url == NULL && service && method != LASSO_HTTP_METHOD_SOAP) {
made_url = url = get_response_url(provider, service, http_method_to_binding(method));
}
@ -1484,6 +1485,29 @@ lasso_profile_saml20_setup_message_signature(LassoProfile *profile, LassoNode *r
return 0;
}
/**
* lasso_saml20_profile_setup_subject:
* @profile: a #LassoProfile object
* @subject: a #LassoSaml2Subject object
*
* Encrypt subject if necessary.
*/
int
lasso_saml20_profile_setup_subject(LassoProfile *profile,
LassoSaml2Subject *subject)
{
LassoProvider *remote_provider;
remote_provider = lasso_server_get_provider(profile->server, profile->remote_providerID);
g_return_val_if_fail (LASSO_IS_PROVIDER(remote_provider), LASSO_ERROR_CAST_FAILED);
if (! (lasso_provider_get_encryption_mode(remote_provider) & LASSO_ENCRYPTION_MODE_NAMEID)) {
return 0;
}
return lasso_saml20_profile_setup_encrypted_node(remote_provider,
(LassoNode**)subject->NameID,
(LassoNode**)subject->EncryptedID);
}
gint
lasso_saml20_profile_setup_encrypted_node(LassoProvider *provider,
LassoNode **node_to_encrypt, LassoNode **node_destination)

View File

@ -34,6 +34,7 @@ extern "C" {
#include "../xml/saml-2.0/saml2_encrypted_element.h"
#include "../xml/saml-2.0/samlp2_status_response.h"
#include "../xml/saml-2.0/samlp2_request_abstract.h"
#include "../xml/saml-2.0/saml2_subject.h"
#include "../id-ff/provider.h"
int lasso_saml20_profile_init_request(LassoProfile *profile, const char *remote_provider_id,
@ -77,6 +78,7 @@ gint lasso_profile_saml20_setup_message_signature(LassoProfile *profile,
LassoNode *request_or_response);
gint lasso_saml20_profile_setup_encrypted_node(LassoProvider *provider,
LassoNode **node_to_encrypt, LassoNode **node_destination);
int lasso_saml20_profile_setup_subject(LassoProfile *profile, LassoSaml2Subject *subject);
#ifdef __cplusplus
}

View File

@ -22,14 +22,18 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define _POSIX_SOURCE
#include "../xml/private.h"
#include <xmlsec/base64.h>
#include <xmlsec/xmltree.h>
#include "providerprivate.h"
#include "../id-ff/providerprivate.h"
#include "../utils.h"
#include "./provider.h"
#include "../xml/saml-2.0/saml2_attribute.h"
#include "../xml/saml-2.0/saml2_xsd.h"
const char *profile_names[LASSO_MD_PROTOCOL_TYPE_LAST] = {
"", /* No fedterm in SAML 2.0 */
@ -50,122 +54,179 @@ const char *profile_names[LASSO_MD_PROTOCOL_TYPE_LAST] = {
static void add_assertion_consumer_url_to_list(gchar *key, G_GNUC_UNUSED gpointer value, GList **list);
static void
load_descriptor(xmlNode *xmlnode, GHashTable *descriptor, LassoProvider *provider)
static const char*
binding_uri_to_identifier(const char *uri)
{
char *descriptor_attrs[] = {"AuthnRequestsSigned", "WantAuthnRequestsSigned", NULL};
if (strcmp(uri, LASSO_SAML2_METADATA_BINDING_SOAP) == 0) {
return "SOAP";
} else if (strcmp(uri, LASSO_SAML2_METADATA_BINDING_REDIRECT) == 0) {
return "HTTP-Redirect";
} else if (strcmp(uri, LASSO_SAML2_METADATA_BINDING_POST) == 0) {
return "HTTP-POST";
} else if (strcmp(uri, LASSO_SAML2_METADATA_BINDING_ARTIFACT) == 0) {
return "HTTP-Artifact";
} else if (strcmp(uri, LASSO_SAML2_METADATA_BINDING_PAOS) == 0) {
return "PAOS";
} else if (strcmp(uri, LASSO_SAML2_METADATA_BINDING_URI) == 0) {
return "URI";
}
return NULL;
}
static gboolean
checkSaml2MdNode(xmlNode *t, char *name)
{
return xmlSecCheckNodeName(t,
BAD_CAST name,
BAD_CAST LASSO_SAML2_METADATA_HREF);
}
static xmlChar*
getSaml2MdProp(xmlNode *t, char *name) {
return xmlGetProp(t, BAD_CAST name);
}
static gboolean
hasSaml2MdProp(xmlNode *t, char *name) {
return xmlHasProp(t, BAD_CAST name) != NULL;
}
static gboolean
xsdIsTrue(xmlChar *value)
{
if (value && strcmp((char*)value, "true") == 0)
return TRUE;
return FALSE;
}
static void
load_endpoint_type(xmlNode *xmlnode, LassoProvider *provider, LassoProviderRole role)
{
xmlChar *binding = xmlGetProp(xmlnode, BAD_CAST "Binding");
char *name = NULL;
char *response_name = NULL;
LassoProviderPrivate *private_data = provider->private_data;
const char *binding_s = NULL;
xmlChar *value = NULL;
xmlChar *response_value = NULL;
binding_s = binding_uri_to_identifier((char*)binding);
if (! binding_s) {
message(G_LOG_LEVEL_CRITICAL, "XXX: unknown binding: %s", binding);
goto cleanup;
}
/* get endpoint location */
value = getSaml2MdProp(xmlnode, LASSO_SAML2_METADATA_ATTRIBUTE_LOCATION);
if (value == NULL) {
message(G_LOG_LEVEL_CRITICAL, "XXX: missing location for element %s", xmlnode->name);
goto cleanup;
}
/* special case of AssertionConsumerService */
if (checkSaml2MdNode(xmlnode, LASSO_SAML2_METADATA_ELEMENT_ASSERTION_CONSUMER_SERVICE)) {
xmlChar *index = getSaml2MdProp(xmlnode, LASSO_SAML2_METADATA_ATTRIBUTE_INDEX);
xmlChar *is_default = getSaml2MdProp(xmlnode, LASSO_SAML2_METADATA_ATTRIBUTE_ISDEFAULT);
if (xsdIsTrue(is_default)) {
lasso_assign_string(private_data->default_assertion_consumer, (char*)index);
}
name = g_strdup_printf(LASSO_SAML2_METADATA_ELEMENT_ASSERTION_CONSUMER_SERVICE
" %s %s",
binding_s,
index);
lasso_release_xml_string(index);
lasso_release_xml_string(is_default);
} else {
name = g_strdup_printf("%s %s", xmlnode->name, binding_s);
}
lasso_release_xml_string(binding);
/* Response endpoint ? */
response_value = getSaml2MdProp(xmlnode, LASSO_SAML2_METADATA_ATTRIBUTE_RESPONSE_LOCATION);
if (response_value) {
response_name = g_strdup_printf("%s "
LASSO_SAML2_METADATA_ATTRIBUTE_RESPONSE_LOCATION,
name);
_lasso_provider_add_metadata_value_for_role(provider, role, response_name,
(char*)response_value);
}
_lasso_provider_add_metadata_value_for_role(provider, role, name, (char*)value);
cleanup:
lasso_release_xml_string(value);
lasso_release_xml_string(response_value);
lasso_release_string(name);
lasso_release_string(response_name);
}
static gboolean
load_descriptor(xmlNode *xmlnode, LassoProvider *provider, LassoProviderRole role)
{
static char * const descriptor_attrs[] = {
LASSO_SAML2_METADATA_ATTRIBUTE_VALID_UNTIL,
LASSO_SAML2_METADATA_ATTRIBUTE_CACHE_DURATION,
LASSO_SAML2_METADATA_ATTRIBUTE_AUTHN_REQUEST_SIGNED,
LASSO_SAML2_METADATA_ATTRIBUTE_WANT_AUTHN_REQUEST_SIGNED,
LASSO_SAML2_METADATA_ATTRIBUTE_ERROR_URL
};
int i;
xmlNode *t;
GList *elements;
char *name, *binding, *response_name;
xmlChar *value;
xmlChar *response_value;
xmlChar *use;
LassoProviderPrivate *pdata = provider->private_data;
char *token, *saveptr;
/* check protocol support enumeration */
value = getSaml2MdProp(xmlnode,
LASSO_SAML2_METADATA_ATTRIBUTE_PROTOCOL_SUPPORT_ENUMERATION);
token = strtok_r((char*) value, " ", &saveptr);
while (token) {
if (strcmp(token, LASSO_SAML2_PROTOCOL_HREF) == 0)
break;
token = strtok_r(NULL, " ", &saveptr);
}
if (g_strcmp0(token, LASSO_SAML2_PROTOCOL_HREF) != 0) {
lasso_release_xml_string(value);
message(G_LOG_LEVEL_WARNING, "%s descriptor does not support SAML 2.0 protocol", xmlnode->name);
return FALSE;
}
lasso_release_xml_string(value);
t = xmlnode->children;
/* add role to supported roles for the provider */
pdata->roles |= role;
t = xmlSecGetNextElementNode(xmlnode->children);
while (t) {
if (t->type != XML_ELEMENT_NODE) {
t = t->next;
continue;
}
if (strcmp((char*)t->name, "KeyDescriptor") == 0) {
use = xmlGetProp(t, (xmlChar*)"use");
if (use == NULL || strcmp((char*)use, "signing") == 0) {
provider->private_data->signing_key_descriptor = xmlCopyNode(t, 1);
}
if (use == NULL || strcmp((char*)use, "encryption") == 0) {
provider->private_data->encryption_key_descriptor =
xmlCopyNode(t, 1);
}
if (use) {
xmlFree(use);
}
t = t->next;
continue;
}
if (strcmp((char*)t->name, "Attribute") == 0) {
if (checkSaml2MdNode(t,
LASSO_SAML2_METADATA_ELEMENT_KEY_DESCRIPTOR)) {
_lasso_provider_load_key_descriptor(provider, t);
} else if (checkSaml2MdNode(t,
LASSO_SAML2_ASSERTION_ELEMENT_ATTRIBUTE) && role == LASSO_PROVIDER_ROLE_IDP) {
LassoSaml2Attribute *attribute;
attribute = LASSO_SAML2_ATTRIBUTE(lasso_node_new_from_xmlNode(t));
if (attribute) {
provider->private_data->attributes =
g_list_append(provider->private_data->attributes, attribute);
}
continue;
}
binding = (char*)xmlGetProp(t, (xmlChar*)"Binding");
if (binding) {
/* Endpoint type */
char *binding_s = NULL;
if (strcmp(binding, LASSO_SAML2_METADATA_BINDING_SOAP) == 0) {
binding_s = "SOAP";
} else if (strcmp(binding, LASSO_SAML2_METADATA_BINDING_REDIRECT) == 0) {
binding_s = "HTTP-Redirect";
} else if (strcmp(binding, LASSO_SAML2_METADATA_BINDING_POST) == 0) {
binding_s = "HTTP-POST";
} else if (strcmp(binding, LASSO_SAML2_METADATA_BINDING_ARTIFACT) == 0) {
binding_s = "HTTP-Artifact";
} else if (strcmp(binding, LASSO_SAML2_METADATA_BINDING_PAOS) == 0) {
binding_s = "PAOS";
} else {
message(G_LOG_LEVEL_CRITICAL, "XXX: unknown binding: %s", binding);
xmlFree(binding);
t = t->next;
continue;
}
value = xmlGetProp(t, (xmlChar*)"Location");
if (value == NULL) {
message(G_LOG_LEVEL_CRITICAL, "XXX: missing location");
xmlFree(binding);
t = t->next;
continue;
}
if (strcmp((char*)t->name, "AssertionConsumerService") == 0) {
char *index = (char*)xmlGetProp(t, (xmlChar*)"index");
char *is_default = (char*)xmlGetProp(t, (xmlChar*)"isDefault");
if (is_default && strcmp(is_default, "true") == 0) {
provider->private_data->default_assertion_consumer =
g_strdup(index);
}
name = g_strdup_printf("%s %s %s", t->name, binding_s, index);
xmlFree(index);
xmlFree(is_default);
}
else {
name = g_strdup_printf("%s %s", t->name, binding_s);
}
xmlFree(binding);
response_value = xmlGetProp(t, (xmlChar*)"ResponseLocation");
if (response_value) {
response_name = g_strdup_printf("%s ResponseLocation", name);
elements = g_hash_table_lookup(descriptor, response_name);
elements = g_list_append(elements, g_strdup((char*)response_value));
g_hash_table_insert(descriptor, response_name, elements);
xmlFree(response_value);
}
attribute = (LassoSaml2Attribute*) lasso_node_new_from_xmlNode(t);
lasso_list_add_new_gobject(pdata->attributes,
attribute);
} else if (hasSaml2MdProp(t, LASSO_SAML2_METADATA_ATTRIBUTE_BINDING)) {
load_endpoint_type(t, provider, role);
} else {
name = g_strdup((char*)t->name);
value = xmlNodeGetContent(t);
_lasso_provider_add_metadata_value_for_role(provider, role, (char*)t->name,
(char*)value);
lasso_release_xml_string(value);
}
elements = g_hash_table_lookup(descriptor, name);
elements = g_list_append(elements, g_strdup((char*)value));
xmlFree(value);
g_hash_table_insert(descriptor, name, elements);
t = t->next;
t = xmlSecGetNextElementNode(t->next);
}
for (i = 0; descriptor_attrs[i]; i++) {
value = xmlGetProp(xmlnode, (xmlChar*)descriptor_attrs[i]);
value = getSaml2MdProp(xmlnode, descriptor_attrs[i]);
if (value == NULL) {
continue;
}
name = g_strdup(descriptor_attrs[i]);
elements = g_hash_table_lookup(descriptor, name);
elements = g_list_append(elements, g_strdup((char*)value));
xmlFree(value);
g_hash_table_insert(descriptor, name, elements);
_lasso_provider_add_metadata_value_for_role(provider, role, descriptor_attrs[i],
(char*)value);
lasso_release_xml_string(value);
}
return TRUE;
}
gboolean
@ -173,103 +234,104 @@ lasso_saml20_provider_load_metadata(LassoProvider *provider, xmlNode *root_node)
{
xmlNode *node, *descriptor_node;
xmlChar *providerID;
LassoProviderPrivate *pdata = provider->private_data;
static const struct {
char *name;
LassoProviderRole role;
} descriptors[] = {
{ LASSO_SAML2_METADATA_ELEMENT_IDP_SSO_DESCRIPTOR,
LASSO_PROVIDER_ROLE_IDP },
{ LASSO_SAML2_METADATA_ELEMENT_SP_SSO_DESCRIPTOR,
LASSO_PROVIDER_ROLE_SP },
{ LASSO_SAML2_METADATA_ELEMENT_ATTRIBUTE_AUTHORITY_DESCRIPTOR,
LASSO_PROVIDER_ROLE_ATTRIBUTE_AUTHORITY },
{ LASSO_SAML2_METADATA_ELEMENT_PDP_DESCRIPTOR,
LASSO_PROVIDER_ROLE_AUTHZ_AUTHORITY },
{ LASSO_SAML2_METADATA_ELEMENT_AUTHN_DESCRIPTOR,
LASSO_PROVIDER_ROLE_AUTHN_AUTHORITY },
{ NULL, 0 }
};
if (strcmp((char*)root_node->name, "EntityDescriptor") == 0) {
/* find a root node for the metadata file */
if (xmlSecCheckNodeName(root_node,
BAD_CAST LASSO_SAML2_METADATA_ELEMENT_ENTITY_DESCRIPTOR,
BAD_CAST LASSO_SAML2_METADATA_HREF)) {
node = root_node;
} else if (strcmp((char*)root_node->name, "EntitiesDescriptor") == 0) {
/* XXX: take the first entity; would it be possible to have an
* optional argument to take another one ? */
node = root_node->children;
while (node && strcmp((char*)node->name, "EntityDescriptor") != 0) {
node = node->next;
}
if (node == NULL) {
message (G_LOG_LEVEL_CRITICAL, "lasso_saml20_provider_load_metadata_from_doc: no EntityDescriptor");
return FALSE;
}
} else {
message (G_LOG_LEVEL_CRITICAL, "lasso_saml20_provider_load_metadata_from_doc: no EntityDescriptor");
/* what? */
return FALSE;
} else if (xmlSecCheckNodeName(root_node,
BAD_CAST LASSO_SAML2_METADATA_ELEMENT_ENTITIES_DESCRIPTOR,
BAD_CAST LASSO_SAML2_METADATA_HREF)) {
node = xmlSecFindChild(root_node,
BAD_CAST LASSO_SAML2_METADATA_ELEMENT_ENTITY_DESCRIPTOR,
BAD_CAST LASSO_SAML2_METADATA_HREF);
}
g_return_val_if_fail (node, FALSE);
providerID = xmlGetProp(node, (xmlChar*)"entityID");
g_return_val_if_fail(providerID, FALSE);
lasso_assign_string(provider->ProviderID, (char*)providerID);
lasso_release_xml_string(providerID);
if (provider->ProviderID == NULL) {
message (G_LOG_LEVEL_CRITICAL, "lasso_saml20_provider_load_metadata_from_doc: no entityID attribute");
return FALSE;
/* initialize roles */
pdata->roles = LASSO_PROVIDER_ROLE_NONE;
lasso_set_string_from_prop(&pdata->valid_until, node,
BAD_CAST LASSO_SAML2_METADATA_ATTRIBUTE_VALID_UNTIL,
BAD_CAST LASSO_SAML2_METADATA_HREF);
lasso_set_string_from_prop(&pdata->cache_duration, node,
BAD_CAST LASSO_SAML2_METADATA_ATTRIBUTE_CACHE_DURATION,
BAD_CAST LASSO_SAML2_METADATA_HREF);
descriptor_node = xmlSecGetNextElementNode(node->children);
while (descriptor_node) {
int i = 0;
while (descriptors[i].name) {
char *name = descriptors[i].name;
LassoProviderRole role = descriptors[i].role;
if (checkSaml2MdNode(descriptor_node, name)) {
load_descriptor(descriptor_node,
provider,
role);
}
i++;
}
if (checkSaml2MdNode(descriptor_node,
LASSO_SAML2_METADATA_ELEMENT_ORGANIZATION)) {
lasso_assign_xml_node(pdata->organization, descriptor_node); }
descriptor_node = xmlSecGetNextElementNode(descriptor_node->next);
}
for (descriptor_node = node->children; descriptor_node != NULL;
descriptor_node = descriptor_node->next) {
if (descriptor_node->type != XML_ELEMENT_NODE)
continue;
if (strcmp((char*)descriptor_node->name, "IDPSSODescriptor") == 0) {
load_descriptor(descriptor_node,
provider->private_data->Descriptors, provider);
provider->role = LASSO_PROVIDER_ROLE_IDP;
continue;
}
if (strcmp((char*)descriptor_node->name, "SPSSODescriptor") == 0) {
load_descriptor(descriptor_node,
provider->private_data->Descriptors, provider);
provider->role = LASSO_PROVIDER_ROLE_SP;
continue;
}
if (strcmp((char*)descriptor_node->name, "AttributeAuthorityDescriptor") == 0) {
load_descriptor(descriptor_node,
provider->private_data->Descriptors, provider);
provider->role = LASSO_PROVIDER_ROLE_ATTRIBUTE_AUTHORITY;
continue;
}
if (strcmp((char*)descriptor_node->name, "PDPDescriptor") == 0) {
load_descriptor(descriptor_node,
provider->private_data->Descriptors, provider);
provider->role = LASSO_PROVIDER_ROLE_PDP;
continue;
}
if (strcmp((char*)descriptor_node->name, "AuthnAuthorityDescriptor") == 0) {
load_descriptor(descriptor_node,
provider->private_data->Descriptors, provider);
provider->role = LASSO_PROVIDER_ROLE_AUTHN_AUTHORITY;
continue;
}
if (strcmp((char*)descriptor_node->name, "Organization") == 0) {
provider->private_data->organization = xmlCopyNode(
descriptor_node, 1);
continue;
}
}
return TRUE;
}
LassoHttpMethod
lasso_saml20_provider_get_first_http_method(LassoProvider *provider,
const LassoProvider *remote_provider, LassoMdProtocolType protocol_type)
LassoProvider *remote_provider, LassoMdProtocolType protocol_type)
{
LassoHttpMethod method = LASSO_HTTP_METHOD_NONE;
int i;
const char *possible_bindings[] = {
"HTTP-Redirect", "HTTP-Post", "SOAP", "HTTP-Artifact", NULL
"HTTP-POST",
"HTTP-Redirect",
"HTTP-Artifact",
"SOAP",
"PAOS",
NULL
};
LassoHttpMethod method_bindings[] = {
LASSO_HTTP_METHOD_SOAP, LASSO_HTTP_METHOD_REDIRECT, LASSO_HTTP_METHOD_POST
LASSO_HTTP_METHOD_POST,
LASSO_HTTP_METHOD_REDIRECT,
LASSO_HTTP_METHOD_ARTIFACT_GET,
LASSO_HTTP_METHOD_SOAP,
LASSO_HTTP_METHOD_PAOS
};
for (i=0; possible_bindings[i] && method == LASSO_HTTP_METHOD_NONE; i++) {
char *s;
const GList *l1, *l2;
s = g_strdup_printf("%s %s", profile_names[protocol_type], possible_bindings[i]);
s = g_strdup_printf("%s %s",
profile_names[protocol_type],
possible_bindings[i]);
l1 = lasso_provider_get_metadata_list(provider, s);
l2 = lasso_provider_get_metadata_list(remote_provider, s);
if (l1 && l2) {
@ -286,37 +348,29 @@ lasso_saml20_provider_check_assertion_consumer_service_url(LassoProvider *provid
GHashTable *descriptor;
GList *l = NULL, *r = NULL, *candidate = NULL;
char *name;
char *binding_s = NULL;
const char *binding_s = NULL;
int lname;
descriptor = provider->private_data->SPDescriptor;
descriptor = provider->private_data->Descriptors;
if (descriptor == NULL || url == NULL || binding == NULL)
return FALSE;
if (strcmp(binding, LASSO_SAML2_METADATA_BINDING_SOAP) == 0) {
binding_s = "SOAP";
} else if (strcmp(binding, LASSO_SAML2_METADATA_BINDING_REDIRECT) == 0) {
binding_s = "HTTP-Redirect";
} else if (strcmp(binding, LASSO_SAML2_METADATA_BINDING_POST) == 0) {
binding_s = "HTTP-POST";
} else if (strcmp(binding, LASSO_SAML2_METADATA_BINDING_ARTIFACT) == 0) {
binding_s = "HTTP-Artifact";
} else if (strcmp(binding, LASSO_SAML2_METADATA_BINDING_PAOS) == 0) {
binding_s = "PAOS";
}
binding_s = binding_uri_to_identifier(binding);
if (binding_s == NULL) {
return FALSE;
}
g_hash_table_foreach(descriptor, (GHFunc)add_assertion_consumer_url_to_list, &r);
g_hash_table_foreach(descriptor,
(GHFunc)add_assertion_consumer_url_to_list,
&r);
name = g_strdup_printf("AssertionConsumerService %s ", binding_s);
name = g_strdup_printf(LASSO_SAML2_METADATA_ELEMENT_ASSERTION_CONSUMER_SERVICE
" %s ", binding_s);
lname = strlen(name);
for (l = r; l; l = g_list_next(l)) {
char *b = l->data;
if (strncmp(name, b, lname) == 0) {
candidate = g_hash_table_lookup(descriptor, b);
candidate = lasso_provider_get_metadata_list_for_role(provider, LASSO_PROVIDER_ROLE_SP, b);
if (candidate && candidate->data && strcmp(candidate->data, url) == 0)
break;
else
@ -333,15 +387,17 @@ lasso_saml20_provider_check_assertion_consumer_service_url(LassoProvider *provid
}
gchar*
lasso_saml20_provider_get_assertion_consumer_service_url(const LassoProvider *provider,
lasso_saml20_provider_get_assertion_consumer_service_url(LassoProvider *provider,
int service_id)
{
GHashTable *descriptor;
GList *l = NULL;
char *sid;
char *name;
const char *possible_bindings[] = {
"HTTP-Artifact", "HTTP-Post", "HTTP-POST", "HTTP-Redirect", "SOAP", NULL
"HTTP-Artifact",
"HTTP-POST",
"HTTP-Redirect",
NULL
};
int i;
@ -351,19 +407,18 @@ lasso_saml20_provider_get_assertion_consumer_service_url(const LassoProvider *pr
sid = g_strdup_printf("%d", service_id);
}
descriptor = provider->private_data->Descriptors;
if (descriptor == NULL)
return NULL;
for (i=0; possible_bindings[i]; i++) {
name = g_strdup_printf("AssertionConsumerService %s %s",
name = g_strdup_printf(LASSO_SAML2_METADATA_ELEMENT_ASSERTION_CONSUMER_SERVICE
" %s %s",
possible_bindings[i], sid);
l = g_hash_table_lookup(descriptor, name);
g_free(name);
l = lasso_provider_get_metadata_list_for_role(provider,
LASSO_PROVIDER_ROLE_SP,
name);
lasso_release_string(name);
if (l != NULL)
break;
}
g_free(sid);
lasso_release_string(sid);
if (l)
return g_strdup(l->data);
return NULL;
@ -372,45 +427,37 @@ lasso_saml20_provider_get_assertion_consumer_service_url(const LassoProvider *pr
static void
add_assertion_consumer_url_to_list(gchar *key, G_GNUC_UNUSED gpointer value, GList **list)
{
if (strncmp(key, "AssertionConsumerService", 24) == 0) {
*list = g_list_append(*list, key);
if (strncmp(key, "sp AssertionConsumerService", 24) == 0) {
lasso_list_add_new_string(*list, key);
}
}
gchar*
lasso_saml20_provider_get_assertion_consumer_service_url_by_binding(const LassoProvider *provider,
gchar *binding)
lasso_saml20_provider_get_assertion_consumer_service_url_by_binding(LassoProvider *provider,
const gchar *binding)
{
GHashTable *descriptor;
GList *l = NULL, *r = NULL;
char *name;
char *binding_s = NULL;
const char *binding_s = NULL;
int lname;
descriptor = provider->private_data->Descriptors;
if (descriptor == NULL)
return NULL;
if (strcmp(binding, LASSO_SAML2_METADATA_BINDING_SOAP) == 0) {
binding_s = "SOAP";
} else if (strcmp(binding, LASSO_SAML2_METADATA_BINDING_REDIRECT) == 0) {
binding_s = "HTTP-Redirect";
} else if (strcmp(binding, LASSO_SAML2_METADATA_BINDING_POST) == 0) {
binding_s = "HTTP-POST";
} else if (strcmp(binding, LASSO_SAML2_METADATA_BINDING_ARTIFACT) == 0) {
binding_s = "HTTP-Artifact";
} else if (strcmp(binding, LASSO_SAML2_METADATA_BINDING_PAOS) == 0) {
binding_s = "PAOS";
}
binding_s = binding_uri_to_identifier(binding);
if (binding_s == NULL) {
return NULL;
}
g_hash_table_foreach(descriptor, (GHFunc)add_assertion_consumer_url_to_list, &r);
g_hash_table_foreach(descriptor,
(GHFunc)add_assertion_consumer_url_to_list,
&r);
name = g_strdup_printf("AssertionConsumerService %s ", binding_s);
name = g_strdup_printf("sp "
LASSO_SAML2_METADATA_ELEMENT_ASSERTION_CONSUMER_SERVICE
" %s ", binding_s);
lname = strlen(name);
for (l = r; l; l = g_list_next(l)) {
char *b = l->data;
@ -419,8 +466,8 @@ lasso_saml20_provider_get_assertion_consumer_service_url_by_binding(const LassoP
break;
}
}
g_free(name);
g_list_free(r);
lasso_release_string(name);
lasso_release_list(r);
if (l) {
return g_strdup(l->data);
@ -429,10 +476,8 @@ lasso_saml20_provider_get_assertion_consumer_service_url_by_binding(const LassoP
return NULL;
}
gchar*
lasso_saml20_provider_get_assertion_consumer_service_binding(const LassoProvider *provider,
lasso_saml20_provider_get_assertion_consumer_service_binding(LassoProvider *provider,
int service_id)
{
GHashTable *descriptor;
@ -441,7 +486,11 @@ lasso_saml20_provider_get_assertion_consumer_service_binding(const LassoProvider
char *name;
char *binding = NULL;
const char *possible_bindings[] = {
"HTTP-Artifact", "HTTP-Post", "HTTP-POST", "HTTP-Redirect", "SOAP", NULL
"HTTP-POST",
"HTTP-Redirect",
"HTTP-Artifact",
"SOAP",
NULL
};
int i;
@ -450,32 +499,32 @@ lasso_saml20_provider_get_assertion_consumer_service_binding(const LassoProvider
} else {
sid = g_strdup_printf("%d", service_id);
}
descriptor = provider->private_data->Descriptors;
if (descriptor == NULL)
return NULL;
for (i=0; possible_bindings[i]; i++) {
name = g_strdup_printf("AssertionConsumerService %s %s",
name = g_strdup_printf(LASSO_SAML2_METADATA_ELEMENT_ASSERTION_CONSUMER_SERVICE
" %s %s",
possible_bindings[i], sid);
l = g_hash_table_lookup(descriptor, name);
g_free(name);
l = lasso_provider_get_metadata_list_for_role(provider, LASSO_PROVIDER_ROLE_SP, name);
lasso_release_string(name);
if (l != NULL) {
binding = g_strdup(possible_bindings[i]);
break;
}
}
g_free(sid);
lasso_release_string(sid);
return binding;
}
gboolean
lasso_saml20_provider_accept_http_method(LassoProvider *provider, const LassoProvider *remote_provider,
lasso_saml20_provider_accept_http_method(LassoProvider *provider, LassoProvider *remote_provider,
LassoMdProtocolType protocol_type, LassoHttpMethod http_method,
gboolean initiate_profile)
{
char *protocol_profile;
const static char *http_methods[] = {
static const char *http_methods[] = {
NULL,
NULL,
NULL,
@ -488,7 +537,7 @@ lasso_saml20_provider_accept_http_method(LassoProvider *provider, const LassoPro
NULL
};
gboolean rc = FALSE;
LassoProviderRole initiating_role;
initiating_role = remote_provider->role;
if (remote_provider->role == LASSO_PROVIDER_ROLE_SP) {
@ -511,7 +560,7 @@ lasso_saml20_provider_accept_http_method(LassoProvider *provider, const LassoPro
/* special hack for single sign on */
if (protocol_type == LASSO_MD_PROTOCOL_TYPE_SINGLE_SIGN_ON) {
/* no need to check for the response, it uses another canal
* (AssertionConsumingService) */
* (AssertionConsumerService) */
rc = (lasso_provider_get_metadata_list(remote_provider, protocol_profile) != NULL);
} else {

View File

@ -35,20 +35,20 @@ extern "C" {
gboolean lasso_saml20_provider_load_metadata(LassoProvider *provider, xmlNode *root_node);
LassoHttpMethod lasso_saml20_provider_get_first_http_method(LassoProvider *provider,
const LassoProvider *remote_provider, LassoMdProtocolType protocol_type);
LassoProvider *remote_provider, LassoMdProtocolType protocol_type);
gboolean lasso_saml20_provider_accept_http_method(LassoProvider *provider,
const LassoProvider *remote_provider, LassoMdProtocolType protocol_type,
LassoProvider *remote_provider, LassoMdProtocolType protocol_type,
LassoHttpMethod http_method, gboolean initiate_profile);
char* lasso_saml20_provider_build_artifact(const LassoProvider *provider);
char* lasso_saml20_provider_build_artifact(LassoProvider *provider);
gchar* lasso_saml20_provider_get_assertion_consumer_service_url(const LassoProvider *provider,
gchar* lasso_saml20_provider_get_assertion_consumer_service_url(LassoProvider *provider,
int service_id);
gchar* lasso_saml20_provider_get_assertion_consumer_service_binding(const LassoProvider *provider,
gchar* lasso_saml20_provider_get_assertion_consumer_service_binding(LassoProvider *provider,
int service_id);
gchar* lasso_saml20_provider_get_assertion_consumer_service_url_by_binding(const LassoProvider *provider,
gchar *binding);
gchar* lasso_saml20_provider_get_assertion_consumer_service_url_by_binding(LassoProvider *provider,
const gchar *binding);
gboolean lasso_saml20_provider_check_assertion_consumer_service_url(LassoProvider *provider, const gchar *url, const gchar *binding);
#ifdef __cplusplus
}

View File

@ -116,6 +116,13 @@
*/
#define LASSO_SAML2_METADATA_BINDING_PAOS "urn:oasis:names:tc:SAML:2.0:bindings:PAOS"
/**
* LASSO_SAML2_METADATA_BINDING_URI:
*
* URI for the URI special binding.
*/
#define LASSO_SAML2_METADATA_BINDING_URI "urn:oasis:names:tc:SAML:2.0:bindings:URI"
/**
* LASSO_SAML2_DEFLATE_ENCODING:
*

View File

@ -33,7 +33,7 @@
#define LASSO_SAML2_METADATA_ELEMENT_SP_SSO_DESCRIPTOR "SPSSODescriptor"
#define LASSO_SAML2_METADATA_ELEMENT_ATTRIBUTE_AUTHORITY_DESCRIPTOR "AttributeAuthorityDescriptor"
#define LASSO_SAML2_METADATA_ELEMENT_PDP_DESCRIPTOR "PDPDescriptor"
#define LASSO_SAML2_METADATA_ELEMENT_AUTHN_DESCRIPTOR "AuthnAuhtorityDescriptor"
#define LASSO_SAML2_METADATA_ELEMENT_AUTHN_DESCRIPTOR "AuthnAuthorityDescriptor"
#define LASSO_SAML2_METADATA_ELEMENT_ORGANIZATION "Organization"
#define LASSO_SAML2_METADATA_ELEMENT_KEY_DESCRIPTOR "KeyDescriptor"
#define LASSO_SAML2_METADATA_ELEMENT_ASSERTION_CONSUMER_SERVICE "AssertionConsumerService"

View File

@ -20,7 +20,7 @@ INCLUDES = \
$(CHECK_CFLAGS)
tests_SOURCES = tests.c login_tests.c basic_tests.c random_tests.c metadata_tests.c login_tests_saml2.c $(WSF_TESTS)
tests_SOURCES = tests.c login_tests.c basic_tests.c random_tests.c metadata_tests.c login_tests_saml2.c assertion_query_saml2.c $(WSF_TESTS)
tests_LDADD = \
$(top_builddir)/lasso/liblasso.la \

View File

@ -0,0 +1,95 @@
/*
* Lasso library C unit tests
*
* Copyright (C) 2004-2007 Entr'ouvert
* http://lasso.entrouvert.org
*
* Authors: See AUTHORS file in top-level directory.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdlib.h>
#include <string.h>
#include <check.h>
#include <glib.h>
#include "../lasso/lasso.h"
#include "../lasso/utils.h"
#include "../lasso/backward_comp.h"
#include "../lasso/xml/saml-2.0/saml2_xsd.h"
#include "./tests.h"
inline static char*
generateIdentityProviderContextDump()
{
LassoServer *serverContext;
GList *providers;
char *ret;
serverContext = lasso_server_new(
TESTSDATADIR "/idp6-saml2/metadata.xml",
TESTSDATADIR "/idp6-saml2/private-key.pem",
NULL, /* Secret key to unlock private key */
NULL);
lasso_server_add_provider(
serverContext,
LASSO_PROVIDER_ROLE_SP,
TESTSDATADIR "/sp5-saml2/metadata.xml",
NULL,
NULL);
providers = g_hash_table_get_values(serverContext->providers);
lasso_provider_set_encryption_mode(LASSO_PROVIDER(providers->data), LASSO_ENCRYPTION_MODE_ASSERTION | LASSO_ENCRYPTION_MODE_NAMEID);
ret = lasso_server_dump(serverContext);
g_object_unref(serverContext);
return ret;
}
inline static char*
generateServiceProviderContextDump()
{
LassoServer *serverContext;
char *ret;
serverContext = lasso_server_new(
TESTSDATADIR "/sp5-saml2/metadata.xml",
TESTSDATADIR "/sp5-saml2/private-key.pem",
NULL, /* Secret key to unlock private key */
NULL);
lasso_server_add_provider(
serverContext,
LASSO_PROVIDER_ROLE_IDP,
TESTSDATADIR "/idp6-saml2/metadata.xml",
NULL,
NULL);
ret = lasso_server_dump(serverContext);
g_object_unref(serverContext);
return ret;
}
Suite*
assertion_query_suite()
{
Suite *s = suite_create("Assertion Query");
TCase *tc_metadata_access = tcase_create("Extended metadata access");
suite_add_tcase(s, tc_metadata_access);
return s;
}

View File

@ -28,6 +28,9 @@
#include <../lasso/lasso.h>
#include <../lasso/id-ff/provider.h>
#include "../lasso/utils.h"
#include "./tests.h"
#include "../lasso/xml/saml-2.0/saml2_xsd.h"
START_TEST(test01_metadata_load_der_certificate_from_x509_cert)
{
@ -83,6 +86,29 @@ START_TEST(test06_metadata_load_public_key_from_rsa_keyvalue)
}
END_TEST
START_TEST(test07_metadata_role_descriptors)
{
LassoProvider *provider = (LassoProvider*)lasso_provider_new(LASSO_PROVIDER_ROLE_IDP, TESTSDATADIR "/idp6-saml2/metadata.xml",
NULL, NULL);
GList *l, *q;
int i = 0;
check_not_null(provider);
for (i = LASSO_PROVIDER_ROLE_ANY+1; i < LASSO_PROVIDER_ROLE_LAST; i++) {
l = lasso_provider_get_metadata_keys_for_role(provider, i);
lasso_foreach(q, l) {
printf("%i %s\n", i, (char*)q->data);
}
}
l = lasso_provider_get_metadata_list_for_role(provider, LASSO_PROVIDER_ROLE_IDP,
LASSO_SAML2_METADATA_ATTRIBUTE_WANT_AUTHN_REQUEST_SIGNED);
check_not_null(l);
check_null(l->next);
check_str_equals(l->data, "true");
lasso_release_gobject(provider);
}
END_TEST
Suite*
metadata_suite()
{
@ -99,12 +125,16 @@ metadata_suite()
tcase_create("Load DER public key from <ds:X509Certificate>");
TCase *tc_metadata_load_public_key_from_rsa_keyvalue =
tcase_create("Load RSAKeyValue public key");
TCase *tc_metadata_role_descriptors =
tcase_create("Lookup different role descriptors datas");
suite_add_tcase(s, tc_metadata_load_der_certificate_from_x509_cert);
suite_add_tcase(s, tc_metadata_load_pem_certificate_from_x509_cert);
suite_add_tcase(s, tc_metadata_load_der_public_key_from_keyvalue);
suite_add_tcase(s, tc_metadata_load_pem_public_key_from_keyvalue);
suite_add_tcase(s, tc_metadata_load_public_key_from_x509_cert);
suite_add_tcase(s, tc_metadata_load_public_key_from_rsa_keyvalue);
suite_add_tcase(s, tc_metadata_role_descriptors);
tcase_add_test(tc_metadata_load_der_certificate_from_x509_cert,
test01_metadata_load_der_certificate_from_x509_cert);
tcase_add_test(tc_metadata_load_pem_certificate_from_x509_cert,
@ -117,5 +147,7 @@ metadata_suite()
test05_metadata_load_public_key_from_x509_cert);
tcase_add_test(tc_metadata_load_public_key_from_rsa_keyvalue,
test06_metadata_load_public_key_from_rsa_keyvalue);
tcase_add_test(tc_metadata_role_descriptors,
test07_metadata_role_descriptors);
return s;
}

View File

@ -34,6 +34,7 @@ extern Suite* login_suite();
extern Suite* login_saml2_suite();
extern Suite* random_suite();
extern Suite* metadata_suite();
extern Suite* assertion_query_suite();
#ifdef LASSO_WSF_ENABLED
extern Suite* idwsf2_suite();
#endif
@ -46,6 +47,7 @@ SuiteFunction suites[] = {
login_saml2_suite,
random_suite,
metadata_suite,
assertion_query_suite,
#ifdef LASSO_WSF_ENABLED
idwsf2_suite,
#endif