/* $Id$ * * Lasso - A free implementation of the Liberty Alliance specifications. * * 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 "saml2_helper.h" #include "../id-ff/server.h" #include "../id-ff/serverprivate.h" #include "../xml/saml-2.0/saml2_audience_restriction.h" #include "../xml/saml-2.0/saml2_one_time_use.h" #include "../xml/saml-2.0/saml2_proxy_restriction.h" #include "../xml/saml-2.0/saml2_attribute.h" #include "../xml/saml-2.0/saml2_attribute_statement.h" #include "../xml/saml-2.0/saml2_attribute_value.h" #include "../xml/private.h" #include "../utils.h" #include "provider.h" #include static GList* lasso_saml2_assertion_get_audience_restrictions(LassoSaml2Assertion *assertion); /** * lasso_saml2_assertion_has_audience_restriction: * @saml2_assertion: a #LassoSaml2Assertion object * * Verify that a #LassoSaml2AudienceRestriction is present in the assertion. * * Return value: TRUE if a #LassoSaml2AudienceRestriction is present in the Conditions of the * #LassoSaml2Assertion. */ gboolean lasso_saml2_assertion_has_audience_restriction(LassoSaml2Assertion *saml2_assertion) { return lasso_saml2_assertion_get_audience_restrictions(saml2_assertion) != NULL; } /** * lasso_saml2_assertion_is_audience_restricted: * @saml2_assertion: a #LassoSaml2Assertion object * @providerID: the providerID that will be compared to the audience restriction declarations. * * Verify that the assertion is restricted to the given providerID. * * Return value: TRUE if @providerID is part of a #LassoSaml2AudienceRestriction element in the * assertion, FALSE otherwise. */ gboolean lasso_saml2_assertion_is_audience_restricted(LassoSaml2Assertion *saml2_assertion, char* providerID) { GList *it; lasso_foreach(it, lasso_saml2_assertion_get_audience_restrictions(saml2_assertion)) { if (LASSO_IS_SAML2_AUDIENCE_RESTRICTION(it->data)) { LassoSaml2AudienceRestriction *saml2_audience_restriction; saml2_audience_restriction = (LassoSaml2AudienceRestriction*)it->data; if (lasso_strisequal(saml2_audience_restriction->Audience,providerID)) return TRUE; } } return FALSE; } /** * lasso_saml2_name_id_new_with_persistent_format: * @id: the identifier for the princiapl * @idpID: the entity ID of the IdP * @providerID: the entity ID of the provider * * Create a new #LassoSaml2NameID object, which the #LASSO_SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT * format, @id as content, @idpID as NameQualifier and @providerID as SPNameQualifier. * * Since: 2.3 * Return value: a newly created #LassoSaml2NameID */ LassoSaml2NameID* lasso_saml2_name_id_new_with_persistent_format(const char *id, const char *idpID, const char *providerID) { return lasso_saml2_name_id_build_persistent(id, idpID, providerID); } /** * lasso_saml2_name_id_build_persistent: * @id: the identifier for the princiapl * @idpID: the entity ID of the IdP * @providerID: the entity ID of the provider * * Create a new #LassoSaml2NameID object, which the #LASSO_SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT * format, @id as content, @idpID as NameQualifier and @providerID as SPNameQualifier. * * Return value: a newly created #LassoSaml2NameID * Deprecated: 2.3: use lasso_saml2_name_id_new_with_persistent_format() instead. */ LassoSaml2NameID* lasso_saml2_name_id_build_persistent(const char *id, const char *idpID, const char *providerID) { LassoSaml2NameID *saml2_name_id; saml2_name_id = (LassoSaml2NameID*)lasso_saml2_name_id_new(); saml2_name_id->content = g_strdup(id); saml2_name_id->Format = g_strdup(LASSO_SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT); saml2_name_id->NameQualifier = g_strdup(idpID); saml2_name_id->SPNameQualifier = g_strdup(providerID); return saml2_name_id; } /** * lasso_saml2_name_id_build_encrypted_persistent * @id: the identifier for the principal * @idpID: the entity ID of the IdP * @provider: the provider for which the NameID is created. * * Create a new #LassoSaml2NameID issued by @idpID and targeted at @provider, and encrypt it using * @provider public key. * * Return value: a newly created #LassoSaml2EncryptedElement object. */ LassoSaml2EncryptedElement* lasso_saml2_encrypted_element_build_encrypted_persistent_name_id( const char *id, const char *idpID, const LassoProvider *provider) { LassoSaml2NameID *saml2_name_id; LassoSaml2EncryptedElement *encrypted_element; saml2_name_id = lasso_saml2_name_id_build_persistent(id, idpID, provider->ProviderID); encrypted_element = lasso_provider_saml2_node_encrypt(provider, (LassoNode*)saml2_name_id); lasso_release_gobject(saml2_name_id); return encrypted_element; } static LassoSaml2Conditions* lasso_saml2_assertion_get_conditions(LassoSaml2Assertion *saml2_assertion, gboolean create) { if (! LASSO_IS_SAML2_CONDITIONS(saml2_assertion->Conditions) && create) { lasso_assign_new_gobject (saml2_assertion->Conditions, (LassoSaml2Conditions*)lasso_saml2_conditions_new()); } return saml2_assertion->Conditions; } static LassoSaml2Subject* lasso_saml2_assertion_get_subject(LassoSaml2Assertion *saml2_assertion, gboolean create) { if (! LASSO_IS_SAML2_SUBJECT(saml2_assertion->Subject) && create) { lasso_assign_new_gobject(saml2_assertion->Subject, (LassoSaml2Subject*)lasso_saml2_subject_new()); } return saml2_assertion->Subject; } static LassoSaml2SubjectConfirmation* lasso_saml2_assertion_get_subject_confirmation(LassoSaml2Assertion *saml2_assertion, gboolean create) { LassoSaml2Subject *subject; subject = lasso_saml2_assertion_get_subject (saml2_assertion, create); if (subject == NULL) return NULL; if (! LASSO_IS_SAML2_SUBJECT_CONFIRMATION(subject->SubjectConfirmation) && create) { lasso_assign_new_gobject(subject->SubjectConfirmation, (LassoSaml2SubjectConfirmation*)lasso_saml2_subject_confirmation_new()); } return subject->SubjectConfirmation; } LassoSaml2SubjectConfirmationData* lasso_saml2_assertion_get_subject_confirmation_data(LassoSaml2Assertion *saml2_assertion, gboolean create) { LassoSaml2SubjectConfirmation *subject_confirmation; subject_confirmation = lasso_saml2_assertion_get_subject_confirmation (saml2_assertion, create); if (subject_confirmation == NULL) return NULL; if (! LASSO_IS_SAML2_SUBJECT_CONFIRMATION_DATA(subject_confirmation->SubjectConfirmationData) && create) { lasso_assign_new_gobject(subject_confirmation->SubjectConfirmationData, (LassoSaml2SubjectConfirmationData*)lasso_saml2_subject_confirmation_data_new()); } return subject_confirmation->SubjectConfirmationData; } /** * lasso_saml2_assertion_set_subject_name_id: * @saml2_assertion: a #LassoSaml2Assertion object * @node: a #LassoSaml2NameID or #LassoSaml2EncryptedElement * * Set the subject NameID, which can be a simple #LassoSaml2NameID object or an encrypted * #LassoSaml2NameID as a #LassoSaml2EncryptedElement. */ void lasso_saml2_assertion_set_subject_name_id(LassoSaml2Assertion *saml2_assertion, LassoNode *node) { LassoSaml2Subject *saml2_subject; g_return_if_fail (LASSO_IS_SAML2_ASSERTION (saml2_assertion)); saml2_subject = lasso_saml2_assertion_get_subject (saml2_assertion, TRUE); if (LASSO_IS_SAML2_NAME_ID(node)) { lasso_assign_gobject (saml2_subject->NameID, node); } else if (LASSO_IS_SAML2_ENCRYPTED_ELEMENT(node)) { lasso_assign_gobject(saml2_subject->EncryptedID, node) } else { message(G_LOG_LEVEL_WARNING, "Cannot set subject name id, since node is neither an EncryptedElement or a NameID"); } } /** * lasso_saml2_assertion_set_subject_confirmation_name_id: * @saml2_assertion: a #LassoSaml2Assertion object * @node: a #LassoSaml2NameID or #LassoSaml2EncryptedElement * * Set the subject NameID, which can be a simple #LassoSaml2NameID object or an encrypted * #LassoSaml2NameID as a #LassoSaml2EncryptedElement. */ void lasso_saml2_assertion_set_subject_confirmation_name_id(LassoSaml2Assertion *saml2_assertion, LassoNode *node) { LassoSaml2SubjectConfirmation *saml2_subject_confirmation; g_return_if_fail (LASSO_IS_SAML2_ASSERTION (saml2_assertion)); saml2_subject_confirmation = lasso_saml2_assertion_get_subject_confirmation (saml2_assertion, TRUE); if (LASSO_IS_SAML2_NAME_ID(node)) { lasso_assign_gobject (saml2_subject_confirmation->NameID, node); } else if (LASSO_IS_SAML2_ENCRYPTED_ELEMENT(node)) { lasso_assign_gobject(saml2_subject_confirmation->EncryptedID, node) } else { message(G_LOG_LEVEL_WARNING, "Cannot set subject name id, since node is neither an EncryptedElement or a NameID"); } } #define set_notbefore_and_notonorafter(node, tolerance, length) \ if (tolerance != -1 && length != -1) \ { \ time_t now, a, b; \ now = time(NULL); \ a = now - tolerance; \ b = now + length + tolerance; \ lasso_assign_new_string (node->NotBefore, \ lasso_time_to_iso_8601_gmt (a)); \ lasso_assign_new_string (node->NotOnOrAfter, \ lasso_time_to_iso_8601_gmt (b)); \ } /** * lasso_saml2_set_subject_confirmation_data: * @saml2_assertion: a #LassoSaml2Assertion object * @tolerance: tolerance to the range of time when the subject can be confirmed * @length: length of the range of time when the subject can be confirmed * @Recipient: the URL where the assertion can be consumed * @InResponseTo: the identifier of the request which resulted in this assertion * @Address: the address IP from which the subject should submit this assertion. * */ void lasso_saml2_assertion_set_subject_confirmation_data(LassoSaml2Assertion *saml2_assertion, time_t tolerance, time_t length, const char *Recipient, const char *InResponseTo, const char *Address) { LassoSaml2SubjectConfirmationData *saml2_subject_confirmation_data; g_return_if_fail(LASSO_IS_SAML2_ASSERTION (saml2_assertion)); saml2_subject_confirmation_data = lasso_saml2_assertion_get_subject_confirmation_data (saml2_assertion, TRUE); set_notbefore_and_notonorafter (saml2_subject_confirmation_data, tolerance, length); lasso_assign_string (saml2_subject_confirmation_data->Recipient, Recipient); lasso_assign_string (saml2_subject_confirmation_data->InResponseTo, InResponseTo); lasso_assign_string (saml2_subject_confirmation_data->Address, Address); } /** * lasso_saml2_assertion_set_basic_conditions: * @tolerance:(default -1): tolerance to the range of time when the assertion is valid * @length:(default -1): length of the range of time when the assertion is valid * @one_time_use:(default FALSE): can the assertion be kept or should it be used immediately * * Set conditions limiting usage of the assertion. * * @tolerance and @length are time quantity measured in seconds, it defines the time range in which * the assertion is valid, it is computed as [now()-tolerance, now()+length+tolerance]. * @one_time_use allows the issuer to limit caching of the assertion. * @proxy_count specify how many proxy hop can be traversed before this assertion should lose any trust. * */ void lasso_saml2_assertion_set_basic_conditions(LassoSaml2Assertion *saml2_assertion, time_t tolerance, time_t length, gboolean one_time_use) { LassoSaml2Conditions *saml2_conditions; g_return_if_fail (LASSO_IS_SAML2_ASSERTION (saml2_assertion)); saml2_conditions = lasso_saml2_assertion_get_conditions (saml2_assertion, TRUE); set_notbefore_and_notonorafter (saml2_assertion->Conditions, tolerance, length); lasso_saml2_assertion_set_one_time_use(saml2_assertion, one_time_use); } /** * lasso_saml2_assertion_set_one_time_use: * @saml2_assertion: a #LassoSaml2Assertion object * @one_time_use: is this assertion to be used one time only ? * * Set the one time use condition on this assertion. */ void lasso_saml2_assertion_set_one_time_use(LassoSaml2Assertion *saml2_assertion, gboolean one_time_use) { LassoSaml2Conditions * saml2_conditions; g_return_if_fail (LASSO_IS_SAML2_ASSERTION (saml2_assertion)); saml2_conditions = lasso_saml2_assertion_get_conditions(saml2_assertion, TRUE); lasso_list_add_new_gobject (saml2_conditions->OneTimeUse, lasso_saml2_one_time_use_new()); if (one_time_use) { lasso_list_add_new_gobject(saml2_conditions->OneTimeUse, lasso_saml2_one_time_use_new()); } else { lasso_release_list_of_gobjects(saml2_conditions->OneTimeUse); } } /** * lasso_saml2_assertion_add_audience_restriction: * @saml2_assertion: a #LassoSaml2Assertion object * @providerId: the provider id to restrict audience to * * Add an audience restriction to a #LassoSaml2Assertion. * */ void lasso_saml2_assertion_add_audience_restriction(LassoSaml2Assertion *saml2_assertion, const char *providerID) { LassoSaml2AudienceRestriction *audience_restriction; LassoSaml2Conditions *conditions; g_return_if_fail (LASSO_IS_SAML2_ASSERTION(saml2_assertion)); conditions = lasso_saml2_assertion_get_conditions (saml2_assertion, TRUE); audience_restriction = (LassoSaml2AudienceRestriction*) lasso_saml2_audience_restriction_new(); lasso_assign_string(audience_restriction->Audience, providerID); lasso_list_add_new_gobject(conditions->AudienceRestriction, audience_restriction); } /** * lasso_saml2_assertion_add_proxy_limit: * @saml2_assertion: a #LassoSaml2Assertion object * @proxy_count:(default -1): the number of hops in the proxy chain, a negative value means no limitation * @proxy_audiences:(allow-none)(element-type string): a list of audience restriction for newly issued assertion * based on the @saml2_assertion assertion. An empty list means no audience restriction. * * A #LassoSaml2ProxyRestriction to the conditions of consumption of @saml2_assertion. */ void lasso_saml2_assertion_add_proxy_limit (LassoSaml2Assertion *saml2_assertion, int proxy_count, GList *proxy_audiences) { LassoSaml2Conditions *saml2_conditions; LassoSaml2ProxyRestriction *saml2_proxy_restriction; g_return_if_fail (LASSO_IS_SAML2_ASSERTION (saml2_assertion)); saml2_conditions = lasso_saml2_assertion_get_conditions (saml2_assertion, TRUE); saml2_proxy_restriction = (LassoSaml2ProxyRestriction*)lasso_saml2_proxy_restriction_new (); if (proxy_count >= 0) { saml2_proxy_restriction->Count = g_strdup_printf("%i", proxy_count); } if (proxy_audiences) { lasso_assign_string (saml2_proxy_restriction->Audience, proxy_audiences->data); if (proxy_audiences->next) { message(G_LOG_LEVEL_WARNING, "Trying to set multiple proxy_audience restriction is not possible with currrent version of Lasso"); } } } /** * lasso_saml2_assertion_validate_time_checks: * @saml2_assertion: a #LassoSaml2Assertion object * @tolerance: a duration as seconds * @now:(default 0): the current time as seconds since EPOCH or 0 to use the system time. * * Check if the @saml2_assertion conditions about NotBefore and NotOnOrAfter are valid with respect * to the @now time or the current time. @tolerance allows to loosely check for validatity, i.e. * start time is decreased of @tolerance seconds and end time is increased of @tolerance seconds. * * Return value: a value among #LassoSaml2AssertionValidationState. */ LassoSaml2AssertionValidationState lasso_saml2_assertion_validate_time_checks(LassoSaml2Assertion *saml2_assertion, unsigned int tolerance, time_t now) { LassoSaml2Conditions *saml2_conditions; g_return_val_if_fail (LASSO_SAML2_ASSERTION (saml2_assertion), LASSO_SAML2_ASSERTION_INDETERMINATE); saml2_conditions = lasso_saml2_assertion_get_conditions(saml2_assertion, FALSE); if (saml2_conditions == NULL) return LASSO_SAML2_ASSERTION_VALID; if (now == 0) now = time(NULL); if (saml2_conditions->NotBefore) { time_t a = lasso_iso_8601_gmt_to_time_t (saml2_conditions->NotBefore); a -= tolerance; if (a == -1) return LASSO_SAML2_ASSERTION_INDETERMINATE; if (now < a) { return LASSO_SAML2_ASSERTION_INVALID; } } if (saml2_conditions->NotOnOrAfter) { time_t b = lasso_iso_8601_gmt_to_time_t (saml2_conditions->NotOnOrAfter); b += tolerance; if (b == -1) return LASSO_SAML2_ASSERTION_INDETERMINATE; if (now >= b) { return LASSO_SAML2_ASSERTION_INVALID; } } return LASSO_SAML2_ASSERTION_VALID; } /** * lasso_saml2_assertion_has_one_time_use: * @saml2_assertion: a #LassoSaml2Assertion object * * Return whether this assertion has the OneTimeUse property. * * In this case the relaying party must add the assertion ID to a OneTimeUser cache and discards any * assertion received in the future with the same ID. * * Return value: TRUE if this assertion has the property OneTimeUse, FALSE otherwise. */ gboolean lasso_saml2_assertion_has_one_time_use(LassoSaml2Assertion *saml2_assertion) { LassoSaml2Conditions *saml2_conditions; g_return_val_if_fail (LASSO_SAML2_ASSERTION (saml2_assertion), FALSE); saml2_conditions = lasso_saml2_assertion_get_conditions(saml2_assertion, FALSE); if (saml2_conditions == NULL) return FALSE; if (saml2_conditions->OneTimeUse) return TRUE; return FALSE; } /** * lasso_saml2_assertion_allows_proxying: * @saml2_assertion: a #LassoSaml2Assertion object * * Test whether this @saml2_assertion allows to mint new assertion on the basis of it. * It verifies that the proxying count is positive (or absent). * * Return value: a value among #LassoSaml2AssertionValidationState enumeration. * #LASSO_SAML2_ASSERTION_INDETERMINATE usually means that an element was not conform to the XML * Schema for SAML 2.0. */ LassoSaml2AssertionValidationState lasso_saml2_assertion_allows_proxying(LassoSaml2Assertion *saml2_assertion) { LassoSaml2Conditions *saml2_conditions; LassoSaml2ProxyRestriction *proxy_restriction; g_return_val_if_fail (LASSO_SAML2_ASSERTION (saml2_assertion), LASSO_SAML2_ASSERTION_INDETERMINATE); saml2_conditions = lasso_saml2_assertion_get_conditions(saml2_assertion, FALSE); if (saml2_conditions == NULL) return LASSO_SAML2_ASSERTION_VALID; if (! saml2_conditions->ProxyRestriction) return LASSO_SAML2_ASSERTION_VALID; if (! LASSO_IS_SAML2_PROXY_RESTRICTION(saml2_conditions->ProxyRestriction->data) || saml2_conditions->ProxyRestriction->next) return LASSO_SAML2_ASSERTION_INDETERMINATE; proxy_restriction = saml2_conditions->ProxyRestriction->data; if (proxy_restriction == NULL) return LASSO_SAML2_ASSERTION_VALID; if (proxy_restriction->Count) { long int count; if (! lasso_string_to_xsd_integer(proxy_restriction->Count, &count) || count < 0) { return LASSO_SAML2_ASSERTION_INDETERMINATE; } if (count == 0) { return LASSO_SAML2_ASSERTION_INVALID; } } return LASSO_SAML2_ASSERTION_VALID; } /** * lasso_saml2_assertion_allows_proxying_to: * @saml2_assertion: a #LassoSaml2Assertion object * @audience:(allow-none): the relaying party which we want to proxy to * * Test whether this @saml2_assertion allows to mint new assertion on the basis of it targetted for * @audience. It verifies that if @audience is * non-NULL it is part of the proxy Audience restriction. If @audience is NULL, it checks that no * proxying Audience restriction is present. * * Return value: a value among #LassoSaml2AssertionValidationState enumeration. * #LASSO_SAML2_ASSERTION_INDETERMINATE usually means that an element was not conform to the XML * Schema for SAML 2.0. */ LassoSaml2AssertionValidationState lasso_saml2_assertion_allows_proxying_to(LassoSaml2Assertion *saml2_assertion, const char *audience) { LassoSaml2Conditions *saml2_conditions; LassoSaml2ProxyRestriction *proxy_restriction; g_return_val_if_fail (LASSO_SAML2_ASSERTION (saml2_assertion), LASSO_SAML2_ASSERTION_INDETERMINATE); saml2_conditions = lasso_saml2_assertion_get_conditions(saml2_assertion, FALSE); if (saml2_conditions == NULL) return LASSO_SAML2_ASSERTION_VALID; if (! saml2_conditions->ProxyRestriction) return LASSO_SAML2_ASSERTION_VALID; if (! LASSO_IS_SAML2_PROXY_RESTRICTION(saml2_conditions->ProxyRestriction->data) || saml2_conditions->ProxyRestriction->next) return LASSO_SAML2_ASSERTION_INDETERMINATE; proxy_restriction = saml2_conditions->ProxyRestriction->data; if (proxy_restriction == NULL) return LASSO_SAML2_ASSERTION_VALID; /* FIXME: Change saml2:ProxyRestriction class */ if (lasso_strisnotequal(proxy_restriction->Audience,audience)) { return LASSO_SAML2_ASSERTION_INVALID; } return LASSO_SAML2_ASSERTION_VALID; } /** * lasso_saml2_assertion_validate_audience: * @saml2_assertion: a #LassoSaml2Assertion object * @audience: the name of an entity * * Check if the @saml2_assertion is directed to a given @audience. * * Return value: a value among #LassoSaml2AssertionValidationState enumeration. */ LassoSaml2AssertionValidationState lasso_saml2_assertion_validate_audience(LassoSaml2Assertion *saml2_assertion, const gchar *audience) { LassoSaml2Conditions *saml2_conditions; gboolean did_audience = FALSE; gboolean found_audience = FALSE; g_return_val_if_fail (LASSO_SAML2_ASSERTION (saml2_assertion), LASSO_SAML2_ASSERTION_INDETERMINATE); saml2_conditions = lasso_saml2_assertion_get_conditions(saml2_assertion, FALSE); if (saml2_conditions == NULL) return LASSO_SAML2_ASSERTION_VALID; lasso_foreach_full_begin (LassoSaml2AudienceRestriction*, saml2_audience_restriction, it, saml2_conditions->AudienceRestriction) did_audience = TRUE; if (lasso_strisequal(saml2_audience_restriction->Audience,audience)) { found_audience = TRUE; } lasso_foreach_full_end() if (did_audience && ! found_audience) { return LASSO_SAML2_ASSERTION_INVALID; } return LASSO_SAML2_ASSERTION_VALID; } /** * lasso_saml2_assertion_validate_conditions: * @saml2_assertion: a #LassoSaml2Assertion object * @relaying_party_providerID:(allow-none): the providerID of the current relaying party, use to * check for audience restrictions. * * Check the validation of the assertion with respect to the conditions of consumption that it * contains. System functions are used for getting current time and checking eventual time * constraints. * * Return value: LASSO_SAML2_ASSERTION_VALID if the assertion is valid, * LASSO_SAML2_ASSERTION_INVALID is some check failed, LASSO_SAML2_ASSERTION_INDETERMINATE if * somehting was impossible to eveluate. */ LassoSaml2AssertionValidationState lasso_saml2_assertion_validate_conditions(LassoSaml2Assertion *saml2_assertion, const char *relaying_party_providerID) { LassoSaml2AssertionValidationState state; state = lasso_saml2_assertion_validate_time_checks(saml2_assertion, 0, 0); if (state != LASSO_SAML2_ASSERTION_VALID) return state; state = lasso_saml2_assertion_validate_audience(saml2_assertion, relaying_party_providerID); return state; } /** * lasso_saml2_assertion_get_issuer_provider: * @saml2_assertion: a #LassoSaml2 assertion * @server: a #LassoServer object * * Return the #LassoProvider object for the provider who created this assertion. * * Return value: a #LassoProvider object, or NULL if the Issuer element is missing, or the given * provider unknown to the #LassoServer object. */ LassoProvider* lasso_saml2_assertion_get_issuer_provider(const LassoSaml2Assertion *saml2_assertion, const LassoServer *server) { LassoSaml2NameID *issuer; g_return_val_if_fail (LASSO_IS_SAML2_ASSERTION (saml2_assertion), NULL); issuer = saml2_assertion->Issuer; g_return_val_if_fail (LASSO_IS_SAML2_NAME_ID (issuer), NULL); g_return_val_if_fail (issuer->Format == NULL || lasso_strisequal(issuer->Format,LASSO_SAML2_NAME_IDENTIFIER_FORMAT_ENTITY), NULL); g_return_val_if_fail (LASSO_IS_SERVER(server), NULL); if (lasso_strisequal(server->parent.ProviderID,issuer->content)) { return (LassoProvider*)&server->parent; } return lasso_server_get_provider (server, issuer->content); } /** * lasso_server_saml2_assertion_setup_signature: * @server: a #LassoServer object * @saml2_assertion: a #LassoSaml2Assertion object * * Configure signature on a saml2:Assertion element. * * Return value: 0 if successfull, an error code otherwise. */ int lasso_server_saml2_assertion_setup_signature(LassoServer *server, LassoSaml2Assertion *saml2_assertion) { LassoSignatureContext context = LASSO_SIGNATURE_CONTEXT_NONE; GList *audience_restrictions = NULL; char *provider_id = NULL; lasso_error_t rc = 0; lasso_bad_param(SERVER, server); lasso_bad_param(SAML2_ASSERTION, saml2_assertion); /* instead of this we should probably allow to pass a provider id or object in a new API */ audience_restrictions = lasso_saml2_assertion_get_audience_restrictions(saml2_assertion); if (audience_restrictions) { provider_id = ((LassoSaml2AudienceRestriction*)audience_restrictions->data)->Audience; } lasso_check_good_rc(lasso_server_get_signature_context_for_provider_by_name(server, provider_id, &context)); lasso_node_set_signature(&saml2_assertion->parent, context); if (! saml2_assertion->ID) { lasso_assign_new_string(saml2_assertion->ID, lasso_build_unique_id(32)); } cleanup: return rc; } /** * lasso_saml2_assertion_add_attribute_with_node: * @assertion: a #LassoSaml2Assertion object * @name: the attribute name * @name_format: the attribute name format (the namespace of the name) * @content: a #LassoNode object to put as content of the attribute * * Add a new attribute declaration and set this node as the content. * * Return value: 0 if successful, an error code otherwise. */ int lasso_saml2_assertion_add_attribute_with_node(LassoSaml2Assertion *assertion, const char *name, const char *name_format, LassoNode *content) { LassoSaml2AttributeValue *attribute_value = NULL; LassoSaml2Attribute *attribute = NULL; LassoSaml2AttributeStatement *attribute_statement = NULL; int rc = 0; lasso_bad_param(SAML2_ASSERTION, assertion); lasso_check_non_empty_string(name); lasso_check_non_empty_string(name_format); lasso_bad_param(NODE, content); attribute_value = lasso_saml2_attribute_value_new(); lasso_list_add_gobject(attribute_value->any, content); attribute = LASSO_SAML2_ATTRIBUTE(lasso_saml2_attribute_new()); lasso_assign_string(attribute->Name, name); lasso_assign_string(attribute->NameFormat, LASSO_SAML2_ATTRIBUTE_NAME_FORMAT_URI); lasso_list_add_new_gobject(attribute->AttributeValue, attribute_value); if (assertion->AttributeStatement && LASSO_IS_SAML2_ATTRIBUTE_STATEMENT( assertion->AttributeStatement->data)) { attribute_statement = (LassoSaml2AttributeStatement*) assertion->AttributeStatement->data; } else { attribute_statement = LASSO_SAML2_ATTRIBUTE_STATEMENT(lasso_saml2_attribute_statement_new()); lasso_list_add_new_gobject(assertion->AttributeStatement, attribute_statement); } lasso_list_add_new_gobject(attribute_statement->Attribute, attribute); cleanup: return rc; } /** * lasso_saml2_assertion_get_in_response_to: * @assertion: a #LassoSaml2Assertion object * * Return the ID of the request this assertion respond to. * * Return value: the InResponseTo attribute content of the SubjectConfirmationData if found */ const char* lasso_saml2_assertion_get_in_response_to(LassoSaml2Assertion *assertion) { LassoSaml2SubjectConfirmationData *scd; scd = lasso_saml2_assertion_get_subject_confirmation_data(assertion, FALSE); if (! scd) return NULL; return scd->InResponseTo; } /** * lasso_saml2_encrypted_element_server_decrypt: * @encrypted_element: a #LassoSaml2EncryptedElement object * @server: a #LassoServer object * @decrypted_node:(out): an output arg for a #LassoNode * * Decrypt the given encrypted element using the encryption private key of the @server object * * Return value: 0 if successful, an error code otherwise. See * lasso_saml2_encrypted_element_server_decrypt(). */ int lasso_saml2_encrypted_element_server_decrypt(LassoSaml2EncryptedElement* encrypted_element, LassoServer *server, LassoNode** decrypted_node) { lasso_bad_param(SERVER, server); int rc = 0; GList *encryption_private_keys; encryption_private_keys = lasso_server_get_encryption_private_keys(server); if (! encryption_private_keys) { return LASSO_PROFILE_ERROR_MISSING_ENCRYPTION_PRIVATE_KEY; } lasso_foreach_full_begin(xmlSecKey*, encryption_private_key, it, encryption_private_keys) { rc = lasso_saml2_encrypted_element_decrypt(encrypted_element, encryption_private_key, decrypted_node); if (rc == 0) break; } lasso_foreach_full_end(); return rc; } /** * lasso_saml2_assertion_decrypt_subject: * @assertion: a #LassoSaml2Assertion object * @server: a #LassoServer object * * Decipher (if needed) the EncryptedID of the Subject. * * Return value: 0 if successful, an error code otherwise. See * lasso_saml2_encrypted_element_server_decrypt(). */ int lasso_saml2_assertion_decrypt_subject(LassoSaml2Assertion *assertion, LassoServer *server) { lasso_bad_param(SAML2_ASSERTION, assertion); lasso_bad_param(SERVER, server); if (assertion->Subject && ! assertion->Subject->NameID && assertion->Subject->EncryptedID) { return lasso_saml2_encrypted_element_server_decrypt(assertion->Subject->EncryptedID, server, (LassoNode**)&assertion->Subject->NameID); } return 0; } /** * lasso_saml2_assertion_get_audience_restrictions: * @assertion: a #LassoSaml2Assertion * * Returns the list of audience restriction associated to the given assertion * * Return value:(transfer none): the GList of the Saml2AudienceRestriction nodes */ static GList* lasso_saml2_assertion_get_audience_restrictions(LassoSaml2Assertion *assertion) { g_return_val_if_fail (LASSO_IS_SAML2_ASSERTION(assertion), NULL); if (! LASSO_IS_SAML2_CONDITIONS(assertion->Conditions)) return FALSE; return assertion->Conditions->AudienceRestriction; }