Blame lasso/saml-2.0/login.c

Packit Service 88ab54
/* $Id$
Packit Service 88ab54
 *
Packit Service 88ab54
 * Lasso - A free implementation of the Liberty Alliance specifications.
Packit Service 88ab54
 *
Packit Service 88ab54
 * Copyright (C) 2004-2007 Entr'ouvert
Packit Service 88ab54
 * http://lasso.entrouvert.org
Packit Service 88ab54
 *
Packit Service 88ab54
 * Authors: See AUTHORS file in top-level directory.
Packit Service 88ab54
 *
Packit Service 88ab54
 * This program is free software; you can redistribute it and/or modify
Packit Service 88ab54
 * it under the terms of the GNU General Public License as published by
Packit Service 88ab54
 * the Free Software Foundation; either version 2 of the License, or
Packit Service 88ab54
 * (at your option) any later version.
Packit Service 88ab54
 *
Packit Service 88ab54
 * This program is distributed in the hope that it will be useful,
Packit Service 88ab54
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 88ab54
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 88ab54
 * GNU General Public License for more details.
Packit Service 88ab54
 *
Packit Service 88ab54
 * You should have received a copy of the GNU General Public License
Packit Service 88ab54
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
Packit Service 88ab54
 */
Packit Service 88ab54
Packit Service 88ab54
#include "../xml/private.h"
Packit Service 88ab54
#include <libxml/xpath.h>
Packit Service 88ab54
#include <libxml/xpathInternals.h>
Packit Service 88ab54
Packit Service 88ab54
#include "providerprivate.h"
Packit Service 88ab54
#include "loginprivate.h"
Packit Service 88ab54
#include "profileprivate.h"
Packit Service 88ab54
#include "federationprivate.h"
Packit Service 88ab54
#include "saml2_helper.h"
Packit Service 88ab54
Packit Service 88ab54
#include "../id-ff/providerprivate.h"
Packit Service 88ab54
#include "../id-ff/serverprivate.h"
Packit Service 88ab54
#include "../id-ff/login.h"
Packit Service 88ab54
#include "../id-ff/identityprivate.h"
Packit Service 88ab54
#include "../id-ff/sessionprivate.h"
Packit Service 88ab54
#include "../id-ff/loginprivate.h"
Packit Service 88ab54
Packit Service 88ab54
#include "../xml/ecp/ecp_relaystate.h"
Packit Service 88ab54
#include "../xml/paos_response.h"
Packit Service 88ab54
Packit Service 88ab54
#include "../xml/xml_enc.h"
Packit Service 88ab54
Packit Service 88ab54
#include "../xml/saml-2.0/samlp2_authn_request.h"
Packit Service 88ab54
#include "../xml/saml-2.0/samlp2_response.h"
Packit Service 88ab54
#include "../xml/saml-2.0/saml2_assertion.h"
Packit Service 88ab54
#include "../xml/saml-2.0/saml2_audience_restriction.h"
Packit Service 88ab54
#include "../xml/saml-2.0/saml2_authn_statement.h"
Packit Service 88ab54
#include "../xml/saml-2.0/saml2_encrypted_element.h"
Packit Service 88ab54
#include "../xml/saml-2.0/saml2_attribute.h"
Packit Service 88ab54
#include "../xml/saml-2.0/saml2_attribute_statement.h"
Packit Service 88ab54
#include "../xml/saml-2.0/saml2_attribute_value.h"
Packit Service 88ab54
#include "../xml/saml-2.0/saml2_name_id.h"
Packit Service 88ab54
#include "../xml/saml-2.0/saml2_xsd.h"
Packit Service 88ab54
#include "../xml/saml-2.0/samlp2_artifact_response.h"
Packit Service 88ab54
Packit Service 88ab54
#include "../utils.h"
Packit Service 88ab54
Packit Service 88ab54
static int lasso_saml20_login_process_federation(LassoLogin *login, gboolean is_consent_obtained);
Packit Service 88ab54
static gboolean lasso_saml20_login_must_ask_for_consent_private(LassoLogin *login);
Packit Service 88ab54
static gint lasso_saml20_login_process_response_status_and_assertion(LassoLogin *login);
Packit Service 88ab54
static char* lasso_saml20_login_get_assertion_consumer_service_url(LassoLogin *login,
Packit Service 88ab54
		LassoProvider *remote_provider);
Packit Service 88ab54
static gboolean _lasso_login_must_verify_signature(LassoProfile *profile) G_GNUC_UNUSED;
Packit Service 88ab54
static gboolean _lasso_login_must_verify_authn_request_signature(LassoProfile *profile);
Packit Service 88ab54
Packit Service 88ab54
/* No need to check type of arguments, it has been done in lasso_login_* methods */
Packit Service 88ab54
Packit Service 88ab54
gint
Packit Service 88ab54
lasso_saml20_login_init_authn_request(LassoLogin *login, LassoHttpMethod http_method)
Packit Service 88ab54
{
Packit Service 88ab54
	LassoProfile *profile = NULL;
Packit Service 88ab54
	LassoSamlp2RequestAbstract *request = NULL;
Packit Service 88ab54
	gchar *default_name_id_format = NULL;
Packit Service 88ab54
	int rc = 0;
Packit Service 88ab54
Packit Service 88ab54
	profile = &login->parent;
Packit Service 88ab54
Packit Service 88ab54
	/* new */
Packit Service 88ab54
	request = (LassoSamlp2RequestAbstract*)lasso_samlp2_authn_request_new();
Packit Service 88ab54
	lasso_check_good_rc(lasso_saml20_profile_init_request(profile, profile->remote_providerID, FALSE,
Packit Service 88ab54
				request, http_method, LASSO_MD_PROTOCOL_TYPE_SINGLE_SIGN_ON));
Packit Service 88ab54
Packit Service 88ab54
	/* FIXME: keep old behaviour */
Packit Service 88ab54
	login->http_method = login->parent.http_request_method;
Packit Service 88ab54
Packit Service 88ab54
	/* save request ID, for later check */
Packit Service 88ab54
	lasso_assign_string(login->private_data->request_id, request->ID);
Packit Service 88ab54
	/* set name id policy */
Packit Service 88ab54
	lasso_assign_new_gobject(LASSO_SAMLP2_AUTHN_REQUEST(request)->NameIDPolicy,
Packit Service 88ab54
			lasso_samlp2_name_id_policy_new());
Packit Service 88ab54
	/* set name id policy format */
Packit Service 88ab54
	/* no need to check server, done in init_request */
Packit Service 88ab54
	default_name_id_format = lasso_provider_get_metadata_one_for_role(&profile->server->parent,
Packit Service 88ab54
			LASSO_PROVIDER_ROLE_SP, "NameIDFormat");
Packit Service 88ab54
	if (default_name_id_format) {
Packit Service 88ab54
		/* steal the string */
Packit Service 88ab54
		lasso_assign_new_string(LASSO_SAMLP2_AUTHN_REQUEST(request)->NameIDPolicy->Format,
Packit Service 88ab54
				default_name_id_format);
Packit Service 88ab54
	} else {
Packit Service 88ab54
		lasso_assign_string(LASSO_SAMLP2_AUTHN_REQUEST(request)->NameIDPolicy->Format,
Packit Service 88ab54
			LASSO_SAML2_NAME_IDENTIFIER_FORMAT_TRANSIENT);
Packit Service 88ab54
	}
Packit Service 88ab54
Packit Service 88ab54
cleanup:
Packit Service 88ab54
	lasso_release_gobject(request);
Packit Service 88ab54
	return rc;
Packit Service 88ab54
}
Packit Service 88ab54
Packit Service 88ab54
static gboolean want_authn_request_signed(LassoProvider *provider) {
Packit Service 88ab54
	char *s;
Packit Service 88ab54
	gboolean rc = FALSE;
Packit Service 88ab54
Packit Service 88ab54
	s = lasso_provider_get_metadata_one_for_role(provider, LASSO_PROVIDER_ROLE_IDP,
Packit Service 88ab54
			LASSO_SAML2_METADATA_ATTRIBUTE_WANT_AUTHN_REQUEST_SIGNED);
Packit Service 88ab54
	if (lasso_strisequal(s,"false")) {
Packit Service 88ab54
		rc = FALSE;
Packit Service 88ab54
	}
Packit Service 88ab54
	lasso_release_string(s);
Packit Service 88ab54
	return rc;
Packit Service 88ab54
}
Packit Service 88ab54
Packit Service 88ab54
static gboolean authn_request_signed(LassoProvider *provider) {
Packit Service 88ab54
	char *s;
Packit Service 88ab54
	gboolean rc = FALSE;
Packit Service 88ab54
Packit Service 88ab54
	s = lasso_provider_get_metadata_one_for_role(provider, LASSO_PROVIDER_ROLE_SP,
Packit Service 88ab54
			LASSO_SAML2_METADATA_ATTRIBUTE_AUTHN_REQUEST_SIGNED);
Packit Service 88ab54
	if (lasso_strisequal(s,"true")) {
Packit Service 88ab54
		rc = TRUE;
Packit Service 88ab54
	}
Packit Service 88ab54
	lasso_release_string(s);
Packit Service 88ab54
	return rc;
Packit Service 88ab54
}
Packit Service 88ab54
Packit Service 88ab54
static gboolean
Packit Service 88ab54
_lasso_login_must_sign_non_authn_request(LassoLogin *profile)
Packit Service 88ab54
{
Packit Service 88ab54
	switch (lasso_profile_get_signature_hint(&profile->parent)) {
Packit Service 88ab54
		case LASSO_PROFILE_SIGNATURE_HINT_MAYBE:
Packit Service 88ab54
			return lasso_flag_add_signature;
Packit Service 88ab54
		case LASSO_PROFILE_SIGNATURE_HINT_FORCE:
Packit Service 88ab54
			return TRUE;
Packit Service 88ab54
		case LASSO_PROFILE_SIGNATURE_HINT_FORBID:
Packit Service 88ab54
			return FALSE;
Packit Service 88ab54
		default:
Packit Service 88ab54
			return TRUE;
Packit Service 88ab54
	}
Packit Service 88ab54
}
Packit Service 88ab54
Packit Service 88ab54
static gboolean
Packit Service 88ab54
_lasso_login_must_sign(LassoProfile *profile)
Packit Service 88ab54
{
Packit Service 88ab54
	gboolean ret;
Packit Service 88ab54
	LassoProvider *remote_provider;
Packit Service 88ab54
Packit Service 88ab54
	remote_provider = lasso_server_get_provider(profile->server,
Packit Service 88ab54
			profile->remote_providerID);
Packit Service 88ab54
Packit Service 88ab54
	switch (lasso_profile_get_signature_hint(profile)) {
Packit Service 88ab54
		case LASSO_PROFILE_SIGNATURE_HINT_MAYBE:
Packit Service 88ab54
			/* If our metadatas say that we sign, then we sign,
Packit Service 88ab54
			 * If the IdP says that he wants our signature, then we sign
Packit Service 88ab54
			 * Otherwise we do not.
Packit Service 88ab54
			 */
Packit Service 88ab54
			ret = authn_request_signed(&profile->server->parent)
Packit Service 88ab54
				|| want_authn_request_signed(remote_provider);
Packit Service 88ab54
			return ret;
Packit Service 88ab54
		case LASSO_PROFILE_SIGNATURE_HINT_FORCE:
Packit Service 88ab54
			return TRUE;
Packit Service 88ab54
		case LASSO_PROFILE_SIGNATURE_HINT_FORBID:
Packit Service 88ab54
			return FALSE;
Packit Service 88ab54
	}
Packit Service 88ab54
	g_assert(0);
Packit Service 88ab54
	return TRUE;
Packit Service 88ab54
}
Packit Service 88ab54
Packit Service 88ab54
static gboolean
Packit Service 88ab54
_lasso_login_must_verify_authn_request_signature(LassoProfile *profile) {
Packit Service 88ab54
	LassoProvider *remote_provider;
Packit Service 88ab54
Packit Service 88ab54
	remote_provider = lasso_server_get_provider(profile->server,
Packit Service 88ab54
			profile->remote_providerID);
Packit Service 88ab54
Packit Service 88ab54
	switch (lasso_profile_get_signature_verify_hint(profile)) {
Packit Service 88ab54
			/* If our metadatas say that we want signature, then we verify,
Packit Service 88ab54
			 * If the SP says that he signs, then we verify
Packit Service 88ab54
			 * Otherwise we do not.
Packit Service 88ab54
			 */
Packit Service 88ab54
		case LASSO_PROFILE_SIGNATURE_VERIFY_HINT_MAYBE:
Packit Service 88ab54
			return want_authn_request_signed(&profile->server->parent) ||
Packit Service 88ab54
				authn_request_signed(remote_provider);
Packit Service 88ab54
		case LASSO_PROFILE_SIGNATURE_VERIFY_HINT_IGNORE:
Packit Service 88ab54
			return FALSE;
Packit Service 88ab54
		case LASSO_PROFILE_SIGNATURE_VERIFY_HINT_FORCE:
Packit Service 88ab54
			return TRUE;
Packit Service 88ab54
		case LASSO_PROFILE_SIGNATURE_VERIFY_HINT_LAST:
Packit Service 88ab54
			break;
Packit Service 88ab54
	}
Packit Service 88ab54
	g_assert(0);
Packit Service 88ab54
	return TRUE;
Packit Service 88ab54
}
Packit Service 88ab54
Packit Service 88ab54
static gboolean
Packit Service 88ab54
_lasso_login_must_verify_signature(LassoProfile *profile) {
Packit Service 88ab54
	switch (lasso_profile_get_signature_verify_hint(profile)) {
Packit Service 88ab54
		case LASSO_PROFILE_SIGNATURE_VERIFY_HINT_MAYBE:
Packit Service 88ab54
			return lasso_flag_verify_signature;
Packit Service 88ab54
		case LASSO_PROFILE_SIGNATURE_VERIFY_HINT_IGNORE:
Packit Service 88ab54
			return FALSE;
Packit Service 88ab54
		case LASSO_PROFILE_SIGNATURE_VERIFY_HINT_FORCE:
Packit Service 88ab54
			return TRUE;
Packit Service 88ab54
		case LASSO_PROFILE_SIGNATURE_VERIFY_HINT_LAST:
Packit Service 88ab54
			break;
Packit Service 88ab54
	}
Packit Service 88ab54
	g_assert(0);
Packit Service 88ab54
	return TRUE;
Packit Service 88ab54
}
Packit Service 88ab54
Packit Service 88ab54
gint
Packit Service 88ab54
lasso_saml20_login_build_authn_request_msg(LassoLogin *login)
Packit Service 88ab54
{
Packit Service 88ab54
	char *url = NULL;
Packit Service 88ab54
	gboolean must_sign = TRUE;
Packit Service 88ab54
	LassoProfile *profile;
Packit Service 88ab54
	LassoSamlp2AuthnRequest *authn_request;
Packit Service 88ab54
	int rc = 0;
Packit Service 88ab54
Packit Service 88ab54
	profile = &login->parent;
Packit Service 88ab54
Packit Service 88ab54
	lasso_extract_node_or_fail(authn_request, profile->request, SAMLP2_AUTHN_REQUEST,
Packit Service 88ab54
			LASSO_PROFILE_ERROR_INVALID_REQUEST);
Packit Service 88ab54
Packit Service 88ab54
	/* default is to sign ! */
Packit Service 88ab54
	must_sign = _lasso_login_must_sign(profile);
Packit Service 88ab54
Packit Service 88ab54
	if (! must_sign) {
Packit Service 88ab54
		lasso_node_remove_signature(profile->request);
Packit Service 88ab54
	}
Packit Service 88ab54
Packit Service 88ab54
	/* support old way of doing PAOS */
Packit Service 88ab54
	if (login->http_method == LASSO_HTTP_METHOD_SOAP
Packit Service 88ab54
			&& lasso_strisequal(authn_request->ProtocolBinding,LASSO_SAML2_METADATA_BINDING_PAOS)) {
Packit Service 88ab54
		login->http_method = LASSO_HTTP_METHOD_PAOS;
Packit Service 88ab54
	}
Packit Service 88ab54
Packit Service 88ab54
	if (login->http_method == LASSO_HTTP_METHOD_PAOS) {
Packit Service 88ab54
Packit Service 88ab54
		/*
Packit Service 88ab54
		 * PAOS is special, the url passed to build_request is the
Packit Service 88ab54
		 * AssertionConsumerServiceURL of this SP, not the
Packit Service 88ab54
		 * destination.
Packit Service 88ab54
		 */
Packit Service 88ab54
		if (authn_request->AssertionConsumerServiceURL) {
Packit Service 88ab54
			url = authn_request->AssertionConsumerServiceURL;
Packit Service 88ab54
			if (!lasso_saml20_provider_check_assertion_consumer_service_url(
Packit Service 88ab54
					LASSO_PROVIDER(profile->server), url, LASSO_SAML2_METADATA_BINDING_PAOS)) {
Packit Service 88ab54
				rc = LASSO_PROFILE_ERROR_INVALID_REQUEST;
Packit Service 88ab54
				goto cleanup;
Packit Service 88ab54
			}
Packit Service 88ab54
		} else {
Packit Service 88ab54
			url = lasso_saml20_provider_get_assertion_consumer_service_url_by_binding(
Packit Service 88ab54
					LASSO_PROVIDER(profile->server), LASSO_SAML2_METADATA_BINDING_PAOS);
Packit Service 88ab54
			lasso_assign_new_string(authn_request->AssertionConsumerServiceURL, url);
Packit Service 88ab54
		}
Packit Service 88ab54
	}
Packit Service 88ab54
Packit Service 88ab54
Packit Service 88ab54
	lasso_check_good_rc(lasso_saml20_profile_build_request_msg(profile, "SingleSignOnService",
Packit Service 88ab54
				login->http_method, url));
Packit Service 88ab54
Packit Service 88ab54
cleanup:
Packit Service 88ab54
	return rc;
Packit Service 88ab54
}
Packit Service 88ab54
Packit Service 88ab54
int
Packit Service 88ab54
lasso_saml20_login_process_authn_request_msg(LassoLogin *login, const char *authn_request_msg)
Packit Service 88ab54
{
Packit Service 88ab54
	LassoNode *request = NULL;
Packit Service 88ab54
	LassoProfile *profile = LASSO_PROFILE(login);
Packit Service 88ab54
	LassoSamlp2StatusResponse *response = NULL;
Packit Service 88ab54
	LassoSamlp2AuthnRequest *authn_request = NULL;
Packit Service 88ab54
	LassoProvider *remote_provider = NULL;
Packit Service 88ab54
	LassoServer *server = NULL;
Packit Service 88ab54
	const gchar *protocol_binding = NULL;
Packit Service 88ab54
	const char *status1 = LASSO_SAML2_STATUS_CODE_RESPONDER;
Packit Service 88ab54
	const char *status2 = NULL;
Packit Service 88ab54
	int rc = 0;
Packit Service 88ab54
Packit Service 88ab54
	if (authn_request_msg == NULL) {
Packit Service 88ab54
		if (profile->request == NULL) {
Packit Service 88ab54
			return critical_error(LASSO_PROFILE_ERROR_MISSING_REQUEST);
Packit Service 88ab54
		}
Packit Service 88ab54
Packit Service 88ab54
		/* AuthnRequest already set by .._init_idp_initiated_authn_request, or from a
Packit Service 88ab54
		 * previously failed call to process_authn_request that we retry. */
Packit Service 88ab54
		request = lasso_ref(profile->request);
Packit Service 88ab54
	} else {
Packit Service 88ab54
		request = lasso_samlp2_authn_request_new();
Packit Service 88ab54
		lasso_check_good_rc(lasso_saml20_profile_process_any_request(profile, request, authn_request_msg));
Packit Service 88ab54
	}
Packit Service 88ab54
	if (! LASSO_IS_SAMLP2_AUTHN_REQUEST(request)) {
Packit Service 88ab54
		return critical_error(LASSO_PROFILE_ERROR_INVALID_MSG);
Packit Service 88ab54
	}
Packit Service 88ab54
	authn_request = LASSO_SAMLP2_AUTHN_REQUEST(request);
Packit Service 88ab54
	/* intialize the response */
Packit Service 88ab54
	response = (LassoSamlp2StatusResponse*) lasso_samlp2_response_new();
Packit Service 88ab54
	lasso_assign_string(response->InResponseTo,
Packit Service 88ab54
			LASSO_SAMLP2_REQUEST_ABSTRACT(profile->request)->ID);
Packit Service 88ab54
	/* reset response binding */
Packit Service 88ab54
	login->protocolProfile = 0;
Packit Service 88ab54
Packit Service 88ab54
	/* find the remote provider */
Packit Service 88ab54
	if (! authn_request->parent.Issuer || ! authn_request->parent.Issuer->content) {
Packit Service 88ab54
		rc = LASSO_PROFILE_ERROR_INVALID_REQUEST;
Packit Service 88ab54
		goto cleanup;
Packit Service 88ab54
	}
Packit Service 88ab54
	remote_provider = lasso_server_get_provider(profile->server, profile->remote_providerID);
Packit Service 88ab54
	if (remote_provider == NULL) {
Packit Service 88ab54
		rc = LASSO_PROFILE_ERROR_UNKNOWN_PROVIDER;
Packit Service 88ab54
		goto cleanup;
Packit Service 88ab54
	}
Packit Service 88ab54
	lasso_extract_node_or_fail(server, lasso_profile_get_server(&login->parent), SERVER,
Packit Service 88ab54
			LASSO_PROFILE_ERROR_MISSING_SERVER);
Packit Service 88ab54
	remote_provider->role = LASSO_PROVIDER_ROLE_SP;
Packit Service 88ab54
	server->parent.role = LASSO_PROVIDER_ROLE_IDP;
Packit Service 88ab54
Packit Service 88ab54
	if (((authn_request->ProtocolBinding != NULL) ||
Packit Service 88ab54
			(authn_request->AssertionConsumerServiceURL != NULL)) &&
Packit Service 88ab54
			(authn_request->AssertionConsumerServiceIndex != -1))
Packit Service 88ab54
	{
Packit Service 88ab54
		rc = LASSO_PROFILE_ERROR_INVALID_REQUEST;
Packit Service 88ab54
		goto cleanup;
Packit Service 88ab54
	}
Packit Service 88ab54
Packit Service 88ab54
	/* try to find a protocol profile for sending the response */
Packit Service 88ab54
	protocol_binding = authn_request->ProtocolBinding;
Packit Service 88ab54
	if (protocol_binding || authn_request->AssertionConsumerServiceURL)
Packit Service 88ab54
	{
Packit Service 88ab54
		if (authn_request->AssertionConsumerServiceURL) {
Packit Service 88ab54
			if (protocol_binding) {
Packit Service 88ab54
				if (! lasso_saml20_provider_check_assertion_consumer_service_url(
Packit Service 88ab54
							remote_provider, 
Packit Service 88ab54
							authn_request->AssertionConsumerServiceURL,
Packit Service 88ab54
							authn_request->ProtocolBinding)) {
Packit Service 88ab54
					// Sent ACS URL is unknown
Packit Service 88ab54
					rc = LASSO_PROFILE_ERROR_INVALID_PROTOCOLPROFILE;
Packit Service 88ab54
					goto cleanup;
Packit Service 88ab54
				}
Packit Service 88ab54
			} else {
Packit Service 88ab54
				// Only ACS URL sent, choose the first associated binding
Packit Service 88ab54
				protocol_binding = lasso_saml20_provider_get_assertion_consumer_service_binding_by_url(
Packit Service 88ab54
						remote_provider, authn_request->AssertionConsumerServiceURL);
Packit Service 88ab54
				if (! protocol_binding) {
Packit Service 88ab54
					rc = LASSO_PROFILE_ERROR_INVALID_PROTOCOLPROFILE;
Packit Service 88ab54
					goto cleanup;
Packit Service 88ab54
				}
Packit Service 88ab54
				lasso_assign_string(authn_request->ProtocolBinding,
Packit Service 88ab54
						protocol_binding);
Packit Service 88ab54
			}
Packit Service 88ab54
		}
Packit Service 88ab54
Packit Service 88ab54
		if (lasso_strisequal(protocol_binding,LASSO_SAML2_METADATA_BINDING_ARTIFACT)) {
Packit Service 88ab54
			login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_ART;
Packit Service 88ab54
		} else if (lasso_strisequal(protocol_binding,LASSO_SAML2_METADATA_BINDING_POST)) {
Packit Service 88ab54
			login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_POST;
Packit Service 88ab54
		} else if (lasso_strisequal(protocol_binding,LASSO_SAML2_METADATA_BINDING_SOAP)) {
Packit Service 88ab54
			login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_LECP;
Packit Service 88ab54
		} else if (lasso_strisequal(protocol_binding,LASSO_SAML2_METADATA_BINDING_REDIRECT)) {
Packit Service 88ab54
			login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_REDIRECT;
Packit Service 88ab54
			goto_cleanup_with_rc(LASSO_PROFILE_ERROR_INVALID_PROTOCOLPROFILE);
Packit Service 88ab54
		} else if (lasso_strisequal(protocol_binding,LASSO_SAML2_METADATA_BINDING_PAOS)) {
Packit Service 88ab54
			login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_LECP;
Packit Service 88ab54
		} else {
Packit Service 88ab54
			rc = LASSO_PROFILE_ERROR_INVALID_PROTOCOLPROFILE;
Packit Service 88ab54
			goto cleanup;
Packit Service 88ab54
		}
Packit Service 88ab54
	} else {
Packit Service 88ab54
		/* protocol binding not set; so it will look into
Packit Service 88ab54
		 * AssertionConsumerServiceIndex
Packit Service 88ab54
		 * Also, if AssertionConsumerServiceIndex is not set in request,
Packit Service 88ab54
		 * its value will be -1, which is just the right value to get
Packit Service 88ab54
		 * default assertion consumer...  (convenient)
Packit Service 88ab54
		 */
Packit Service 88ab54
		gchar *binding;
Packit Service 88ab54
		int service_index = authn_request->AssertionConsumerServiceIndex;
Packit Service 88ab54
Packit Service 88ab54
		binding = lasso_saml20_provider_get_assertion_consumer_service_binding(
Packit Service 88ab54
				remote_provider, service_index);
Packit Service 88ab54
		if (binding == NULL) {
Packit Service 88ab54
			if (service_index == -1) {
Packit Service 88ab54
				goto_cleanup_with_rc(LASSO_LOGIN_ERROR_NO_DEFAULT_ENDPOINT);
Packit Service 88ab54
			} else {
Packit Service 88ab54
				goto_cleanup_with_rc(LASSO_PROFILE_ERROR_INVALID_PROTOCOLPROFILE);
Packit Service 88ab54
			}
Packit Service 88ab54
		} else if (lasso_strisequal(binding,"HTTP-Artifact")) {
Packit Service 88ab54
			login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_ART;
Packit Service 88ab54
		} else if (lasso_strisequal(binding,"HTTP-POST")) {
Packit Service 88ab54
			login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_POST;
Packit Service 88ab54
		} else if (lasso_strisequal(binding,"HTTP-Redirect")) {
Packit Service 88ab54
			login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_REDIRECT;
Packit Service 88ab54
		} else if (lasso_strisequal(binding,"SOAP")) {
Packit Service 88ab54
			login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_LECP;
Packit Service 88ab54
		} else if (lasso_strisequal(binding,"PAOS")) {
Packit Service 88ab54
			login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_LECP;
Packit Service 88ab54
		}
Packit Service 88ab54
		lasso_release_string(binding);
Packit Service 88ab54
	}
Packit Service 88ab54
Packit Service 88ab54
Packit Service 88ab54
	if (_lasso_login_must_verify_authn_request_signature(profile) && profile->signature_status)
Packit Service 88ab54
	{
Packit Service 88ab54
		status1 = LASSO_SAML2_STATUS_CODE_REQUESTER;
Packit Service 88ab54
		status2 = LASSO_LIB_STATUS_CODE_INVALID_SIGNATURE;
Packit Service 88ab54
		rc = profile->signature_status;
Packit Service 88ab54
	} else {
Packit Service 88ab54
		status1 = LASSO_SAML2_STATUS_CODE_SUCCESS;
Packit Service 88ab54
		status2 = NULL;
Packit Service 88ab54
	}
Packit Service 88ab54
	lasso_saml20_profile_init_response(profile, response,
Packit Service 88ab54
				status1, status2);
Packit Service 88ab54
cleanup:
Packit Service 88ab54
	lasso_release_gobject(request);
Packit Service 88ab54
	lasso_release_gobject(response);
Packit Service 88ab54
	return rc;
Packit Service 88ab54
}
Packit Service 88ab54
Packit Service 88ab54
Packit Service 88ab54
gboolean
Packit Service 88ab54
lasso_saml20_login_must_authenticate(LassoLogin *login)
Packit Service 88ab54
{
Packit Service 88ab54
	LassoSamlp2AuthnRequest *request;
Packit Service 88ab54
	gboolean matched = TRUE;
Packit Service 88ab54
	GList *assertions = NULL;
Packit Service 88ab54
	LassoProfile *profile = &login->parent;
Packit Service 88ab54
Packit Service 88ab54
	if (! LASSO_IS_SAMLP2_AUTHN_REQUEST(profile->request))
Packit Service 88ab54
		return FALSE;
Packit Service 88ab54
Packit Service 88ab54
	request = LASSO_SAMLP2_AUTHN_REQUEST(profile->request);
Packit Service 88ab54
	if (request->ForceAuthn == TRUE && request->IsPassive == FALSE)
Packit Service 88ab54
		return TRUE;
Packit Service 88ab54
Packit Service 88ab54
	if (request->RequestedAuthnContext) {
Packit Service 88ab54
		char *comparison = request->RequestedAuthnContext->Comparison;
Packit Service 88ab54
		GList *class_refs = request->RequestedAuthnContext->AuthnContextClassRef;
Packit Service 88ab54
		char *class_ref;
Packit Service 88ab54
		GList *t1, *t2;
Packit Service 88ab54
		int compa = -1;
Packit Service 88ab54
Packit Service 88ab54
		if (comparison == NULL || lasso_strisequal(comparison,"exact")) {
Packit Service 88ab54
			compa = 0;
Packit Service 88ab54
		} else if (lasso_strisequal(comparison,"minimum")) {
Packit Service 88ab54
			message(G_LOG_LEVEL_CRITICAL, "'minimum' comparison is not implemented");
Packit Service 88ab54
			compa = 1;
Packit Service 88ab54
		} else if (lasso_strisequal(comparison,"better")) {
Packit Service 88ab54
			message(G_LOG_LEVEL_CRITICAL, "'better' comparison is not implemented");
Packit Service 88ab54
			compa = 2;
Packit Service 88ab54
		} else if (lasso_strisequal(comparison,"maximum")) {
Packit Service 88ab54
			message(G_LOG_LEVEL_CRITICAL, "'maximum' comparison is not implemented");
Packit Service 88ab54
			compa = 3;
Packit Service 88ab54
		}
Packit Service 88ab54
Packit Service 88ab54
		if (class_refs) {
Packit Service 88ab54
			matched = FALSE;
Packit Service 88ab54
		}
Packit Service 88ab54
Packit Service 88ab54
		assertions = lasso_session_get_assertions(profile->session, NULL);
Packit Service 88ab54
		for (t1 = class_refs; t1 && !matched; t1 = g_list_next(t1)) {
Packit Service 88ab54
			class_ref = t1->data;
Packit Service 88ab54
			for (t2 = assertions; t2 && !matched; t2 = g_list_next(t2)) {
Packit Service 88ab54
				LassoSaml2Assertion *assertion;
Packit Service 88ab54
				LassoSaml2AuthnStatement *as = NULL;
Packit Service 88ab54
				char *method;
Packit Service 88ab54
				GList *t3;
Packit Service 88ab54
Packit Service 88ab54
				if (LASSO_IS_SAML2_ASSERTION(t2->data) == FALSE) {
Packit Service 88ab54
					continue;
Packit Service 88ab54
				}
Packit Service 88ab54
Packit Service 88ab54
				assertion = t2->data;
Packit Service 88ab54
Packit Service 88ab54
				for (t3 = assertion->AuthnStatement; t3; t3 = g_list_next(t3)) {
Packit Service 88ab54
					if (LASSO_IS_SAML2_AUTHN_STATEMENT(t3->data)) {
Packit Service 88ab54
						as = t3->data;
Packit Service 88ab54
						break;
Packit Service 88ab54
					}
Packit Service 88ab54
				}
Packit Service 88ab54
Packit Service 88ab54
				if (as == NULL)
Packit Service 88ab54
					continue;
Packit Service 88ab54
Packit Service 88ab54
				if (as->AuthnContext == NULL)
Packit Service 88ab54
					continue;
Packit Service 88ab54
Packit Service 88ab54
				method = as->AuthnContext->AuthnContextClassRef;
Packit Service 88ab54
Packit Service 88ab54
				switch (compa) {
Packit Service 88ab54
				case 1: /* minimum */
Packit Service 88ab54
					/* XXX: implement 'minimum' comparison */
Packit Service 88ab54
				case 2: /* better */
Packit Service 88ab54
					/* XXX: implement 'better' comparison */
Packit Service 88ab54
				case 3: /* maximum */
Packit Service 88ab54
					/* XXX: implement 'maximum' comparison */
Packit Service 88ab54
				case 0: /* exact */
Packit Service 88ab54
					if (lasso_strisequal(method,class_ref)) {
Packit Service 88ab54
						matched = TRUE;
Packit Service 88ab54
					}
Packit Service 88ab54
					break;
Packit Service 88ab54
				default: /* never reached */
Packit Service 88ab54
					break;
Packit Service 88ab54
				}
Packit Service 88ab54
				if (matched == TRUE) {
Packit Service 88ab54
					break;
Packit Service 88ab54
				}
Packit Service 88ab54
			}
Packit Service 88ab54
		}
Packit Service 88ab54
	} else {
Packit Service 88ab54
		/* if nothing specific was asked; don't look for any
Packit Service 88ab54
		 * particular assertions, one is enough
Packit Service 88ab54
		 */
Packit Service 88ab54
		matched = (profile->session != NULL && \
Packit Service 88ab54
				lasso_session_count_assertions(profile->session) > 0);
Packit Service 88ab54
	}
Packit Service 88ab54
	if (assertions) {
Packit Service 88ab54
		lasso_release_list(assertions);
Packit Service 88ab54
	}
Packit Service 88ab54
	if (matched == FALSE && request->IsPassive == FALSE)
Packit Service 88ab54
		return TRUE;
Packit Service 88ab54
	if (profile->identity == NULL && request->IsPassive) {
Packit Service 88ab54
		lasso_saml20_profile_set_response_status_responder(LASSO_PROFILE(login),
Packit Service 88ab54
				LASSO_SAML2_STATUS_CODE_NO_PASSIVE);
Packit Service 88ab54
		return FALSE;
Packit Service 88ab54
	}
Packit Service 88ab54
	return FALSE;
Packit Service 88ab54
}
Packit Service 88ab54
Packit Service 88ab54
static gboolean
Packit Service 88ab54
lasso_saml20_login_must_ask_for_consent_private(LassoLogin *login)
Packit Service 88ab54
{
Packit Service 88ab54
	LassoProfile *profile = LASSO_PROFILE(login);
Packit Service 88ab54
	LassoSamlp2NameIDPolicy *name_id_policy;
Packit Service 88ab54
	char *consent;
Packit Service 88ab54
	LassoFederation *federation;
Packit Service 88ab54
	const char *name_id_sp_name_qualifier = NULL;
Packit Service 88ab54
	LassoProvider *remote_provider;
Packit Service 88ab54
	gboolean rc = TRUE;
Packit Service 88ab54
Packit Service 88ab54
	name_id_policy = LASSO_SAMLP2_AUTHN_REQUEST(profile->request)->NameIDPolicy;
Packit Service 88ab54
Packit Service 88ab54
	if (name_id_policy) {
Packit Service 88ab54
		char *format = name_id_policy->Format;
Packit Service 88ab54
		if (lasso_strisequal(format,LASSO_SAML2_NAME_IDENTIFIER_FORMAT_TRANSIENT)) {
Packit Service 88ab54
			goto_cleanup_with_rc (FALSE)
Packit Service 88ab54
		}
Packit Service 88ab54
		if (name_id_policy->AllowCreate == FALSE) {
Packit Service 88ab54
			goto_cleanup_with_rc (FALSE)
Packit Service 88ab54
		}
Packit Service 88ab54
	}
Packit Service 88ab54
Packit Service 88ab54
	remote_provider = lasso_server_get_provider(profile->server, profile->remote_providerID);
Packit Service 88ab54
	name_id_sp_name_qualifier = lasso_provider_get_sp_name_qualifier(remote_provider);
Packit Service 88ab54
Packit Service 88ab54
	/* if something goes wrong better to ask thant to let go */
Packit Service 88ab54
	if (name_id_sp_name_qualifier == NULL)
Packit Service 88ab54
		goto_cleanup_with_rc (TRUE)
Packit Service 88ab54
Packit Service 88ab54
	if (profile->identity && profile->identity->federations) {
Packit Service 88ab54
		federation = g_hash_table_lookup(profile->identity->federations,
Packit Service 88ab54
				name_id_sp_name_qualifier);
Packit Service 88ab54
		if (federation) {
Packit Service 88ab54
			goto_cleanup_with_rc (FALSE)
Packit Service 88ab54
		}
Packit Service 88ab54
	}
Packit Service 88ab54
Packit Service 88ab54
	consent = LASSO_SAMLP2_REQUEST_ABSTRACT(profile->request)->Consent;
Packit Service 88ab54
	if (consent == NULL)
Packit Service 88ab54
		goto_cleanup_with_rc (FALSE)
Packit Service 88ab54
Packit Service 88ab54
	if (lasso_strisequal(consent,LASSO_SAML2_CONSENT_OBTAINED))
Packit Service 88ab54
		goto_cleanup_with_rc (FALSE)
Packit Service 88ab54
Packit Service 88ab54
	if (lasso_strisequal(consent,LASSO_SAML2_CONSENT_PRIOR))
Packit Service 88ab54
		goto_cleanup_with_rc (FALSE)
Packit Service 88ab54
Packit Service 88ab54
	if (lasso_strisequal(consent,LASSO_SAML2_CONSENT_IMPLICIT))
Packit Service 88ab54
		goto_cleanup_with_rc (FALSE)
Packit Service 88ab54
Packit Service 88ab54
	if (lasso_strisequal(consent,LASSO_SAML2_CONSENT_EXPLICIT))
Packit Service 88ab54
		goto_cleanup_with_rc (FALSE)
Packit Service 88ab54
Packit Service 88ab54
	if (lasso_strisequal(consent,LASSO_SAML2_CONSENT_UNAVAILABLE))
Packit Service 88ab54
		goto_cleanup_with_rc (TRUE)
Packit Service 88ab54
Packit Service 88ab54
	if (lasso_strisequal(consent,LASSO_SAML2_CONSENT_INAPPLICABLE))
Packit Service 88ab54
		goto_cleanup_with_rc (TRUE)
Packit Service 88ab54
Packit Service 88ab54
cleanup:
Packit Service 88ab54
	return rc;
Packit Service 88ab54
}
Packit Service 88ab54
Packit Service 88ab54
gboolean
Packit Service 88ab54
lasso_saml20_login_must_ask_for_consent(LassoLogin *login)
Packit Service 88ab54
{
Packit Service 88ab54
	LassoProfile *profile = LASSO_PROFILE(login);
Packit Service 88ab54
Packit Service 88ab54
	if (LASSO_SAMLP2_AUTHN_REQUEST(profile->request)->IsPassive)
Packit Service 88ab54
		return FALSE;
Packit Service 88ab54
Packit Service 88ab54
	return lasso_saml20_login_must_ask_for_consent_private(login);
Packit Service 88ab54
}
Packit Service 88ab54
Packit Service 88ab54
int
Packit Service 88ab54
lasso_saml20_login_validate_request_msg(LassoLogin *login, gboolean authentication_result,
Packit Service 88ab54
		gboolean is_consent_obtained)
Packit Service 88ab54
{
Packit Service 88ab54
	LassoProfile *profile;
Packit Service 88ab54
	int rc = 0;
Packit Service 88ab54
Packit Service 88ab54
	profile = LASSO_PROFILE(login);
Packit Service 88ab54
Packit Service 88ab54
	if (authentication_result == FALSE) {
Packit Service 88ab54
		lasso_saml20_profile_set_response_status_responder(profile,
Packit Service 88ab54
				LASSO_SAML2_STATUS_CODE_REQUEST_DENIED);
Packit Service 88ab54
		goto_cleanup_with_rc(LASSO_LOGIN_ERROR_REQUEST_DENIED);
Packit Service 88ab54
	}
Packit Service 88ab54
Packit Service 88ab54
	if (_lasso_login_must_verify_authn_request_signature(profile) && profile->signature_status)
Packit Service 88ab54
	{
Packit Service 88ab54
		lasso_saml20_profile_set_response_status_requester(profile,
Packit Service 88ab54
					LASSO_LIB_STATUS_CODE_INVALID_SIGNATURE);
Packit Service 88ab54
Packit Service 88ab54
		if (profile->signature_status == LASSO_DS_ERROR_SIGNATURE_NOT_FOUND) {
Packit Service 88ab54
			goto_cleanup_with_rc(LASSO_LOGIN_ERROR_UNSIGNED_AUTHN_REQUEST);
Packit Service 88ab54
		}
Packit Service 88ab54
		goto_cleanup_with_rc(LASSO_LOGIN_ERROR_INVALID_SIGNATURE);
Packit Service 88ab54
	}
Packit Service 88ab54
Packit Service 88ab54
	rc = lasso_saml20_login_process_federation(login, is_consent_obtained);
Packit Service 88ab54
	if (rc == LASSO_LOGIN_ERROR_FEDERATION_NOT_FOUND) {
Packit Service 88ab54
		lasso_saml20_profile_set_response_status_requester(profile,
Packit Service 88ab54
			LASSO_LIB_STATUS_CODE_FEDERATION_DOES_NOT_EXIST);
Packit Service 88ab54
		goto cleanup;
Packit Service 88ab54
	}
Packit Service 88ab54
	/* UNKNOWN_PROVIDER, CONSENT_NOT_OBTAINED */
Packit Service 88ab54
	if (rc) {
Packit Service 88ab54
		lasso_saml20_profile_set_response_status_responder(profile,
Packit Service 88ab54
			LASSO_SAML2_STATUS_CODE_REQUEST_DENIED);
Packit Service 88ab54
		goto cleanup;
Packit Service 88ab54
	}
Packit Service 88ab54
Packit Service 88ab54
	lasso_saml20_profile_set_response_status_success(profile, NULL);
Packit Service 88ab54
cleanup:
Packit Service 88ab54
Packit Service 88ab54
	return rc;
Packit Service 88ab54
}
Packit Service 88ab54
Packit Service 88ab54
static int
Packit Service 88ab54
lasso_saml20_login_process_federation(LassoLogin *login, gboolean is_consent_obtained)
Packit Service 88ab54
{
Packit Service 88ab54
	LassoProfile *profile = LASSO_PROFILE(login);
Packit Service 88ab54
	LassoSamlp2NameIDPolicy *name_id_policy;
Packit Service 88ab54
	char *name_id_policy_format = NULL;
Packit Service 88ab54
	LassoFederation *federation;
Packit Service 88ab54
	const char *name_id_sp_name_qualifier = NULL;
Packit Service 88ab54
	LassoProvider *remote_provider;
Packit Service 88ab54
	int rc = 0;
Packit Service 88ab54
Packit Service 88ab54
	/* verify if identity already exists else create it */
Packit Service 88ab54
	if (profile->identity == NULL) {
Packit Service 88ab54
		profile->identity = lasso_identity_new();
Packit Service 88ab54
	}
Packit Service 88ab54
Packit Service 88ab54
	remote_provider = lasso_server_get_provider(profile->server, profile->remote_providerID);
Packit Service 88ab54
	if (! LASSO_IS_PROVIDER(remote_provider)) {
Packit Service 88ab54
		goto_cleanup_with_rc (LASSO_PROFILE_ERROR_UNKNOWN_PROVIDER);
Packit Service 88ab54
	}
Packit Service 88ab54
Packit Service 88ab54
	if (! LASSO_IS_SAMLP2_AUTHN_REQUEST(profile->request)) {
Packit Service 88ab54
		goto_cleanup_with_rc(critical_error(LASSO_PROFILE_ERROR_INVALID_REQUEST));
Packit Service 88ab54
	}
Packit Service 88ab54
Packit Service 88ab54
	name_id_policy = ((LassoSamlp2AuthnRequest*)profile->request)->NameIDPolicy;
Packit Service 88ab54
Packit Service 88ab54
	if (name_id_policy) {
Packit Service 88ab54
		name_id_policy_format = name_id_policy->Format;
Packit Service 88ab54
	}
Packit Service 88ab54
Packit Service 88ab54
	if (! name_id_policy_format) {
Packit Service 88ab54
		name_id_policy_format = lasso_provider_get_default_name_id_format(remote_provider);
Packit Service 88ab54
	}
Packit Service 88ab54
Packit Service 88ab54
	lasso_assign_string(login->nameIDPolicy, name_id_policy_format);
Packit Service 88ab54
Packit Service 88ab54
	if (lasso_saml20_login_must_ask_for_consent_private(login) && !is_consent_obtained) {
Packit Service 88ab54
		goto_cleanup_with_rc (LASSO_LOGIN_ERROR_CONSENT_NOT_OBTAINED)
Packit Service 88ab54
	}
Packit Service 88ab54
	if (lasso_strisnotequal(name_id_policy_format,LASSO_SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT)) {
Packit Service 88ab54
		/* non persistent case, TRANSIENT is handled by lasso_login_build_assertion() and
Packit Service 88ab54
		 * other format are the sole responsibility of the caller */
Packit Service 88ab54
		goto_cleanup_with_rc (0)
Packit Service 88ab54
	}
Packit Service 88ab54
Packit Service 88ab54
	/* PERSISTENT case, try to federation or find an existing federation */
Packit Service 88ab54
	name_id_sp_name_qualifier = lasso_provider_get_sp_name_qualifier(remote_provider);
Packit Service 88ab54
	if (name_id_sp_name_qualifier == NULL) {
Packit Service 88ab54
		goto_cleanup_with_rc (LASSO_PROFILE_ERROR_UNKNOWN_PROVIDER);
Packit Service 88ab54
	}
Packit Service 88ab54
Packit Service 88ab54
	/* search a federation in the identity */
Packit Service 88ab54
	federation = lasso_identity_get_federation(profile->identity, name_id_sp_name_qualifier);
Packit Service 88ab54
	if (! federation && ( ! name_id_policy || name_id_policy->AllowCreate == FALSE)) {
Packit Service 88ab54
		goto_cleanup_with_rc (LASSO_LOGIN_ERROR_FEDERATION_NOT_FOUND)
Packit Service 88ab54
	}
Packit Service 88ab54
	if (! federation && name_id_policy && name_id_policy->AllowCreate) {
Packit Service 88ab54
		federation = lasso_federation_new(name_id_sp_name_qualifier);
Packit Service 88ab54
		lasso_saml20_federation_build_local_name_identifier(federation,
Packit Service 88ab54
				LASSO_PROVIDER(profile->server)->ProviderID,
Packit Service 88ab54
				LASSO_SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT,
Packit Service 88ab54
				NULL);
Packit Service 88ab54
		lasso_assign_string(LASSO_SAML2_NAME_ID(federation->local_nameIdentifier)->SPNameQualifier,
Packit Service 88ab54
				name_id_sp_name_qualifier);
Packit Service 88ab54
		lasso_identity_add_federation(profile->identity, federation);
Packit Service 88ab54
	}
Packit Service 88ab54
Packit Service 88ab54
	lasso_assign_gobject(profile->nameIdentifier, federation->local_nameIdentifier);
Packit Service 88ab54
Packit Service 88ab54
cleanup:
Packit Service 88ab54
	return rc;
Packit Service 88ab54
}
Packit Service 88ab54
Packit Service 88ab54
static LassoFederation*
Packit Service 88ab54
_lasso_login_saml20_get_federation(LassoLogin *login) {
Packit Service 88ab54
	LassoFederation *federation = NULL;
Packit Service 88ab54
	const char *name_id_sp_name_qualifier = NULL;
Packit Service 88ab54
Packit Service 88ab54
Packit Service 88ab54
	name_id_sp_name_qualifier = lasso_provider_get_sp_name_qualifier(
Packit Service 88ab54
			lasso_server_get_provider(login->parent.server, login->parent.remote_providerID));
Packit Service 88ab54
	federation = lasso_identity_get_federation(login->parent.identity, name_id_sp_name_qualifier);
Packit Service 88ab54
	return federation;
Packit Service 88ab54
}
Packit Service 88ab54
Packit Service 88ab54
int
Packit Service 88ab54
lasso_saml20_login_build_assertion(LassoLogin *login,
Packit Service 88ab54
		const char *authenticationMethod,
Packit Service 88ab54
		const char *authenticationInstant,
Packit Service 88ab54
		const char *notBefore,
Packit Service 88ab54
		const char *notOnOrAfter)
Packit Service 88ab54
{
Packit Service 88ab54
	LassoProfile *profile = &login->parent;
Packit Service 88ab54
	LassoSaml2Assertion *assertion = NULL;
Packit Service 88ab54
	LassoSaml2AudienceRestriction *audience_restriction = NULL;
Packit Service 88ab54
	LassoSamlp2NameIDPolicy *name_id_policy = NULL;
Packit Service 88ab54
	LassoSaml2NameID *name_id = NULL;
Packit Service 88ab54
	LassoSaml2AuthnStatement *authentication_statement;
Packit Service 88ab54
	LassoProvider *provider = NULL;
Packit Service 88ab54
	LassoSamlp2Response *response = NULL;
Packit Service 88ab54
	LassoSamlp2RequestAbstract *request_abstract = NULL;
Packit Service 88ab54
	LassoSamlp2AuthnRequest *authn_request = NULL;
Packit Service 88ab54
	gboolean do_encrypt_nameid = FALSE;
Packit Service 88ab54
	gboolean do_encrypt_assertion = FALSE;
Packit Service 88ab54
	int rc = 0;
Packit Service 88ab54
Packit Service 88ab54
	provider = lasso_server_get_provider(profile->server, profile->remote_providerID);
Packit Service 88ab54
Packit Service 88ab54
	if (provider) {
Packit Service 88ab54
		do_encrypt_nameid = lasso_provider_get_encryption_mode(provider) &
Packit Service 88ab54
			LASSO_ENCRYPTION_MODE_NAMEID;
Packit Service 88ab54
		do_encrypt_assertion = lasso_provider_get_encryption_mode(provider) &
Packit Service 88ab54
			LASSO_ENCRYPTION_MODE_ASSERTION;
Packit Service 88ab54
	}
Packit Service 88ab54
Packit Service 88ab54
	if (LASSO_IS_SAMLP2_AUTHN_REQUEST(profile->request)) {
Packit Service 88ab54
		authn_request = (LassoSamlp2AuthnRequest*)profile->request;
Packit Service 88ab54
		request_abstract = &authn_request->parent;
Packit Service 88ab54
	}
Packit Service 88ab54
	goto_cleanup_if_fail_with_rc(LASSO_IS_SAMLP2_RESPONSE(profile->response),
Packit Service 88ab54
			LASSO_PROFILE_ERROR_MISSING_RESPONSE);
Packit Service 88ab54
Packit Service 88ab54
	assertion = LASSO_SAML2_ASSERTION(lasso_saml2_assertion_new());
Packit Service 88ab54
	assertion->ID = lasso_build_unique_id(32);
Packit Service 88ab54
	lasso_assign_string(assertion->Version, "2.0");
Packit Service 88ab54
	assertion->IssueInstant = lasso_get_current_time();
Packit Service 88ab54
	assertion->Issuer = LASSO_SAML2_NAME_ID(lasso_saml2_name_id_new_with_string(
Packit Service 88ab54
			LASSO_PROVIDER(profile->server)->ProviderID));
Packit Service 88ab54
	assertion->Conditions = LASSO_SAML2_CONDITIONS(lasso_saml2_conditions_new());
Packit Service 88ab54
	lasso_assign_string(assertion->Conditions->NotBefore, notBefore);
Packit Service 88ab54
	lasso_assign_string(assertion->Conditions->NotOnOrAfter, notOnOrAfter);
Packit Service 88ab54
Packit Service 88ab54
	audience_restriction = LASSO_SAML2_AUDIENCE_RESTRICTION(
Packit Service 88ab54
			lasso_saml2_audience_restriction_new());
Packit Service 88ab54
	lasso_assign_string(audience_restriction->Audience, profile->remote_providerID);
Packit Service 88ab54
	lasso_list_add_new_gobject(assertion->Conditions->AudienceRestriction, audience_restriction);
Packit Service 88ab54
Packit Service 88ab54
	assertion->Subject = LASSO_SAML2_SUBJECT(lasso_saml2_subject_new());
Packit Service 88ab54
	assertion->Subject->SubjectConfirmation = LASSO_SAML2_SUBJECT_CONFIRMATION(
Packit Service 88ab54
			lasso_saml2_subject_confirmation_new());
Packit Service 88ab54
	assertion->Subject->SubjectConfirmation->Method = g_strdup(
Packit Service 88ab54
			LASSO_SAML2_CONFIRMATION_METHOD_BEARER);
Packit Service 88ab54
	assertion->Subject->SubjectConfirmation->SubjectConfirmationData =
Packit Service 88ab54
		LASSO_SAML2_SUBJECT_CONFIRMATION_DATA(
Packit Service 88ab54
			lasso_saml2_subject_confirmation_data_new());
Packit Service 88ab54
	lasso_assign_string(
Packit Service 88ab54
		assertion->Subject->SubjectConfirmation->SubjectConfirmationData->NotOnOrAfter,
Packit Service 88ab54
		notOnOrAfter);
Packit Service 88ab54
Packit Service 88ab54
	/* If request is present, refer to it in the response */
Packit Service 88ab54
	if (authn_request) {
Packit Service 88ab54
		if (request_abstract->ID) {
Packit Service 88ab54
			lasso_assign_string(assertion->Subject->SubjectConfirmation->SubjectConfirmationData->InResponseTo,
Packit Service 88ab54
					request_abstract->ID);
Packit Service 88ab54
			/*
Packit Service 88ab54
			 * It MUST NOT contain a NotBefore attribute. If
Packit Service 88ab54
			 * the containing message is in response to an <AuthnRequest>,
Packit Service 88ab54
			 * then the InResponseTo attribute MUST match the request's ID.
Packit Service 88ab54
			 */
Packit Service 88ab54
			lasso_release_string(assertion->Subject->SubjectConfirmation->SubjectConfirmationData->NotBefore);
Packit Service 88ab54
		}
Packit Service 88ab54
		name_id_policy = authn_request->NameIDPolicy;
Packit Service 88ab54
	}
Packit Service 88ab54
	/* TRANSIENT */
Packit Service 88ab54
	if (!name_id_policy || name_id_policy->Format == NULL ||
Packit Service 88ab54
			lasso_strisequal(name_id_policy->Format,LASSO_SAML2_NAME_IDENTIFIER_FORMAT_UNSPECIFIED) ||
Packit Service 88ab54
			lasso_strisequal(name_id_policy->Format,LASSO_SAML2_NAME_IDENTIFIER_FORMAT_TRANSIENT)) {
Packit Service 88ab54
		char *id = lasso_build_unique_id(32);
Packit Service 88ab54
Packit Service 88ab54
		name_id = (LassoSaml2NameID*)lasso_saml2_name_id_new_with_string(id);
Packit Service 88ab54
		lasso_release_string(id);
Packit Service 88ab54
		lasso_assign_string(name_id->NameQualifier,
Packit Service 88ab54
				lasso_provider_get_sp_name_qualifier(&profile->server->parent));
Packit Service 88ab54
		lasso_assign_string(name_id->Format, LASSO_SAML2_NAME_IDENTIFIER_FORMAT_TRANSIENT);
Packit Service 88ab54
		assertion->Subject->NameID = name_id;
Packit Service 88ab54
	/* FEDERATED */
Packit Service 88ab54
	} else if (lasso_strisequal(name_id_policy->Format,
Packit Service 88ab54
				LASSO_SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT) ||
Packit Service 88ab54
			lasso_strisequal(name_id_policy->Format,
Packit Service 88ab54
				LASSO_SAML2_NAME_IDENTIFIER_FORMAT_ENCRYPTED))
Packit Service 88ab54
		{
Packit Service 88ab54
		LassoFederation *federation;
Packit Service 88ab54
Packit Service 88ab54
		federation = _lasso_login_saml20_get_federation(login);
Packit Service 88ab54
		goto_cleanup_if_fail_with_rc(federation != NULL,
Packit Service 88ab54
				LASSO_PROFILE_ERROR_FEDERATION_NOT_FOUND);
Packit Service 88ab54
Packit Service 88ab54
		if (lasso_strisequal(name_id_policy->Format,LASSO_SAML2_NAME_IDENTIFIER_FORMAT_ENCRYPTED)) {
Packit Service 88ab54
			do_encrypt_nameid = TRUE;
Packit Service 88ab54
		}
Packit Service 88ab54
		lasso_assign_gobject(assertion->Subject->NameID,
Packit Service 88ab54
				federation->local_nameIdentifier);
Packit Service 88ab54
	/* ALL OTHER KIND OF NAME ID FORMATS */
Packit Service 88ab54
	} else {
Packit Service 88ab54
		/* caller must set the name identifier content afterwards */
Packit Service 88ab54
		name_id = LASSO_SAML2_NAME_ID(lasso_saml2_name_id_new());
Packit Service 88ab54
		lasso_assign_string(name_id->NameQualifier,
Packit Service 88ab54
				LASSO_PROVIDER(profile->server)->ProviderID);
Packit Service 88ab54
		lasso_assign_string(name_id->Format, name_id_policy->Format);
Packit Service 88ab54
		assertion->Subject->NameID = name_id;
Packit Service 88ab54
		if (do_encrypt_nameid) {
Packit Service 88ab54
			message(G_LOG_LEVEL_WARNING, "NameID encryption is currently not "
Packit Service 88ab54
					"supported with non transient or persisent NameID format");
Packit Service 88ab54
			do_encrypt_nameid = FALSE;
Packit Service 88ab54
		}
Packit Service 88ab54
	}
Packit Service 88ab54
Packit Service 88ab54
	authentication_statement = LASSO_SAML2_AUTHN_STATEMENT(lasso_saml2_authn_statement_new());
Packit Service 88ab54
	authentication_statement->AuthnInstant = g_strdup(authenticationInstant);
Packit Service 88ab54
	authentication_statement->AuthnContext = LASSO_SAML2_AUTHN_CONTEXT(
Packit Service 88ab54
			lasso_saml2_authn_context_new());
Packit Service 88ab54
	authentication_statement->AuthnContext->AuthnContextClassRef = g_strdup(
Packit Service 88ab54
			authenticationMethod);
Packit Service 88ab54
Packit Service 88ab54
	/* if remote provider supports logout profile, add a session index == ID of the assertion */
Packit Service 88ab54
	if (lasso_provider_get_first_http_method(&login->parent.server->parent,
Packit Service 88ab54
				provider, LASSO_MD_PROTOCOL_TYPE_SINGLE_LOGOUT) != LASSO_HTTP_METHOD_NONE) {
Packit Service 88ab54
		lasso_assign_string(authentication_statement->SessionIndex, assertion->ID);
Packit Service 88ab54
	}
Packit Service 88ab54
	lasso_list_add_new_gobject(assertion->AuthnStatement, authentication_statement);
Packit Service 88ab54
Packit Service 88ab54
	/* Save signing material in assertion private datas to be able to sign later */
Packit Service 88ab54
	lasso_check_good_rc(lasso_server_saml2_assertion_setup_signature(profile->server,
Packit Service 88ab54
				assertion));
Packit Service 88ab54
Packit Service 88ab54
	/* Encrypt NameID */
Packit Service 88ab54
	if (do_encrypt_nameid) {
Packit Service 88ab54
		/* store assertion in session object */
Packit Service 88ab54
		if (profile->session == NULL) {
Packit Service 88ab54
			profile->session = lasso_session_new();
Packit Service 88ab54
		}
Packit Service 88ab54
Packit Service 88ab54
		lasso_session_add_assertion(profile->session, profile->remote_providerID,
Packit Service 88ab54
				LASSO_NODE(assertion));
Packit Service 88ab54
Packit Service 88ab54
		/* FIXME: as with assertions, it should be possible to setup encryption of NameID for later */
Packit Service 88ab54
		goto_cleanup_if_fail_with_rc(provider != NULL, LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND);
Packit Service 88ab54
Packit Service 88ab54
		assertion->Subject->EncryptedID = (LassoSaml2EncryptedElement*)lasso_node_encrypt(
Packit Service 88ab54
			(LassoNode*)assertion->Subject->NameID,
Packit Service 88ab54
			lasso_provider_get_encryption_public_key(provider),
Packit Service 88ab54
			lasso_provider_get_encryption_sym_key_type(provider),
Packit Service 88ab54
			provider->ProviderID);
Packit Service 88ab54
		goto_cleanup_if_fail_with_rc(assertion->Subject->EncryptedID != NULL,
Packit Service 88ab54
				LASSO_DS_ERROR_ENCRYPTION_FAILED);
Packit Service 88ab54
		lasso_release_gobject(assertion->Subject->NameID);
Packit Service 88ab54
	}
Packit Service 88ab54
Packit Service 88ab54
	/* Save encryption material in assertion private datas to be able to encrypt later */
Packit Service 88ab54
	if (do_encrypt_assertion) {
Packit Service 88ab54
		lasso_node_set_encryption((LassoNode*)assertion,
Packit Service 88ab54
				lasso_provider_get_encryption_public_key(provider),
Packit Service 88ab54
				lasso_provider_get_encryption_sym_key_type(provider));
Packit Service 88ab54
	}
Packit Service 88ab54
Packit Service 88ab54
	response = LASSO_SAMLP2_RESPONSE(profile->response);
Packit Service 88ab54
	lasso_list_add_gobject(response->Assertion, assertion);
Packit Service 88ab54
	lasso_assign_gobject(login->private_data->saml2_assertion, assertion);
Packit Service 88ab54
cleanup:
Packit Service 88ab54
	lasso_release_gobject(assertion);
Packit Service 88ab54
	return rc;
Packit Service 88ab54
}
Packit Service 88ab54
Packit Service 88ab54
gint
Packit Service 88ab54
lasso_saml20_login_build_artifact_msg(LassoLogin *login, LassoHttpMethod http_method)
Packit Service 88ab54
{
Packit Service 88ab54
	LassoProfile *profile;
Packit Service 88ab54
	LassoProvider *remote_provider;
Packit Service 88ab54
	char *url;
Packit Service 88ab54
	LassoSaml2Assertion *assertion;
Packit Service 88ab54
	LassoSamlp2StatusResponse *response;
Packit Service 88ab54
	int rc = 0;
Packit Service 88ab54
Packit Service 88ab54
	profile = &login->parent;
Packit Service 88ab54
Packit Service 88ab54
	if (profile->remote_providerID == NULL)
Packit Service 88ab54
		return critical_error(LASSO_PROFILE_ERROR_MISSING_REMOTE_PROVIDERID);
Packit Service 88ab54
Packit Service 88ab54
	if (http_method != LASSO_HTTP_METHOD_ARTIFACT_GET && http_method != LASSO_HTTP_METHOD_ARTIFACT_POST) {
Packit Service 88ab54
		return critical_error(LASSO_PROFILE_ERROR_INVALID_HTTP_METHOD);
Packit Service 88ab54
	}
Packit Service 88ab54
Packit Service 88ab54
	if (! LASSO_IS_SAMLP2_RESPONSE(profile->response)) {
Packit Service 88ab54
		return critical_error(LASSO_PROFILE_ERROR_MISSING_RESPONSE);
Packit Service 88ab54
	}
Packit Service 88ab54
	response = (LassoSamlp2StatusResponse*)profile->response;
Packit Service 88ab54
	/* XXX: why checking now ? */
Packit Service 88ab54
	if (response->Status == NULL || response->Status->StatusCode == NULL
Packit Service 88ab54
			|| response->Status->StatusCode->Value == NULL) {
Packit Service 88ab54
		return critical_error(LASSO_PROFILE_ERROR_MISSING_STATUS_CODE);
Packit Service 88ab54
	}
Packit Service 88ab54
Packit Service 88ab54
	remote_provider = lasso_server_get_provider(profile->server, profile->remote_providerID);
Packit Service 88ab54
	if (LASSO_IS_PROVIDER(remote_provider) == FALSE)
Packit Service 88ab54
		return critical_error(LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND);
Packit Service 88ab54
Packit Service 88ab54
	url = lasso_saml20_login_get_assertion_consumer_service_url(login, remote_provider);
Packit Service 88ab54
	assertion = login->private_data->saml2_assertion;
Packit Service 88ab54
	if (LASSO_IS_SAML2_ASSERTION(assertion) && url) {
Packit Service 88ab54
		LassoSaml2SubjectConfirmationData *subject_confirmation_data;
Packit Service 88ab54
Packit Service 88ab54
		subject_confirmation_data =
Packit Service 88ab54
			lasso_saml2_assertion_get_subject_confirmation_data(assertion, TRUE);
Packit Service 88ab54
		lasso_assign_string(subject_confirmation_data->Recipient, url);
Packit Service 88ab54
	}
Packit Service 88ab54
Packit Service 88ab54
	/* If there is a non-encrypted NameID, fix the assertion in the session */
Packit Service 88ab54
	if (assertion && assertion->Subject && assertion->Subject->NameID) {
Packit Service 88ab54
		/* store assertion in session object */
Packit Service 88ab54
		if (profile->session == NULL) {
Packit Service 88ab54
			profile->session = lasso_session_new();
Packit Service 88ab54
		}
Packit Service 88ab54
		lasso_session_add_assertion(profile->session, profile->remote_providerID,
Packit Service 88ab54
				LASSO_NODE(assertion));
Packit Service 88ab54
	}
Packit Service 88ab54
Packit Service 88ab54
Packit Service 88ab54
	lasso_check_good_rc(lasso_saml20_profile_build_response_msg(profile, NULL, http_method,
Packit Service 88ab54
				url));
Packit Service 88ab54
Packit Service 88ab54
cleanup:
Packit Service 88ab54
	lasso_release_string(url);
Packit Service 88ab54
	return rc;
Packit Service 88ab54
}
Packit Service 88ab54
Packit Service 88ab54
Packit Service 88ab54
gint
Packit Service 88ab54
lasso_saml20_login_init_request(LassoLogin *login, gchar *response_msg,
Packit Service 88ab54
		LassoHttpMethod response_http_method)
Packit Service 88ab54
{
Packit Service 88ab54
	return lasso_saml20_profile_init_artifact_resolve(LASSO_PROFILE(login),
Packit Service 88ab54
			LASSO_PROVIDER_ROLE_IDP, response_msg, response_http_method);
Packit Service 88ab54
}
Packit Service 88ab54
Packit Service 88ab54
Packit Service 88ab54
gint
Packit Service 88ab54
lasso_saml20_login_build_request_msg(LassoLogin *login)
Packit Service 88ab54
{
Packit Service 88ab54
	LassoProfile *profile;
Packit Service 88ab54
	lasso_error_t rc = 0;
Packit Service 88ab54
Packit Service 88ab54
	profile = &login->parent;
Packit Service 88ab54
	if (_lasso_login_must_sign_non_authn_request(login)) {
Packit Service 88ab54
		rc = lasso_profile_saml20_setup_message_signature(profile, profile->request);
Packit Service 88ab54
		if (rc != 0) {
Packit Service 88ab54
			return rc;
Packit Service 88ab54
		}
Packit Service 88ab54
	} else {
Packit Service 88ab54
		lasso_node_remove_signature(profile->request);
Packit Service 88ab54
	}
Packit Service 88ab54
	return lasso_saml20_profile_build_request_msg(profile, "ArtifactResolutionService",
Packit Service 88ab54
			LASSO_HTTP_METHOD_SOAP, profile->msg_url);
Packit Service 88ab54
}
Packit Service 88ab54
Packit Service 88ab54
gint
Packit Service 88ab54
lasso_saml20_login_process_request_msg(LassoLogin *login, gchar *request_msg)
Packit Service 88ab54
{
Packit Service 88ab54
	LassoProfile *profile = LASSO_PROFILE(login);
Packit Service 88ab54
	int rc = 0;
Packit Service 88ab54
Packit Service 88ab54
	rc = lasso_saml20_profile_process_artifact_resolve(profile, request_msg);
Packit Service 88ab54
	if (rc != 0) {
Packit Service 88ab54
		return rc;
Packit Service 88ab54
	}
Packit Service 88ab54
	/* compat with liberty id-ff code */
Packit Service 88ab54
	lasso_assign_new_string(login->assertionArtifact, lasso_profile_get_artifact(profile));
Packit Service 88ab54
	return 0;
Packit Service 88ab54
}
Packit Service 88ab54
Packit Service 88ab54
gint
Packit Service 88ab54
lasso_saml20_login_build_response_msg(LassoLogin *login)
Packit Service 88ab54
{
Packit Service 88ab54
	LassoProfile *profile = LASSO_PROFILE(login);
Packit Service 88ab54
	LassoProvider *remote_provider;
Packit Service 88ab54
	LassoSaml2Assertion *assertion;
Packit Service 88ab54
	int rc = 0;
Packit Service 88ab54
Packit Service 88ab54
	if (login->protocolProfile == LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_LECP) {
Packit Service 88ab54
		char *assertionConsumerURL;
Packit Service 88ab54
Packit Service 88ab54
		lasso_check_good_rc(lasso_profile_saml20_setup_message_signature(profile,
Packit Service 88ab54
					profile->response));
Packit Service 88ab54
		remote_provider = lasso_server_get_provider(profile->server, profile->remote_providerID);
Packit Service 88ab54
		if (LASSO_IS_PROVIDER(remote_provider) == FALSE)
Packit Service 88ab54
			return critical_error(LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND);
Packit Service 88ab54
Packit Service 88ab54
		assertionConsumerURL = lasso_saml20_provider_get_assertion_consumer_service_url_by_binding(
Packit Service 88ab54
                         remote_provider, LASSO_SAML2_METADATA_BINDING_PAOS);
Packit Service 88ab54
Packit Service 88ab54
		assertion = login->private_data->saml2_assertion;
Packit Service 88ab54
		if (LASSO_IS_SAML2_ASSERTION(assertion) == TRUE) {
Packit Service 88ab54
			assertion->Subject->SubjectConfirmation->SubjectConfirmationData->Recipient
Packit Service 88ab54
						= g_strdup(assertionConsumerURL);
Packit Service 88ab54
		}
Packit Service 88ab54
Packit Service 88ab54
		/* If response is signed it MUST have Destination attribute, optional otherwise */
Packit Service 88ab54
		lasso_assign_string(((LassoSamlp2StatusResponse*)profile->response)->Destination,
Packit Service 88ab54
					assertionConsumerURL);
Packit Service 88ab54
Packit Service 88ab54
		/* build an ECP SOAP Response */
Packit Service 88ab54
		lasso_assign_new_string(profile->msg_body, lasso_node_export_to_ecp_soap_response(
Packit Service 88ab54
					LASSO_NODE(profile->response), assertionConsumerURL));
Packit Service 88ab54
		lasso_release_string(assertionConsumerURL);
Packit Service 88ab54
		return rc;
Packit Service 88ab54
	}
Packit Service 88ab54
Packit Service 88ab54
	return lasso_saml20_profile_build_artifact_response(LASSO_PROFILE(login));
Packit Service 88ab54
Packit Service 88ab54
cleanup:
Packit Service 88ab54
	return rc;
Packit Service 88ab54
}
Packit Service 88ab54
Packit Service 88ab54
/**
Packit Service 88ab54
 * lasso_saml20_login_process_paos_response_msg:
Packit Service 88ab54
 * @login: a #LassoLogin profile object
Packit Service 88ab54
 * @msg: ECP to SP PAOS message
Packit Service 88ab54
 *
Packit Service 88ab54
 * Process an ECP to SP PAOS response message.
Packit Service 88ab54
 *
Packit Service 88ab54
 * SAML2 Profile for ECP (Section 4.2) defines these steps for an ECP
Packit Service 88ab54
 * transaction
Packit Service 88ab54
 *
Packit Service 88ab54
 * 1. ECP issues HTTP Request to SP
Packit Service 88ab54
 * 2. SP issues <AuthnRequest> to ECP using PAOS
Packit Service 88ab54
 * 3. ECP determines IdP
Packit Service 88ab54
 * 4. ECP conveys <AuthnRequest> to IdP using SOAP
Packit Service 88ab54
 * 5. IdP identifies principal
Packit Service 88ab54
 * 6. IdP issues <Response> to ECP, targeted at SP using SOAP
Packit Service 88ab54
 * 7. ECP conveys <Response> to SP using PAOS
Packit Service 88ab54
 * 8. SP grants or denies access to principal
Packit Service 88ab54
 *
Packit Service 88ab54
 * This function is used in the implemention of Step 8 in an SP. The
Packit Service 88ab54
 * ECP response from Step 7 has been received from the ECP client, the
Packit Service 88ab54
 * SP must now parse the response and act upon the result of the Authn
Packit Service 88ab54
 * request the SP issued in Step 2. If the SOAP body contains a
Packit Service 88ab54
 * samlp:Response with a saml:Assertion the assertion is processed in
Packit Service 88ab54
 * the context of the @login parameter.
Packit Service 88ab54
 *
Packit Service 88ab54
 * The response may contain in the SOAP header a paos:Response or
Packit Service 88ab54
 * ecp:RelayState elment, both are optional. If the ecp:RelayState is
Packit Service 88ab54
 * present it is assigned to the #LassoProfile.msg_relayState
Packit Service 88ab54
 * field. If the paos:Response is present it's refToMessageID
Packit Service 88ab54
 * attribute is assigned to the #LassoProfile.msg_messageID field.
Packit Service 88ab54
 */
Packit Service 88ab54
gint
Packit Service 88ab54
lasso_saml20_login_process_paos_response_msg(LassoLogin *login, gchar *msg)
Packit Service 88ab54
{
Packit Service 88ab54
	LassoSoapHeader *header = NULL;
Packit Service 88ab54
	LassoProfile *profile;
Packit Service 16967e
	int rc;
Packit Service 88ab54
Packit Service 88ab54
	lasso_null_param(msg);
Packit Service 88ab54
Packit Service 88ab54
	profile = LASSO_PROFILE(login);
Packit Service 88ab54
Packit Service 16967e
        /*
Packit Service 16967e
         * lasso_saml20_profile_process_soap_response_with_headers()
Packit Service 16967e
         * performs a signature check on the SAML message. A signature
Packit Service 16967e
         * can also appear on the assertion which is checked by
Packit Service 16967e
         * lasso_saml20_login_process_response_status_and_assertion()
Packit Service 16967e
         * (below). Therefore if the error is SIGNATURE_NOT_FOUND we
Packit Service 16967e
         * proceed because
Packit Service 16967e
         * lasso_saml20_login_process_response_status_and_assertion()
Packit Service 16967e
         * will test the signature on the assertion.
Packit Service 16967e
         */
Packit Service 16967e
	rc = lasso_saml20_profile_process_soap_response_with_headers(profile, msg, &header);
Packit Service 16967e
        if (rc != 0 && rc != LASSO_DS_ERROR_SIGNATURE_NOT_FOUND) {
Packit Service 16967e
            return rc;
Packit Service 16967e
        }
Packit Service 88ab54
Packit Service 88ab54
	/*
Packit Service 88ab54
	 * If the SOAP message contained a header check for the optional
Packit Service 16967e
	 * paos:Response and ecp:RelayState elements, if they exist extract their
Packit Service 16967e
	 * values into the profile.
Packit Service 88ab54
	 */
Packit Service 88ab54
	if (header) {
Packit Service 88ab54
		GList *i = NULL;
Packit Service 88ab54
		LassoEcpRelayState *ecp_relaystate = NULL;
Packit Service 88ab54
		LassoPaosResponse *paos_response = NULL;
Packit Service 88ab54
Packit Service 88ab54
		lasso_foreach(i, header->Other) {
Packit Service 88ab54
			if (!ecp_relaystate && LASSO_IS_ECP_RELAYSTATE(i->data)) {
Packit Service 88ab54
				ecp_relaystate = (LassoEcpRelayState *)i->data;
Packit Service 88ab54
			} else if (!paos_response && LASSO_IS_PAOS_RESPONSE(i->data)) {
Packit Service 88ab54
				paos_response = (LassoPaosResponse *)i->data;
Packit Service 88ab54
			}
Packit Service 88ab54
			if (ecp_relaystate && paos_response) break;
Packit Service 88ab54
		}
Packit Service 88ab54
		if (ecp_relaystate) {
Packit Service 88ab54
			lasso_assign_string(profile->msg_relayState, ecp_relaystate->RelayState);
Packit Service 88ab54
		}
Packit Service 88ab54
		if (paos_response) {
Packit Service 88ab54
			lasso_profile_set_message_id(profile, paos_response->refToMessageID);
Packit Service 88ab54
		}
Packit Service 88ab54
		lasso_release_gobject(header);
Packit Service 88ab54
	}
Packit Service 88ab54
Packit Service 16967e
	rc = lasso_saml20_login_process_response_status_and_assertion(login);
Packit Service 16967e
	return rc;
Packit Service 88ab54
}
Packit Service 88ab54
Packit Service 88ab54
/**
Packit Service 88ab54
 * lasso_saml20_login_process_authn_response_msg:
Packit Service 88ab54
 * @login: a #LassoLogin profile object
Packit Service 88ab54
 * @authn_response_msg: a string containg a response msg to an #LassoSaml2AuthnRequest
Packit Service 88ab54
 *
Packit Service 88ab54
 * Parse a response made using binding HTTP-Redirect, HTTP-Post or HTTP-SOAP. Any signature
Packit Service 88ab54
 * validation error is reported.
Packit Service 88ab54
 *
Packit Service 88ab54
 * Return value: 0 if succesfull, an error code otherwise.
Packit Service 88ab54
 */
Packit Service 88ab54
gint
Packit Service 88ab54
lasso_saml20_login_process_authn_response_msg(LassoLogin *login, gchar *authn_response_msg)
Packit Service 88ab54
{
Packit Service 88ab54
	LassoProfile *profile = NULL;
Packit Service 88ab54
	LassoSamlp2Response *samlp2_response = NULL;
Packit Service 88ab54
	LassoHttpMethod response_method = LASSO_HTTP_METHOD_NONE;
Packit Service 88ab54
	int rc = 0;
Packit Service 88ab54
Packit Service 88ab54
	lasso_null_param(authn_response_msg);
Packit Service 88ab54
Packit Service 88ab54
	/* parse the message */
Packit Service 88ab54
	profile = LASSO_PROFILE(login);
Packit Service 88ab54
	samlp2_response = (LassoSamlp2Response*)lasso_samlp2_response_new();
Packit Service 88ab54
	rc = lasso_saml20_profile_process_any_response(profile,
Packit Service 88ab54
		(LassoSamlp2StatusResponse*)samlp2_response, &response_method,
Packit Service 88ab54
		authn_response_msg);
Packit Service 88ab54
Packit Service 88ab54
	if (response_method != LASSO_HTTP_METHOD_POST) {
Packit Service 88ab54
		/* Only HTTP-Post binding is possible through this method */
Packit Service 88ab54
		goto_cleanup_with_rc(LASSO_PROFILE_ERROR_UNSUPPORTED_PROFILE);
Packit Service 88ab54
	}
Packit Service 88ab54
Packit Service 88ab54
	/* Skip signature errors, let lasso_saml20_login_process_response_status_and_assertion
Packit Service 88ab54
	 * handle them */
Packit Service 88ab54
	goto_cleanup_if_fail (rc == 0 || rc == LASSO_LOGIN_ERROR_STATUS_NOT_SUCCESS || rc ==
Packit Service 88ab54
			LASSO_PROFILE_ERROR_CANNOT_VERIFY_SIGNATURE);
Packit Service 88ab54
Packit Service 88ab54
	rc = lasso_saml20_login_process_response_status_and_assertion(login);
Packit Service 88ab54
cleanup:
Packit Service 88ab54
	lasso_release_gobject(samlp2_response);
Packit Service 88ab54
	return rc;
Packit Service 88ab54
}
Packit Service 88ab54
Packit Service 88ab54
gint
Packit Service 88ab54
lasso_saml20_login_process_response_msg(LassoLogin *login, gchar *response_msg)
Packit Service 88ab54
{
Packit Service 88ab54
	LassoProfile *profile = LASSO_PROFILE(login);
Packit Service 88ab54
	int rc = 0;
Packit Service 88ab54
Packit Service 88ab54
	rc = lasso_saml20_profile_process_artifact_response(profile, response_msg);
Packit Service 88ab54
	if (rc) {
Packit Service 88ab54
		return rc;
Packit Service 88ab54
	}
Packit Service 88ab54
	if (LASSO_IS_SAMLP2_ARTIFACT_RESPONSE(login->parent.response)) {
Packit Service 88ab54
		return lasso_saml20_login_process_authn_request_msg(login, NULL);
Packit Service 88ab54
	} else {
Packit Service 88ab54
		return lasso_saml20_login_process_response_status_and_assertion(login);
Packit Service 88ab54
	}
Packit Service 88ab54
}
Packit Service 88ab54
Packit Service 88ab54
static gint
Packit Service 88ab54
lasso_saml20_login_check_assertion_signature(LassoLogin *login,
Packit Service 88ab54
		LassoSaml2Assertion *assertion)
Packit Service 88ab54
{
Packit Service 88ab54
	xmlNode *original_node = NULL;
Packit Service 88ab54
	LassoSaml2NameID *Issuer = NULL;
Packit Service 88ab54
	LassoServer *server = NULL;
Packit Service 88ab54
	LassoProfile *profile = NULL;
Packit Service 88ab54
	char *remote_provider_id = NULL;
Packit Service 88ab54
	LassoProvider *remote_provider;
Packit Service 88ab54
	int rc = 0;
Packit Service 88ab54
Packit Service 88ab54
	lasso_bad_param(SAML2_ASSERTION, assertion);
Packit Service 88ab54
Packit Service 88ab54
	profile = (LassoProfile*)login;
Packit Service 88ab54
	lasso_extract_node_or_fail(server, lasso_profile_get_server(profile),
Packit Service 88ab54
			SERVER, LASSO_PROFILE_ERROR_MISSING_SERVER);
Packit Service 88ab54
Packit Service 88ab54
	/* Get an issuer */
Packit Service 88ab54
	Issuer = assertion->Issuer;
Packit Service 88ab54
	if (! Issuer || /* No issuer */
Packit Service 88ab54
			! Issuer->content || /* No issuer content */
Packit Service 88ab54
			(Issuer->Format &&
Packit Service 88ab54
			 lasso_strisnotequal(Issuer->Format,LASSO_SAML2_NAME_IDENTIFIER_FORMAT_ENTITY)))
Packit Service 88ab54
		/* Issuer format is not entity */
Packit Service 88ab54
	{
Packit Service 88ab54
		rc = LASSO_PROFILE_ERROR_MISSING_ISSUER;
Packit Service 88ab54
		goto cleanup;
Packit Service 88ab54
	} else {
Packit Service 88ab54
		remote_provider_id = Issuer->content;
Packit Service 88ab54
	}
Packit Service 88ab54
	remote_provider = lasso_server_get_provider(server, remote_provider_id);
Packit Service 88ab54
	goto_cleanup_if_fail_with_rc(remote_provider, LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND);
Packit Service 88ab54
Packit Service 88ab54
	/* Get the original node */
Packit Service 88ab54
	original_node = lasso_node_get_original_xmlnode(LASSO_NODE(assertion));
Packit Service 88ab54
	goto_cleanup_if_fail_with_rc(original_node, LASSO_PROFILE_ERROR_CANNOT_VERIFY_SIGNATURE);
Packit Service 88ab54
Packit Service 88ab54
	rc = profile->signature_status = lasso_provider_verify_saml_signature(remote_provider, original_node, NULL);
Packit Service 88ab54
Packit Service 88ab54
#define log_verify_assertion_signature_error(msg) \
Packit Service 88ab54
			message(G_LOG_LEVEL_WARNING, "Could not verify signature of assertion" \
Packit Service 88ab54
					"ID:%s, " msg ".", assertion->ID);
Packit Service 88ab54
cleanup:
Packit Service 88ab54
	switch (rc) {
Packit Service 88ab54
		case LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND:
Packit Service 88ab54
			log_verify_assertion_signature_error("Issuer is unknown");
Packit Service 88ab54
			break;
Packit Service 88ab54
		case LASSO_PROFILE_ERROR_MISSING_ISSUER:
Packit Service 88ab54
			log_verify_assertion_signature_error(
Packit Service 88ab54
				"no Issuer found or Issuer has bad format");
Packit Service 88ab54
			break;
Packit Service 88ab54
		case LASSO_PROFILE_ERROR_CANNOT_VERIFY_SIGNATURE:
Packit Service 88ab54
			log_verify_assertion_signature_error(
Packit Service 88ab54
				" the original xmlNode is certainly not accessible anymore");
Packit Service 88ab54
Packit Service 88ab54
		default:
Packit Service 88ab54
			break;
Packit Service 88ab54
	}
Packit Service 88ab54
#undef log_verify_assertion_signature_error
Packit Service 88ab54
	return rc;
Packit Service 88ab54
}
Packit Service 88ab54
Packit Service 88ab54
static gboolean
Packit Service 88ab54
_lasso_check_assertion_issuer(LassoSaml2Assertion *assertion, const gchar *provider_id)
Packit Service 88ab54
{
Packit Service 88ab54
	if (! LASSO_SAML2_ASSERTION(assertion) || ! provider_id)
Packit Service 88ab54
		return FALSE;
Packit Service 88ab54
Packit Service 88ab54
	if (! assertion->Issuer || ! assertion->Issuer->content)
Packit Service 88ab54
		return FALSE;
Packit Service 88ab54
Packit Service 88ab54
	return lasso_strisequal(assertion->Issuer->content,provider_id);
Packit Service 88ab54
}
Packit Service 88ab54
Packit Service 88ab54
static gint
Packit Service 88ab54
_lasso_saml20_login_decrypt_assertion(LassoLogin *login, LassoSamlp2Response *samlp2_response)
Packit Service 88ab54
{
Packit Service 88ab54
	GList *encryption_private_keys = NULL;
Packit Service 88ab54
	GList *it = NULL;
Packit Service 88ab54
	gboolean at_least_one_decryption_failture = FALSE;
Packit Service 88ab54
	gboolean at_least_one_malformed_element = FALSE;
Packit Service 88ab54
Packit Service 88ab54
	if (! samlp2_response->EncryptedAssertion)
Packit Service 88ab54
		return 0; /* nothing to do */
Packit Service 88ab54
Packit Service 88ab54
	encryption_private_keys = lasso_server_get_encryption_private_keys(login->parent.server);
Packit Service 88ab54
	if (! encryption_private_keys) {
Packit Service 88ab54
			message(G_LOG_LEVEL_WARNING, "Missing private encryption key, cannot decrypt assertions.");
Packit Service 88ab54
			return LASSO_DS_ERROR_DECRYPTION_FAILED_MISSING_PRIVATE_KEY;
Packit Service 88ab54
	}
Packit Service 88ab54
Packit Service 88ab54
	lasso_foreach (it, samlp2_response->EncryptedAssertion) {
Packit Service 88ab54
		LassoSaml2EncryptedElement *encrypted_assertion;
Packit Service 88ab54
		LassoSaml2Assertion * assertion = NULL;
Packit Service 88ab54
		int rc1 = 0;
Packit Service 88ab54
Packit Service 88ab54
		if (! LASSO_IS_SAML2_ENCRYPTED_ELEMENT(it->data)) {
Packit Service 88ab54
			message(G_LOG_LEVEL_WARNING, "EncryptedAssertion contains a non EncryptedElement object");
Packit Service 88ab54
			at_least_one_malformed_element |= TRUE;
Packit Service 88ab54
			continue;
Packit Service 88ab54
		}
Packit Service 88ab54
		encrypted_assertion = (LassoSaml2EncryptedElement*)it->data;
Packit Service 88ab54
		lasso_foreach_full_begin(xmlSecKey*, encryption_private_key, it,
Packit Service 88ab54
				encryption_private_keys)
Packit Service 88ab54
		{
Packit Service 88ab54
			rc1 = lasso_saml2_encrypted_element_decrypt(encrypted_assertion, encryption_private_key, (LassoNode**)&assertion);
Packit Service 88ab54
			if (rc1 == 0)
Packit Service 88ab54
				break;
Packit Service 88ab54
		}
Packit Service 88ab54
		lasso_foreach_full_end();
Packit Service 88ab54
		if (rc1 == LASSO_DS_ERROR_DECRYPTION_FAILED) {
Packit Service 88ab54
			message(G_LOG_LEVEL_WARNING, "Could not decrypt the EncryptedKey");
Packit Service 88ab54
			at_least_one_decryption_failture |= TRUE;
Packit Service 88ab54
			continue;
Packit Service 88ab54
		} else if (rc1) {
Packit Service 88ab54
			message(G_LOG_LEVEL_WARNING, "Could not decrypt an assertion: %s", lasso_strerror(rc1));
Packit Service 88ab54
			at_least_one_decryption_failture |= TRUE;
Packit Service 88ab54
			continue;
Packit Service 88ab54
		}
Packit Service 88ab54
Packit Service 88ab54
		if (! LASSO_IS_SAML2_ASSERTION(assertion)) {
Packit Service 88ab54
			message(G_LOG_LEVEL_WARNING, "EncryptedAssertion contains something that is not an assertion");
Packit Service 88ab54
			lasso_release_gobject(assertion);
Packit Service 88ab54
			continue;
Packit Service 88ab54
		}
Packit Service 88ab54
		/* copy the assertion to the clear assertion list */
Packit Service 88ab54
		lasso_list_add_new_gobject(samlp2_response->Assertion, assertion);
Packit Service 88ab54
	}
Packit Service 88ab54
	
Packit Service 88ab54
	if (at_least_one_decryption_failture) {
Packit Service 88ab54
		return LASSO_DS_ERROR_DECRYPTION_FAILED;
Packit Service 88ab54
	}
Packit Service 88ab54
	if (at_least_one_malformed_element) {
Packit Service 88ab54
		return LASSO_XML_ERROR_SCHEMA_INVALID_FRAGMENT;
Packit Service 88ab54
	}
Packit Service 88ab54
	return 0;
Packit Service 88ab54
}
Packit Service 88ab54
Packit Service 88ab54
static gint
Packit Service 88ab54
lasso_saml20_login_process_response_status_and_assertion(LassoLogin *login)
Packit Service 88ab54
{
Packit Service 88ab54
	LassoSamlp2StatusResponse *response;
Packit Service 88ab54
	LassoSamlp2Response *samlp2_response = NULL;
Packit Service 88ab54
	LassoProfile *profile;
Packit Service 88ab54
	char *status_value;
Packit Service 88ab54
	lasso_error_t rc = 0;
Packit Service 88ab54
	lasso_error_t assertion_signature_status = 0;
Packit Service 88ab54
	LassoProfileSignatureVerifyHint verify_hint;
Packit Service 88ab54
Packit Service 88ab54
	profile = &login->parent;
Packit Service 88ab54
	lasso_extract_node_or_fail(response, profile->response, SAMLP2_STATUS_RESPONSE,
Packit Service 88ab54
			LASSO_PROFILE_ERROR_INVALID_MSG);
Packit Service 88ab54
	lasso_extract_node_or_fail(samlp2_response, response, SAMLP2_RESPONSE,
Packit Service 88ab54
			LASSO_PROFILE_ERROR_INVALID_MSG);
Packit Service 88ab54
Packit Service 88ab54
	if (response->Status == NULL || ! LASSO_IS_SAMLP2_STATUS(response->Status) ||
Packit Service 88ab54
			response->Status->StatusCode == NULL ||
Packit Service 88ab54
			response->Status->StatusCode->Value == NULL) {
Packit Service 88ab54
		return LASSO_PROFILE_ERROR_MISSING_STATUS_CODE;
Packit Service 88ab54
	}
Packit Service 88ab54
Packit Service 88ab54
	status_value = response->Status->StatusCode->Value;
Packit Service 88ab54
	if (status_value && lasso_strisnotequal(status_value,LASSO_SAML2_STATUS_CODE_SUCCESS)) {
Packit Service 88ab54
		if (lasso_strisequal(status_value,LASSO_SAML2_STATUS_CODE_REQUEST_DENIED))
Packit Service 88ab54
			return LASSO_LOGIN_ERROR_REQUEST_DENIED;
Packit Service 88ab54
		if (lasso_strisequal(status_value,LASSO_SAML2_STATUS_CODE_RESPONDER) ||
Packit Service 88ab54
				lasso_strisequal(status_value,LASSO_SAML2_STATUS_CODE_REQUESTER)) {
Packit Service 88ab54
			/* samlp:Responder */
Packit Service 88ab54
			if (response->Status->StatusCode->StatusCode &&
Packit Service 88ab54
					response->Status->StatusCode->StatusCode->Value) {
Packit Service 88ab54
				status_value = response->Status->StatusCode->StatusCode->Value;
Packit Service 88ab54
				if (lasso_strisequal(status_value,LASSO_LIB_STATUS_CODE_FEDERATION_DOES_NOT_EXIST)) {
Packit Service 88ab54
					return LASSO_LOGIN_ERROR_FEDERATION_NOT_FOUND;
Packit Service 88ab54
				}
Packit Service 88ab54
				if (lasso_strisequal(status_value,LASSO_LIB_STATUS_CODE_UNKNOWN_PRINCIPAL)) {
Packit Service 88ab54
					return LASSO_LOGIN_ERROR_UNKNOWN_PRINCIPAL;
Packit Service 88ab54
				}
Packit Service 88ab54
			}
Packit Service 88ab54
		}
Packit Service 88ab54
		return LASSO_LOGIN_ERROR_STATUS_NOT_SUCCESS;
Packit Service 88ab54
	}
Packit Service 88ab54
Packit Service 88ab54
	/* Decrypt all EncryptedAssertions */
Packit Service 88ab54
	_lasso_saml20_login_decrypt_assertion(login, samlp2_response);
Packit Service 88ab54
	/* traverse all assertions */
Packit Service 88ab54
	goto_cleanup_if_fail_with_rc (samlp2_response->Assertion != NULL,
Packit Service 88ab54
			LASSO_PROFILE_ERROR_MISSING_ASSERTION);
Packit Service 88ab54
Packit Service 88ab54
	verify_hint = lasso_profile_get_signature_verify_hint(profile);
Packit Service 88ab54
Packit Service 88ab54
	lasso_foreach_full_begin(LassoSaml2Assertion*, assertion, it, samlp2_response->Assertion);
Packit Service 88ab54
		LassoSaml2Subject *subject = NULL;
Packit Service 88ab54
Packit Service 88ab54
		lasso_assign_gobject (login->private_data->saml2_assertion, assertion);
Packit Service 88ab54
Packit Service 88ab54
		/* If signature has already been verified on the message, and assertion has the same
Packit Service 88ab54
		 * issuer as the message, the assertion is covered. So no need to verify a second
Packit Service 88ab54
		 * time */
Packit Service 88ab54
		if (profile->signature_status != 0 
Packit Service 88ab54
			|| ! _lasso_check_assertion_issuer(assertion,
Packit Service 88ab54
				profile->remote_providerID)
Packit Service 88ab54
			|| verify_hint == LASSO_PROFILE_SIGNATURE_VERIFY_HINT_FORCE) {
Packit Service 88ab54
			assertion_signature_status = lasso_saml20_login_check_assertion_signature(login,
Packit Service 88ab54
					assertion);
Packit Service 88ab54
			/* If signature validation fails, it is the return code for this function */
Packit Service 88ab54
			if (assertion_signature_status) {
Packit Service 88ab54
				rc = LASSO_PROFILE_ERROR_CANNOT_VERIFY_SIGNATURE;
Packit Service 88ab54
			}
Packit Service 88ab54
		}
Packit Service 88ab54
Packit Service 88ab54
		lasso_extract_node_or_fail(subject, assertion->Subject, SAML2_SUBJECT,
Packit Service 88ab54
				LASSO_PROFILE_ERROR_MISSING_SUBJECT);
Packit Service 88ab54
Packit Service 88ab54
		/* Verify Subject->SubjectConfirmationData->InResponseTo */
Packit Service 88ab54
		if (login->private_data->request_id) {
Packit Service 88ab54
			const char *in_response_to = lasso_saml2_assertion_get_in_response_to(assertion);
Packit Service 88ab54
Packit Service 88ab54
			if (lasso_strisnotequal(in_response_to,login->private_data->request_id)) {
Packit Service 88ab54
				rc = LASSO_LOGIN_ERROR_ASSERTION_DOES_NOT_MATCH_REQUEST_ID;
Packit Service 88ab54
				goto cleanup;
Packit Service 88ab54
			}
Packit Service 88ab54
		}
Packit Service 88ab54
Packit Service 88ab54
		/** Handle nameid */
Packit Service 88ab54
		lasso_check_good_rc(lasso_saml20_profile_process_name_identifier_decryption(profile,
Packit Service 88ab54
					&subject->NameID, &subject->EncryptedID));
Packit Service 88ab54
	lasso_foreach_full_end();
Packit Service 88ab54
Packit Service 88ab54
	switch (verify_hint) {
Packit Service 88ab54
		case LASSO_PROFILE_SIGNATURE_VERIFY_HINT_FORCE:
Packit Service 88ab54
		case LASSO_PROFILE_SIGNATURE_VERIFY_HINT_MAYBE:
Packit Service 88ab54
			break;
Packit Service 88ab54
		case LASSO_PROFILE_SIGNATURE_VERIFY_HINT_IGNORE:
Packit Service 88ab54
			/* ignore signature errors */
Packit Service 88ab54
			if (rc == LASSO_PROFILE_ERROR_CANNOT_VERIFY_SIGNATURE) {
Packit Service 88ab54
				rc = 0;
Packit Service 88ab54
			}
Packit Service 88ab54
			break;
Packit Service 88ab54
		default:
Packit Service 88ab54
			g_assert(0);
Packit Service 88ab54
	}
Packit Service 88ab54
cleanup:
Packit Service 88ab54
	return rc;
Packit Service 88ab54
}
Packit Service 88ab54
Packit Service 88ab54
Packit Service 88ab54
gint
Packit Service 88ab54
lasso_saml20_login_accept_sso(LassoLogin *login)
Packit Service 88ab54
{
Packit Service 88ab54
	LassoProfile *profile;
Packit Service 88ab54
	LassoSaml2Assertion *assertion;
Packit Service 88ab54
	GList *previous_assertion_ids, *t;
Packit Service 88ab54
	LassoSaml2NameID *ni;
Packit Service 88ab54
	LassoFederation *federation;
Packit Service 88ab54
Packit Service 88ab54
	profile = LASSO_PROFILE(login);
Packit Service 88ab54
	if (LASSO_SAMLP2_RESPONSE(profile->response)->Assertion == NULL)
Packit Service 88ab54
		return LASSO_PROFILE_ERROR_MISSING_ASSERTION;
Packit Service 88ab54
Packit Service 88ab54
	assertion = LASSO_SAMLP2_RESPONSE(profile->response)->Assertion->data;
Packit Service 88ab54
	if (assertion == NULL)
Packit Service 88ab54
		return LASSO_PROFILE_ERROR_MISSING_ASSERTION;
Packit Service 88ab54
Packit Service 88ab54
	previous_assertion_ids = lasso_session_get_assertion_ids(profile->session,
Packit Service 88ab54
			profile->remote_providerID);
Packit Service 88ab54
	lasso_foreach(t, previous_assertion_ids) {
Packit Service 88ab54
		if (lasso_strisequal(t->data, assertion->ID)) {
Packit Service 88ab54
			lasso_release_list_of_strings(previous_assertion_ids);
Packit Service 88ab54
			return LASSO_LOGIN_ERROR_ASSERTION_REPLAY;
Packit Service 88ab54
		}
Packit Service 88ab54
	}
Packit Service 88ab54
	lasso_release_list_of_strings(previous_assertion_ids);
Packit Service 88ab54
Packit Service 88ab54
	lasso_session_add_assertion(profile->session, profile->remote_providerID,
Packit Service 88ab54
			LASSO_NODE(assertion));
Packit Service 88ab54
Packit Service 88ab54
	if (assertion->Subject && assertion->Subject->NameID) {
Packit Service 88ab54
		ni = assertion->Subject->NameID;
Packit Service 88ab54
	} else {
Packit Service 88ab54
		return LASSO_PROFILE_ERROR_MISSING_NAME_IDENTIFIER;
Packit Service 88ab54
	}
Packit Service 88ab54
Packit Service 88ab54
	/* create federation, only if nameidentifier format is Federated */
Packit Service 88ab54
	if (ni && ni->Format
Packit Service 88ab54
			&& lasso_strisequal(ni->Format,LASSO_SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT)) {
Packit Service 88ab54
		federation = lasso_federation_new(LASSO_PROFILE(login)->remote_providerID);
Packit Service 88ab54
Packit Service 88ab54
		lasso_assign_gobject(federation->local_nameIdentifier, ni);
Packit Service 88ab54
		/* add federation in identity */
Packit Service 88ab54
		lasso_identity_add_federation(LASSO_PROFILE(login)->identity, federation);
Packit Service 88ab54
	}
Packit Service 88ab54
Packit Service 88ab54
	return 0;
Packit Service 88ab54
}
Packit Service 88ab54
Packit Service 88ab54
gint
Packit Service 88ab54
lasso_saml20_login_build_authn_response_msg(LassoLogin *login)
Packit Service 88ab54
{
Packit Service 88ab54
	LassoProfile *profile;
Packit Service 88ab54
	LassoProvider *remote_provider = NULL;
Packit Service 88ab54
	LassoSaml2Assertion *assertion = NULL;
Packit Service 88ab54
	LassoHttpMethod http_method = LASSO_HTTP_METHOD_NONE;
Packit Service 88ab54
	char *url = NULL;
Packit Service 88ab54
	int rc = 0;
Packit Service 88ab54
Packit Service 88ab54
	profile = &login->parent;
Packit Service 88ab54
Packit Service 88ab54
	if (login->protocolProfile != LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_POST &&
Packit Service 88ab54
		login->protocolProfile != LASSO_LOGIN_PROTOCOL_PROFILE_REDIRECT) {
Packit Service 88ab54
		return critical_error(LASSO_PROFILE_ERROR_INVALID_PROTOCOLPROFILE);
Packit Service 88ab54
	}
Packit Service 88ab54
Packit Service 88ab54
	if (_lasso_login_must_sign_non_authn_request(login)) {
Packit Service 88ab54
		lasso_check_good_rc(lasso_profile_saml20_setup_message_signature(profile,
Packit Service 88ab54
					profile->response));
Packit Service 88ab54
	} else {
Packit Service 88ab54
		lasso_node_remove_signature(profile->response);
Packit Service 88ab54
	}
Packit Service 88ab54
Packit Service 88ab54
	remote_provider = lasso_server_get_provider(profile->server, profile->remote_providerID);
Packit Service 88ab54
	if (LASSO_IS_PROVIDER(remote_provider) == FALSE)
Packit Service 88ab54
		return critical_error(LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND);
Packit Service 88ab54
Packit Service 88ab54
	url = lasso_saml20_login_get_assertion_consumer_service_url(login, remote_provider);
Packit Service 88ab54
Packit Service 88ab54
	assertion = login->private_data->saml2_assertion;
Packit Service 88ab54
	if (LASSO_IS_SAML2_ASSERTION(assertion) && url) {
Packit Service 88ab54
		LassoSaml2SubjectConfirmationData *subject_confirmation_data;
Packit Service 88ab54
Packit Service 88ab54
		subject_confirmation_data =
Packit Service 88ab54
			lasso_saml2_assertion_get_subject_confirmation_data(assertion, TRUE);
Packit Service 88ab54
		lasso_assign_string(subject_confirmation_data->Recipient, url);
Packit Service 88ab54
	}
Packit Service 88ab54
Packit Service 88ab54
	/* If there is a non-encrypted NameID, fix the assertion in the session */
Packit Service 88ab54
	if (assertion && assertion->Subject && assertion->Subject->NameID) {
Packit Service 88ab54
		/* store assertion in session object */
Packit Service 88ab54
		if (profile->session == NULL) {
Packit Service 88ab54
			profile->session = lasso_session_new();
Packit Service 88ab54
		}
Packit Service 88ab54
		lasso_session_add_assertion(profile->session, profile->remote_providerID,
Packit Service 88ab54
				LASSO_NODE(assertion));
Packit Service 88ab54
	}
Packit Service 88ab54
Packit Service 88ab54
	switch (login->protocolProfile) {
Packit Service 88ab54
		case LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_POST:
Packit Service 88ab54
			http_method = LASSO_HTTP_METHOD_POST;
Packit Service 88ab54
			break;
Packit Service 88ab54
		case LASSO_LOGIN_PROTOCOL_PROFILE_REDIRECT:
Packit Service 88ab54
			http_method = LASSO_HTTP_METHOD_REDIRECT;
Packit Service 88ab54
			break;
Packit Service 88ab54
		default:
Packit Service 88ab54
			message(G_LOG_LEVEL_CRITICAL, "Cannot happen");
Packit Service 88ab54
			break;
Packit Service 88ab54
	}
Packit Service 88ab54
	lasso_check_good_rc(lasso_saml20_profile_build_response_msg(profile, NULL, http_method, url));
Packit Service 88ab54
Packit Service 88ab54
cleanup:
Packit Service 88ab54
	lasso_release_string(url);
Packit Service 88ab54
	return rc;
Packit Service 88ab54
}
Packit Service 88ab54
Packit Service 88ab54
static char*
Packit Service 88ab54
lasso_saml20_login_get_assertion_consumer_service_url(LassoLogin *login,
Packit Service 88ab54
	LassoProvider *remote_provider)
Packit Service 88ab54
{
Packit Service 88ab54
	LassoSamlp2AuthnRequest *request;
Packit Service 88ab54
	char *url = NULL;
Packit Service 88ab54
Packit Service 88ab54
	request = LASSO_SAMLP2_AUTHN_REQUEST(LASSO_PROFILE(login)->request);
Packit Service 88ab54
Packit Service 88ab54
	if (request->AssertionConsumerServiceURL) {
Packit Service 88ab54
		if (lasso_saml20_provider_check_assertion_consumer_service_url(remote_provider,
Packit Service 88ab54
					request->AssertionConsumerServiceURL,
Packit Service 88ab54
					request->ProtocolBinding)) {
Packit Service 88ab54
			return g_strdup(request->AssertionConsumerServiceURL);
Packit Service 88ab54
		}
Packit Service 88ab54
	}
Packit Service 88ab54
Packit Service 88ab54
	if (request->AssertionConsumerServiceIndex != -1 || request->ProtocolBinding == NULL) {
Packit Service 88ab54
		url = lasso_saml20_provider_get_assertion_consumer_service_url(remote_provider,
Packit Service 88ab54
				request->AssertionConsumerServiceIndex);
Packit Service 88ab54
	}
Packit Service 88ab54
Packit Service 88ab54
	if (url == NULL && request->ProtocolBinding) {
Packit Service 88ab54
		url = lasso_saml20_provider_get_assertion_consumer_service_url_by_binding(
Packit Service 88ab54
				remote_provider, request->ProtocolBinding);
Packit Service 88ab54
	}
Packit Service 88ab54
Packit Service 88ab54
	if (url == NULL) {
Packit Service 88ab54
		message(G_LOG_LEVEL_WARNING,
Packit Service 88ab54
				"can't find assertion consumer service url (going for default)");
Packit Service 88ab54
		url = lasso_saml20_provider_get_assertion_consumer_service_url(remote_provider, -1);
Packit Service 88ab54
	}
Packit Service 88ab54
Packit Service 88ab54
	return url;
Packit Service 88ab54
}
Packit Service 88ab54
Packit Service 88ab54
gint
Packit Service 88ab54
lasso_saml20_login_init_idp_initiated_authn_request(LassoLogin *login,
Packit Service 88ab54
		const gchar *remote_providerID)
Packit Service 88ab54
{
Packit Service 88ab54
	LassoProfile *profile = NULL;
Packit Service 88ab54
	LassoProvider *provider = NULL;
Packit Service 88ab54
	LassoServer *server = NULL;
Packit Service 88ab54
	gchar *default_name_id_format = NULL;
Packit Service 88ab54
	int rc = 0;
Packit Service 88ab54
Packit Service 88ab54
	profile = &login->parent;
Packit Service 88ab54
	lasso_extract_node_or_fail(server, lasso_profile_get_server(profile), SERVER,
Packit Service 88ab54
			LASSO_PROFILE_ERROR_MISSING_SERVER);
Packit Service 88ab54
	provider = lasso_server_get_provider(server, remote_providerID);
Packit Service 88ab54
	if (! LASSO_IS_PROVIDER(provider))
Packit Service 88ab54
		return LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND;
Packit Service 88ab54
Packit Service 88ab54
	/* fix roles */
Packit Service 88ab54
	server->parent.role = LASSO_PROVIDER_ROLE_IDP;
Packit Service 88ab54
	provider->role = LASSO_PROVIDER_ROLE_SP;
Packit Service 88ab54
Packit Service 88ab54
	lasso_assign_string(profile->remote_providerID, remote_providerID);
Packit Service 88ab54
	lasso_assign_new_gobject(profile->request, lasso_samlp2_authn_request_new());
Packit Service 88ab54
	lasso_assign_new_gobject(LASSO_SAMLP2_AUTHN_REQUEST(profile->request)->NameIDPolicy,
Packit Service 88ab54
			lasso_samlp2_name_id_policy_new());
Packit Service 88ab54
	lasso_assign_new_gobject(LASSO_SAMLP2_REQUEST_ABSTRACT(profile->request)->Issuer,
Packit Service 88ab54
			LASSO_SAML2_NAME_ID(lasso_saml2_name_id_new_with_string(
Packit Service 88ab54
					(char*)remote_providerID)));
Packit Service 88ab54
	default_name_id_format = lasso_provider_get_default_name_id_format(provider);
Packit Service 88ab54
	/* Change default NameIDFormat if default exists */
Packit Service 88ab54
	if (default_name_id_format) {
Packit Service 88ab54
		lasso_assign_new_string(LASSO_SAMLP2_AUTHN_REQUEST(profile->request)->NameIDPolicy->Format,
Packit Service 88ab54
				default_name_id_format);
Packit Service 88ab54
	} else {
Packit Service 88ab54
		/* we eventually used the default of the IDP (not of the target SP), so we reset to
Packit Service 88ab54
		 * Lasso default, that is Transient */
Packit Service 88ab54
		lasso_assign_string(LASSO_SAMLP2_AUTHN_REQUEST(profile->request)->NameIDPolicy->Format,
Packit Service 88ab54
				LASSO_SAML2_NAME_IDENTIFIER_FORMAT_TRANSIENT);
Packit Service 88ab54
	}
Packit Service 88ab54
	lasso_assign_string(LASSO_SAMLP2_AUTHN_REQUEST(profile->request)->NameIDPolicy->SPNameQualifier,
Packit Service 88ab54
		remote_providerID);
Packit Service 88ab54
cleanup:
Packit Service 88ab54
Packit Service 88ab54
	return rc;
Packit Service 88ab54
}