lasso_saml20_login_build_assertion(LassoLogin *login,
		const char *authenticationMethod,
		const char *authenticationInstant,
		const char *notBefore,
		const char *notOnOrAfter)
{
	LassoProfile *profile = &login->parent;
	LassoSaml2Assertion *assertion = NULL;
	LassoSaml2AudienceRestriction *audience_restriction = NULL;
	LassoSamlp2NameIDPolicy *name_id_policy = NULL;
	LassoSaml2NameID *name_id = NULL;
	LassoSaml2AuthnStatement *authentication_statement;
	LassoProvider *provider = NULL;
	LassoSamlp2Response *response = NULL;
	LassoSamlp2RequestAbstract *request_abstract = NULL;
	LassoSamlp2AuthnRequest *authn_request = NULL;
	gboolean do_encrypt_nameid = FALSE;
	gboolean do_encrypt_assertion = FALSE;
	int rc = 0;

	provider = lasso_server_get_provider(profile->server, profile->remote_providerID);

	if (provider) {
		do_encrypt_nameid = lasso_provider_get_encryption_mode(provider) &
			LASSO_ENCRYPTION_MODE_NAMEID;
		do_encrypt_assertion = lasso_provider_get_encryption_mode(provider) &
			LASSO_ENCRYPTION_MODE_ASSERTION;
	}

	if (LASSO_IS_SAMLP2_AUTHN_REQUEST(profile->request)) {
		authn_request = (LassoSamlp2AuthnRequest*)profile->request;
		request_abstract = &authn_request->parent;
	}
	goto_cleanup_if_fail_with_rc(LASSO_IS_SAMLP2_RESPONSE(profile->response),
			LASSO_PROFILE_ERROR_MISSING_RESPONSE);

	assertion = LASSO_SAML2_ASSERTION(lasso_saml2_assertion_new());
	assertion->ID = lasso_build_unique_id(32);
	lasso_assign_string(assertion->Version, "2.0");
	assertion->IssueInstant = lasso_get_current_time();
	assertion->Issuer = LASSO_SAML2_NAME_ID(lasso_saml2_name_id_new_with_string(
			LASSO_PROVIDER(profile->server)->ProviderID));
	assertion->Conditions = LASSO_SAML2_CONDITIONS(lasso_saml2_conditions_new());
	lasso_assign_string(assertion->Conditions->NotBefore, notBefore);
	lasso_assign_string(assertion->Conditions->NotOnOrAfter, notOnOrAfter);

	audience_restriction = LASSO_SAML2_AUDIENCE_RESTRICTION(
			lasso_saml2_audience_restriction_new());
	lasso_assign_string(audience_restriction->Audience, profile->remote_providerID);
	lasso_list_add_new_gobject(assertion->Conditions->AudienceRestriction, audience_restriction);

	assertion->Subject = LASSO_SAML2_SUBJECT(lasso_saml2_subject_new());
	assertion->Subject->SubjectConfirmation = LASSO_SAML2_SUBJECT_CONFIRMATION(
			lasso_saml2_subject_confirmation_new());
	assertion->Subject->SubjectConfirmation->Method = g_strdup(
			LASSO_SAML2_CONFIRMATION_METHOD_BEARER);
	assertion->Subject->SubjectConfirmation->SubjectConfirmationData =
		LASSO_SAML2_SUBJECT_CONFIRMATION_DATA(
			lasso_saml2_subject_confirmation_data_new());
	lasso_assign_string(
		assertion->Subject->SubjectConfirmation->SubjectConfirmationData->NotOnOrAfter,
		notOnOrAfter);

	/* If request is present, refer to it in the response */
	if (authn_request) {
		if (request_abstract->ID) {
			lasso_assign_string(assertion->Subject->SubjectConfirmation->SubjectConfirmationData->InResponseTo,
					request_abstract->ID);
			/*
			 * It MUST NOT contain a NotBefore attribute. If
			 * the containing message is in response to an <AuthnRequest>,
			 * then the InResponseTo attribute MUST match the request's ID.
			 */
			lasso_release_string(assertion->Subject->SubjectConfirmation->SubjectConfirmationData->NotBefore);
		}
		name_id_policy = authn_request->NameIDPolicy;
	}
	/* TRANSIENT */
	if (!name_id_policy || name_id_policy->Format == NULL ||
			lasso_strisequal(name_id_policy->Format,LASSO_SAML2_NAME_IDENTIFIER_FORMAT_UNSPECIFIED) ||
			lasso_strisequal(name_id_policy->Format,LASSO_SAML2_NAME_IDENTIFIER_FORMAT_TRANSIENT)) {
		char *id = lasso_build_unique_id(32);

		name_id = (LassoSaml2NameID*)lasso_saml2_name_id_new_with_string(id);
		lasso_release_string(id);
		lasso_assign_string(name_id->NameQualifier,
				lasso_provider_get_sp_name_qualifier(&profile->server->parent));
		lasso_assign_string(name_id->Format, LASSO_SAML2_NAME_IDENTIFIER_FORMAT_TRANSIENT);
		assertion->Subject->NameID = name_id;
	/* FEDERATED */
	} else if (lasso_strisequal(name_id_policy->Format,
				LASSO_SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT) ||
			lasso_strisequal(name_id_policy->Format,
				LASSO_SAML2_NAME_IDENTIFIER_FORMAT_ENCRYPTED))
		{
		LassoFederation *federation;

		federation = _lasso_login_saml20_get_federation(login);
		goto_cleanup_if_fail_with_rc(federation != NULL,
				LASSO_PROFILE_ERROR_FEDERATION_NOT_FOUND);

		if (lasso_strisequal(name_id_policy->Format,LASSO_SAML2_NAME_IDENTIFIER_FORMAT_ENCRYPTED)) {
			do_encrypt_nameid = TRUE;
		}
		lasso_assign_gobject(assertion->Subject->NameID,
				federation->local_nameIdentifier);
	/* ALL OTHER KIND OF NAME ID FORMATS */
	} else {
		/* caller must set the name identifier content afterwards */
		name_id = LASSO_SAML2_NAME_ID(lasso_saml2_name_id_new());
		lasso_assign_string(name_id->NameQualifier,
				LASSO_PROVIDER(profile->server)->ProviderID);
		lasso_assign_string(name_id->Format, name_id_policy->Format);
		assertion->Subject->NameID = name_id;
		if (do_encrypt_nameid) {
			message(G_LOG_LEVEL_WARNING, "NameID encryption is currently not "
					"supported with non transient or persisent NameID format");
			do_encrypt_nameid = FALSE;
		}
	}

	authentication_statement = LASSO_SAML2_AUTHN_STATEMENT(lasso_saml2_authn_statement_new());
	authentication_statement->AuthnInstant = g_strdup(authenticationInstant);
	authentication_statement->AuthnContext = LASSO_SAML2_AUTHN_CONTEXT(
			lasso_saml2_authn_context_new());
	authentication_statement->AuthnContext->AuthnContextClassRef = g_strdup(
			authenticationMethod);

	/* if remote provider supports logout profile, add a session index == ID of the assertion */
	if (lasso_provider_get_first_http_method(&login->parent.server->parent,
				provider, LASSO_MD_PROTOCOL_TYPE_SINGLE_LOGOUT) != LASSO_HTTP_METHOD_NONE) {
		lasso_assign_string(authentication_statement->SessionIndex, assertion->ID);
	}
	lasso_list_add_new_gobject(assertion->AuthnStatement, authentication_statement);

	/* Save signing material in assertion private datas to be able to sign later */
	lasso_check_good_rc(lasso_server_saml2_assertion_setup_signature(profile->server,
				assertion));

	/* Encrypt NameID */
	if (do_encrypt_nameid) {
		/* store assertion in session object */
		if (profile->session == NULL) {
			profile->session = lasso_session_new();
		}

		lasso_session_add_assertion(profile->session, profile->remote_providerID,
				LASSO_NODE(assertion));

		/* FIXME: as with assertions, it should be possible to setup encryption of NameID for later */
		goto_cleanup_if_fail_with_rc(provider != NULL, LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND);

		assertion->Subject->EncryptedID = (LassoSaml2EncryptedElement*)lasso_node_encrypt(
			(LassoNode*)assertion->Subject->NameID,
			lasso_provider_get_encryption_public_key(provider),
			lasso_provider_get_encryption_sym_key_type(provider),
			provider->ProviderID);
		goto_cleanup_if_fail_with_rc(assertion->Subject->EncryptedID != NULL,
				LASSO_DS_ERROR_ENCRYPTION_FAILED);
		lasso_release_gobject(assertion->Subject->NameID);
	}

	/* Save encryption material in assertion private datas to be able to encrypt later */
	if (do_encrypt_assertion) {
		lasso_node_set_encryption((LassoNode*)assertion,
				lasso_provider_get_encryption_public_key(provider),
				lasso_provider_get_encryption_sym_key_type(provider));
	}

	response = LASSO_SAMLP2_RESPONSE(profile->response);
	lasso_list_add_gobject(response->Assertion, assertion);
	lasso_assign_gobject(login->private_data->saml2_assertion, assertion);
cleanup:
	lasso_release_gobject(assertion);
	return rc;
}