summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Dauvergne <bdauvergne@entrouvert.com>2009-03-27 15:05:07 +0000
committerBenjamin Dauvergne <bdauvergne@entrouvert.com>2009-03-27 15:05:07 +0000
commit5d93009e0be759a527e9b3b4c0b6a166d2bc635b (patch)
tree6f1a71a61fc9c10805d0042232f3e0cd07cf065a
parenta57841ce69d85d6012f3faea349b46be0d06592f (diff)
downloadlasso-5d93009e0be759a527e9b3b4c0b6a166d2bc635b.tar.gz
lasso-5d93009e0be759a527e9b3b4c0b6a166d2bc635b.tar.xz
lasso-5d93009e0be759a527e9b3b4c0b6a166d2bc635b.zip
SAML 2.0: add internal generic implementation
* lasso/saml-2.0/profile.c: * lasso/saml-2.0/profileprivate.h: the current effort is to simplify implementation code in saml-2.0 and much of the other frameworks. Those new methods: lasso_saml20_init_request lasso_saml20_profile_process_name_identifier_decryption lasso_saml20_profile_process_soap_request lasso_saml20_profile_process_soap_response lasso_saml20_profile_process_any_request lasso_saml20_profile_process_any_response lasso_saml20_profile_setup_request_signing lasso_saml20_profile_build_request_msg lasso_saml20_profile_build_response lasso_saml20_profile_init_response should help reduce code in login.c, logout.c, name_id_management.c and assertion_query.c. They should also permit to make all profiles at the same level of binding support (GET,REDIRECT,POST,ARTIFACT_GET,ARTIFACT_POST). Those function centralize error code handling, initialization of commong class (LassoSamlp2StatusResponse and LassoSamlp2RequestAbstract) and also the handling of NameID decryption.
-rw-r--r--lasso/saml-2.0/profile.c889
-rw-r--r--lasso/saml-2.0/profileprivate.h20
2 files changed, 881 insertions, 28 deletions
diff --git a/lasso/saml-2.0/profile.c b/lasso/saml-2.0/profile.c
index fea83bca..1a18e911 100644
--- a/lasso/saml-2.0/profile.c
+++ b/lasso/saml-2.0/profile.c
@@ -41,9 +41,63 @@
#include <lasso/xml/saml-2.0/samlp2_status_response.h>
#include <lasso/xml/saml-2.0/samlp2_response.h>
#include <lasso/xml/saml-2.0/saml2_assertion.h>
+#include "../utils.h"
static char* lasso_saml20_profile_build_artifact(LassoProvider *provider);
+/*
+ * Helper functions
+ */
+static int
+get_provider(LassoProfile *profile, LassoProvider **provider_out)
+{
+ int rc = 0;
+ LassoProvider *provider;
+ LassoServer *server;
+
+ lasso_bad_param(PROFILE, profile);
+
+ lasso_extract_node_or_fail(server, profile->server, SERVER,
+ LASSO_PROFILE_ERROR_MISSING_SERVER);
+ provider = lasso_server_get_provider(server, profile->remote_providerID);
+ if (! provider) {
+ return LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND;
+ }
+
+ *provider_out = provider;
+cleanup:
+ return 0;
+
+}
+
+static char *
+get_url(LassoProvider *provider, char *service, char *binding)
+{
+ char *meta;
+ char *result;
+
+ meta = g_strdup_printf("%s %s", service, binding);
+ result = lasso_provider_get_metadata_one(provider, meta);
+ lasso_release_string(meta);
+ return result;
+}
+
+static char *
+get_response_url(LassoProvider *provider, char *service, char *binding)
+{
+ char *meta;
+ char *result;
+
+ meta = g_strdup_printf("%s %s ResponseLocation", service, binding);
+ result = lasso_provider_get_metadata_one(provider, meta);
+ lasso_release_string(meta);
+ if (! result) {
+ result = get_url(provider, service, binding);
+ }
+ return result;
+}
+
+
/**
* lasso_saml20_profile_generate_artifact
* @profile: a #LassoProfile
@@ -95,41 +149,59 @@ lasso_saml20_profile_build_artifact(LassoProvider *provider)
return ret;
}
-void
-lasso_saml20_profile_set_response_status(LassoProfile *profile, const char *status_code_value)
+static int
+lasso_saml20_profile_set_response_status2(LassoProfile *profile,
+ const char *code1, const char *code2)
{
- LassoSamlp2Status *status;
+ LassoSamlp2StatusResponse *status_response = NULL;
+ LassoSamlp2Status *status = NULL;
+ LassoSamlp2StatusCode *status_code1 = NULL;
+ LassoSamlp2StatusCode *status_code2 = NULL;
+ int rc = 0;
+
+ lasso_bad_param(PROFILE, profile);
+ lasso_null_param(code1);
+ lasso_extract_node_or_fail(status_response, profile->response, SAMLP2_STATUS_RESPONSE,
+ LASSO_PROFILE_ERROR_MISSING_RESPONSE);
+
+ if (! LASSO_IS_SAMLP2_STATUS(status_response->Status)) {
+ lasso_assign_new_gobject(status_response->Status,
+ (LassoSamlp2Status*)lasso_samlp2_status_new());
+ }
+ status = status_response->Status;
+ if (! LASSO_IS_SAMLP2_STATUS_CODE(status->StatusCode)) {
+ lasso_assign_new_gobject(status->StatusCode,
+ (LassoSamlp2StatusCode*)lasso_samlp2_status_code_new());
+ }
+ status_code1 = status->StatusCode;
+ lasso_assign_string(status_code1->Value, code1);
+
+ if (code2) {
+ if (! LASSO_IS_SAMLP2_STATUS_CODE(status_code1->StatusCode)) {
+ lasso_assign_new_gobject(status_code1->StatusCode,
+ (LassoSamlp2StatusCode*)lasso_samlp2_status_code_new());
+ }
+ status_code2 = status_code1->StatusCode;
+ lasso_assign_string(status_code2->Value, code2);
+ }
- status = LASSO_SAMLP2_STATUS(lasso_samlp2_status_new());
- status->StatusCode = LASSO_SAMLP2_STATUS_CODE(lasso_samlp2_status_code_new());
- status->StatusCode->Value = g_strdup(status_code_value);
+cleanup:
+ return rc;
+}
+void
+lasso_saml20_profile_set_response_status(LassoProfile *profile, const char *status_code_value)
+{
if (strcmp(status_code_value, LASSO_SAML2_STATUS_CODE_SUCCESS) != 0 &&
strcmp(status_code_value, LASSO_SAML2_STATUS_CODE_VERSION_MISMATCH) != 0 &&
strcmp(status_code_value, LASSO_SAML2_STATUS_CODE_REQUESTER) != 0) {
- status->StatusCode->Value = g_strdup(LASSO_SAML2_STATUS_CODE_RESPONDER);
- status->StatusCode->StatusCode = LASSO_SAMLP2_STATUS_CODE(
- lasso_samlp2_status_code_new());
- status->StatusCode->StatusCode->Value = g_strdup(status_code_value);
- }
-
- if (LASSO_IS_SAMLP2_RESPONSE(profile->response) ||
- LASSO_IS_SAMLP2_ARTIFACT_RESPONSE(profile->response) ||
- LASSO_IS_SAMLP2_NAME_ID_MAPPING_RESPONSE(profile->response) ||
- LASSO_IS_SAMLP2_STATUS_RESPONSE(profile->response)) {
- LassoSamlp2StatusResponse *response;
- response = LASSO_SAMLP2_STATUS_RESPONSE(profile->response);
- if (response->Status)
- lasso_node_destroy(LASSO_NODE(response->Status));
- response->Status = status;
- return;
+ lasso_saml20_profile_set_response_status2(profile,
+ LASSO_SAML2_STATUS_CODE_RESPONDER, status_code_value);
+ } else {
+ lasso_saml20_profile_set_response_status2(profile, status_code_value, NULL);
}
-
- message(G_LOG_LEVEL_CRITICAL, "Failed to set status");
- g_assert_not_reached();
}
-
int
lasso_saml20_profile_init_artifact_resolve(LassoProfile *profile,
const char *msg, LassoHttpMethod method)
@@ -329,8 +401,8 @@ lasso_profile_is_saml_query(const gchar *query)
static void
-lasso_saml20_profile_set_session_from_dump_decrypt(
- G_GNUC_UNUSED gpointer key, LassoSaml2Assertion *assertion, G_GNUC_UNUSED gpointer data)
+lasso_saml20_profile_set_session_from_dump_decrypt(G_GNUC_UNUSED gpointer key,
+ LassoSaml2Assertion *assertion, G_GNUC_UNUSED gpointer data)
{
if (LASSO_IS_SAML2_ASSERTION(assertion) == FALSE) {
return;
@@ -355,3 +427,764 @@ lasso_saml20_profile_set_session_from_dump(LassoProfile *profile)
return 0;
}
+
+/**
+ * lasso_saml20_profile_process_name_identifier_decryption:
+ * @profile: the #LassoProfile object
+ * @name_id: the field containing the #LassoSaml2NameID object
+ * @encrypted_id: the field containing an encrypted #LassoSaml2NameID as a #LassoSaml2EncryptedElement
+ *
+ * Place content of the NameID in the profile nameIdentifier field, if no NameID is present but an
+ * EncryptedElement is, then decrypt it, store it in place of the name_id field and in the
+ * nameIdentifier field of the profile.
+ *
+ * Return value: 0 if successful,
+ * LASSO_PROFILE_ERROR_MISSING_NAME_IDENTIFIER if no NameID can be found,
+ * LASSO_PROFILE_ERROR_MISSING_ENCRYPTION_PRIVATE_KEY if an encryption element is present but no no
+ * decryption key.
+ */
+gint
+lasso_saml20_profile_process_name_identifier_decryption(LassoProfile *profile,
+ LassoSaml2NameID **name_id,
+ LassoSaml2EncryptedElement **encrypted_id)
+{
+ xmlSecKey *encryption_private_key = NULL;
+ int rc = 0;
+
+ lasso_bad_param(PROFILE, profile);
+ lasso_null_param(name_id);
+ lasso_null_param(encrypted_id);
+
+ if (*name_id == NULL && *encrypted_id != NULL) {
+ encryption_private_key = profile->server->private_data->encryption_private_key;
+ if (! LASSO_IS_SAML2_ENCRYPTED_ELEMENT(*encrypted_id)) {
+ return LASSO_PROFILE_ERROR_MISSING_NAME_IDENTIFIER;
+ }
+ if (encrypted_id != NULL && encryption_private_key == NULL) {
+ return LASSO_PROFILE_ERROR_MISSING_ENCRYPTION_PRIVATE_KEY;
+ }
+ rc = lasso_saml2_encrypted_element_decrypt(*encrypted_id, encryption_private_key,
+ &profile->nameIdentifier);
+ if (rc)
+ goto cleanup;
+ if (! LASSO_IS_SAML2_NAME_ID(profile->nameIdentifier)) {
+ rc = LASSO_PROFILE_ERROR_MISSING_NAME_IDENTIFIER;
+ goto cleanup;
+ }
+
+ // swap the node contents
+ lasso_assign_gobject(*name_id, LASSO_SAML2_NAME_ID(profile->nameIdentifier));
+ lasso_release_gobject(*encrypted_id);
+ } else {
+ lasso_assign_gobject(profile->nameIdentifier, (LassoNode*)*name_id);
+ }
+cleanup:
+ return rc;
+}
+
+int
+lasso_saml20_profile_process_any_request(LassoProfile *profile,
+ LassoNode *request_node,
+ char *request_msg)
+{
+ int rc = 0;
+ LassoSaml2NameID *name_id = NULL;
+ LassoProvider *remote_provider = NULL;
+ LassoServer *server = NULL;
+ LassoSamlp2RequestAbstract *request_abstract = NULL;
+ LassoMessageFormat format;
+ xmlDoc *doc = NULL;
+ xmlNode *content = NULL;
+
+ lasso_bad_param(PROFILE, profile);
+
+ /* reset signature_status */
+ profile->signature_status = 0;
+ format = lasso_node_init_from_message_with_format(request_node,
+ request_msg, LASSO_MESSAGE_FORMAT_UNKNOWN, &doc, &content);
+ if (format <= LASSO_MESSAGE_FORMAT_UNKNOWN) {
+ rc = LASSO_PROFILE_ERROR_INVALID_MSG;
+ goto cleanup;
+ }
+ switch (format) {
+ case LASSO_MESSAGE_FORMAT_BASE64:
+ profile->http_request_method = LASSO_HTTP_METHOD_POST;
+ break;
+ case LASSO_MESSAGE_FORMAT_SOAP:
+ profile->http_request_method = LASSO_HTTP_METHOD_SOAP;
+ break;
+ case LASSO_MESSAGE_FORMAT_QUERY:
+ profile->http_request_method = LASSO_HTTP_METHOD_REDIRECT;
+ break;
+ default:
+ rc = LASSO_PROFILE_ERROR_UNSUPPORTED_PROFILE;
+ goto cleanup;
+ }
+ lasso_assign_gobject(profile->request, request_node);
+ if (format == LASSO_MESSAGE_FORMAT_QUERY) {
+ lasso_assign_new_string(profile->msg_relayState,
+ lasso_get_relaystate_from_query(request_msg));
+ }
+
+ lasso_extract_node_or_fail(request_abstract, profile->request, SAMLP2_REQUEST_ABSTRACT,
+ LASSO_PROFILE_ERROR_INVALID_MSG);
+ lasso_extract_node_or_fail(server, profile->server, SERVER,
+ LASSO_PROFILE_ERROR_MISSING_SERVER);
+ lasso_extract_node_or_fail(name_id, request_abstract->Issuer, SAML2_NAME_ID,
+ LASSO_PROFILE_ERROR_MISSING_ISSUER);
+ lasso_assign_string(profile->remote_providerID, request_abstract->Issuer->content);
+
+ remote_provider = lasso_server_get_provider(server, profile->remote_providerID);
+ if (remote_provider == NULL) {
+ rc = LASSO_PROFILE_ERROR_UNKNOWN_PROVIDER;
+ goto cleanup;
+ }
+
+ /* verify the signature at the request level */
+ if (content && doc && format != LASSO_MESSAGE_FORMAT_QUERY) {
+ rc = profile->signature_status =
+ lasso_provider_verify_saml_signature(remote_provider, content, doc);
+ } else if (format == LASSO_MESSAGE_FORMAT_QUERY) {
+ rc = profile->signature_status =
+ lasso_provider_verify_query_signature(remote_provider, request_msg);
+ } else {
+ rc = LASSO_PROFILE_ERROR_CANNOT_VERIFY_SIGNATURE;
+ }
+
+cleanup:
+
+ lasso_release_doc(doc);
+ return rc;
+}
+
+
+int
+lasso_saml20_profile_process_soap_request(LassoProfile *profile,
+ char *request_msg)
+{
+ int rc = 0;
+ LassoSaml2NameID *issuer = NULL;
+ LassoProvider *remote_provider = NULL;
+ LassoServer *server = NULL;
+ LassoSamlp2RequestAbstract *request_abstract = NULL;
+
+ lasso_bad_param(PROFILE, profile);
+
+ profile->signature_status = 0;
+ profile->request = lasso_node_new_from_soap(request_msg);
+ profile->http_request_method = LASSO_HTTP_METHOD_SOAP;
+ lasso_extract_node_or_fail(request_abstract, profile->request, SAMLP2_REQUEST_ABSTRACT,
+ LASSO_PROFILE_ERROR_INVALID_MSG);
+ lasso_extract_node_or_fail(server, profile->server, SERVER,
+ LASSO_PROFILE_ERROR_MISSING_SERVER);
+ lasso_extract_node_or_fail(issuer, request_abstract->Issuer, SAML2_NAME_ID,
+ LASSO_PROFILE_ERROR_MISSING_ISSUER);
+ lasso_assign_string(profile->remote_providerID, issuer->content);
+
+ remote_provider = lasso_server_get_provider(server, profile->remote_providerID);
+ if (remote_provider == NULL) {
+ rc = LASSO_PROFILE_ERROR_UNKNOWN_PROVIDER;
+ goto cleanup;
+ }
+
+ rc = profile->signature_status = lasso_provider_verify_signature(
+ remote_provider, request_msg, "ID", LASSO_MESSAGE_FORMAT_SOAP);
+
+cleanup:
+
+ return rc;
+}
+
+int
+lasso_saml20_init_request(LassoProfile *profile,
+ char *remote_provider_id,
+ gboolean first_in_session,
+ LassoSamlp2RequestAbstract *request_abstract,
+ LassoHttpMethod http_method,
+ LassoMdProtocolType protocol_type)
+{
+ LassoIdentity *identity = NULL;
+ LassoSession *session = NULL;
+ LassoServer *server = NULL;
+ LassoProvider *remote_provider = NULL;
+ LassoSaml2NameID *name_id = NULL;
+ char *remote_provider_id_auto = NULL;
+ int rc = 0;
+
+ lasso_bad_param(PROFILE, profile);
+ lasso_bad_param(SAMLP2_REQUEST_ABSTRACT, request_abstract);
+ if (http_method < LASSO_HTTP_METHOD_ANY || http_method >= LASSO_HTTP_METHOD_LAST) {
+ message(G_LOG_LEVEL_CRITICAL, "Invalid LassoHttpMethod argument");
+ return LASSO_PARAM_ERROR_INVALID_VALUE;
+ }
+
+ /* verify identity and sessions */
+ lasso_extract_node_or_fail(identity, profile->identity, IDENTITY,
+ LASSO_PROFILE_ERROR_IDENTITY_NOT_FOUND);
+ lasso_extract_node_or_fail(session, profile->session, SESSION,
+ LASSO_PROFILE_ERROR_SESSION_NOT_FOUND);
+ lasso_extract_node_or_fail(server, profile->server, SERVER,
+ LASSO_PROFILE_ERROR_MISSING_SERVER);
+
+ /* set remote provider Id */
+ if (! remote_provider_id) {
+ if (first_in_session) {
+ remote_provider_id_auto = lasso_session_get_provider_index(session, 0);
+ } else {
+ remote_provider_id_auto = lasso_server_get_first_providerID(server);
+ }
+ }
+ if (! remote_provider_id && ! remote_provider_id_auto) {
+ rc = LASSO_PROFILE_ERROR_CANNOT_FIND_A_PROVIDER;
+ goto cleanup;
+ }
+ if (remote_provider_id) {
+ lasso_assign_string(profile->remote_providerID, remote_provider_id);
+ } else {
+ lasso_assign_new_string(profile->remote_providerID, remote_provider_id_auto);
+ }
+ rc = get_provider(profile, &remote_provider);
+ if (rc)
+ goto cleanup;
+ /* set the name identifier */
+ name_id = (LassoSaml2NameID*)lasso_profile_get_nameIdentifier(profile);
+ if (! LASSO_IS_SAML2_NAME_ID(name_id)) {
+ rc = LASSO_PROFILE_ERROR_FEDERATION_NOT_FOUND;
+ goto cleanup;
+ }
+ lasso_assign_gobject(profile->nameIdentifier, (LassoNode*)name_id);
+
+ /* verify that this provider supports the current http method */
+ if (http_method == LASSO_HTTP_METHOD_ANY) {
+ http_method = lasso_saml20_provider_get_first_http_method((LassoProvider*)server,
+ remote_provider, protocol_type);
+ }
+ if (http_method == LASSO_HTTP_METHOD_NONE) {
+ rc = LASSO_PROFILE_ERROR_UNSUPPORTED_PROFILE;
+ goto cleanup;
+ }
+ if (! lasso_saml20_provider_accept_http_method(
+ (LassoProvider*)server,
+ remote_provider,
+ protocol_type,
+ http_method,
+ TRUE)) {
+ rc = LASSO_PROFILE_ERROR_UNSUPPORTED_PROFILE;
+ }
+ profile->http_request_method = http_method;
+
+ /* initialize request fields */
+ lasso_assign_new_string(request_abstract->ID, lasso_build_unique_id(32));
+ lasso_assign_string(request_abstract->Version, "2.0");
+ lasso_assign_gobject(request_abstract->Issuer,
+ LASSO_SAML2_NAME_ID(lasso_saml2_name_id_new_with_string(
+ LASSO_PROVIDER(profile->server)->ProviderID)));
+ lasso_assign_new_string(request_abstract->IssueInstant, lasso_get_current_time());
+ lasso_assign_gobject(profile->request, LASSO_NODE(request_abstract));
+
+cleanup:
+ return rc;
+}
+
+static int
+lasso_saml20_profile_build_post_request_msg(LassoProfile *profile,
+ LassoProvider *provider, char *service)
+{
+ int rc = 0;
+ LassoSamlp2RequestAbstract *request_abstract;
+
+ lasso_bad_param(PROFILE, profile);
+ lasso_bad_param(PROVIDER, provider);
+ lasso_extract_node_or_fail(request_abstract, profile->request, SAMLP2_REQUEST_ABSTRACT,
+ LASSO_PROFILE_ERROR_BUILDING_MESSAGE_FAILED);
+
+ lasso_assign_new_string(profile->msg_url, get_response_url(provider, service, "HTTP-POST"));
+ if (! profile->msg_url) {
+ return critical_error(LASSO_PROFILE_ERROR_UNKNOWN_PROFILE_URL);
+ }
+ lasso_assign_new_string(profile->msg_body,
+ lasso_node_export_to_base64(LASSO_NODE(request_abstract)));
+ if (! profile->msg_body) {
+ return critical_error(LASSO_PROFILE_ERROR_BUILDING_MESSAGE_FAILED);
+ }
+cleanup:
+ return rc;
+}
+
+static int
+lasso_saml20_profile_build_soap_request_msg(LassoProfile *profile, LassoProvider *provider,
+ char *service)
+{
+ int rc = 0;
+ char *url = NULL;
+ LassoSamlp2RequestAbstract *request_abstract;
+
+ lasso_bad_param(PROFILE, profile);
+ lasso_bad_param(PROVIDER, provider);
+ lasso_extract_node_or_fail(request_abstract, profile->request, SAMLP2_REQUEST_ABSTRACT,
+ LASSO_PROFILE_ERROR_BUILDING_MESSAGE_FAILED);
+
+ url = get_url(provider, service, "SOAP");
+ if (! url) {
+ rc = critical_error(LASSO_PROFILE_ERROR_UNKNOWN_PROFILE_URL);
+ goto cleanup;
+ }
+ lasso_assign_new_string(profile->msg_body,
+ lasso_node_export_to_soap(LASSO_NODE(request_abstract)));
+ lasso_transfer_string(profile->msg_url, url);
+
+ if (! profile->msg_body) {
+ return LASSO_PROFILE_ERROR_BUILDING_MESSAGE_FAILED;
+ }
+
+cleanup:
+ lasso_release_string(url);
+ return rc;
+}
+
+static int
+lasso_saml20_profile_build_redirect_request_msg(LassoProfile *profile, LassoProvider *provider,
+ char *service, gboolean no_signature)
+{
+ int rc = 0;
+ char *url = NULL;
+ char *query = NULL;
+ LassoSamlp2RequestAbstract *request_abstract;
+
+ lasso_bad_param(PROFILE, profile);
+ lasso_bad_param(PROVIDER, provider);
+ lasso_extract_node_or_fail(request_abstract, profile->request, SAMLP2_REQUEST_ABSTRACT,
+ LASSO_PROFILE_ERROR_BUILDING_MESSAGE_FAILED);
+ if (no_signature)
+ request_abstract->sign_type = LASSO_SIGNATURE_TYPE_NONE;
+ url = get_url(provider, service, "HTTP-Redirect");
+ if (! url) {
+ rc = critical_error(LASSO_PROFILE_ERROR_UNKNOWN_PROFILE_URL);
+ goto cleanup;
+ }
+ query = lasso_node_export_to_query(LASSO_NODE(request_abstract),
+ profile->server->signature_method,
+ profile->server->private_key);
+ if (! query) {
+ rc = critical_error(LASSO_PROFILE_ERROR_BUILDING_QUERY_FAILED);
+ goto cleanup;
+ }
+ lasso_assign_new_string(profile->msg_url, lasso_concat_url_query(url, query));
+ lasso_release_string(profile->msg_body);
+
+cleanup:
+ lasso_release_string(url);
+ return rc;
+
+}
+
+int
+lasso_saml20_profile_setup_request_signing(LassoProfile *profile)
+{
+ LassoSamlp2RequestAbstract *request_abstract = NULL;
+ LassoServer *server = NULL;
+ int rc = 0;
+
+ lasso_extract_node_or_fail(request_abstract, profile->request, SAMLP2_REQUEST_ABSTRACT,
+ LASSO_PROFILE_ERROR_INVALID_MSG);
+ lasso_extract_node_or_fail(server, profile->server, SERVER,
+ LASSO_PROFILE_ERROR_MISSING_SERVER);
+
+ request_abstract->sign_method = server->signature_method;
+ request_abstract->sign_type = server->certificate ? LASSO_SIGNATURE_TYPE_WITHX509 :
+ LASSO_SIGNATURE_TYPE_SIMPLE;
+ lasso_assign_string(request_abstract->private_key_file, server->private_key);
+ lasso_assign_string(request_abstract->certificate_file, server->certificate);
+
+cleanup:
+ return rc;
+}
+
+int
+lasso_saml20_profile_build_request_msg(LassoProfile *profile, char *service, gboolean no_signature)
+{
+ LassoProvider *provider;
+ int rc = 0;
+
+ lasso_bad_param(PROFILE, profile);
+
+ lasso_profile_clean_msg_info(profile);
+ rc = get_provider(profile, &provider);
+ if (rc)
+ goto cleanup;
+
+ rc = lasso_saml20_profile_setup_request_signing(profile);
+ if (rc)
+ goto cleanup;
+
+ switch (profile->http_request_method) {
+ case LASSO_HTTP_METHOD_SOAP:
+ rc = lasso_saml20_profile_build_soap_request_msg(profile, provider,
+ service);
+ break;
+ case LASSO_HTTP_METHOD_POST:
+ rc = lasso_saml20_profile_build_post_request_msg(profile, provider,
+ service);
+ break;
+ case LASSO_HTTP_METHOD_REDIRECT:
+ rc = lasso_saml20_profile_build_redirect_request_msg(profile, provider,
+ service, no_signature);
+ break;
+ case LASSO_HTTP_METHOD_ARTIFACT_GET:
+ case LASSO_HTTP_METHOD_ARTIFACT_POST:
+ rc = LASSO_PROFILE_ERROR_UNSUPPORTED_PROFILE;
+ break;
+ default:
+ rc = LASSO_PROFILE_ERROR_INVALID_HTTP_METHOD;
+ break;
+ }
+
+cleanup:
+ return rc;
+
+}
+
+int
+lasso_saml20_profile_init_response(LassoProfile *profile, const char *status_code)
+{
+ LassoSamlp2StatusResponse *status_response = NULL;
+ LassoSamlp2RequestAbstract *request_abstract = NULL;
+ LassoServer *server = NULL;
+ int rc = 0;
+
+ lasso_bad_param(PROFILE, profile);
+ lasso_extract_node_or_fail(status_response, profile->response, SAMLP2_STATUS_RESPONSE,
+ LASSO_PROFILE_ERROR_MISSING_RESPONSE);
+ lasso_extract_node_or_fail(server, profile->server, SERVER,
+ LASSO_PROFILE_ERROR_MISSING_SERVER);
+ lasso_extract_node_or_fail(request_abstract, profile->request, SAMLP2_REQUEST_ABSTRACT,
+ LASSO_PROFILE_ERROR_MISSING_REQUEST);
+
+ lasso_assign_new_string(status_response->ID, lasso_build_unique_id(32));
+ lasso_assign_string(status_response->Version, "2.0");
+ lasso_assign_new_gobject(status_response->Issuer,
+ LASSO_SAML2_NAME_ID(lasso_saml2_name_id_new_with_string(
+ server->parent.ProviderID)));
+ lasso_assign_new_string(status_response->IssueInstant, lasso_get_current_time());
+ lasso_assign_string(status_response->InResponseTo, request_abstract->ID);
+ if (status_code)
+ lasso_saml20_profile_set_response_status(profile,
+ status_code);
+
+cleanup:
+ return rc;
+}
+
+int
+lasso_saml20_profile_validate_request(LassoProfile *profile, gboolean needs_identity,
+ LassoSamlp2StatusResponse *status_response, LassoProvider **provider_out)
+{
+ int rc = 0;
+ LassoSamlp2RequestAbstract *request_abstract = NULL;
+ LassoSaml2NameID *issuer = NULL;
+ LassoIdentity *identity = NULL;
+ LassoProvider *provider = NULL;
+
+ lasso_bad_param(PROFILE, profile);
+ lasso_bad_param(SAMLP2_STATUS_RESPONSE, status_response);
+ /* verify request presence */
+ lasso_extract_node_or_fail(request_abstract, profile->request, SAMLP2_REQUEST_ABSTRACT,
+ LASSO_PROFILE_ERROR_MISSING_REQUEST);
+ /* look for identity object */
+ if (needs_identity) {
+ lasso_extract_node_or_fail(identity, profile->identity, IDENTITY,
+ LASSO_PROFILE_ERROR_IDENTITY_NOT_FOUND);
+ }
+
+ /* extract provider */
+ lasso_extract_node_or_fail(issuer, request_abstract->Issuer, SAML2_NAME_ID,
+ LASSO_PROFILE_ERROR_MISSING_ISSUER);
+ lasso_assign_string(profile->remote_providerID, issuer->content);
+ rc = get_provider(profile, &provider);
+ if (rc)
+ goto cleanup;
+
+ /* init the response */
+ lasso_assign_gobject(profile->response, &status_response->parent);
+ lasso_saml20_profile_init_response(profile, LASSO_SAML2_STATUS_CODE_SUCCESS);
+
+ if (profile->signature_status) {
+ message(G_LOG_LEVEL_WARNING, "Request signature is invalid");
+ lasso_saml20_profile_set_response_status2(profile,
+ LASSO_SAML2_STATUS_CODE_REQUESTER,
+ LASSO_LIB_STATUS_CODE_INVALID_SIGNATURE);
+ return profile->signature_status;
+ }
+
+cleanup:
+ if (provider && provider_out)
+ *provider_out = provider;
+ return rc;
+
+}
+
+static int
+lasso_saml20_profile_setup_response_signing(LassoProfile *profile)
+{
+ LassoSamlp2StatusResponse *response_abstract = NULL;
+ LassoServer *server = NULL;
+ int rc = 0;
+
+ lasso_extract_node_or_fail(response_abstract, profile->response, SAMLP2_STATUS_RESPONSE,
+ LASSO_PROFILE_ERROR_INVALID_MSG);
+ lasso_extract_node_or_fail(server, profile->server, SERVER, LASSO_PROFILE_ERROR_MISSING_SERVER);
+
+ response_abstract->sign_method = server->signature_method;
+ response_abstract->sign_type = server->certificate ? LASSO_SIGNATURE_TYPE_WITHX509 :
+ LASSO_SIGNATURE_TYPE_SIMPLE;
+ lasso_assign_string(response_abstract->private_key_file, server->private_key);
+ lasso_assign_string(response_abstract->certificate_file, server->certificate);
+
+cleanup:
+
+ return rc;
+
+}
+
+static int
+lasso_saml20_profile_build_post_response(LassoProfile *profile, LassoProvider *provider, char *service)
+{
+ lasso_bad_param(PROFILE, profile);
+ lasso_bad_param(PROVIDER, provider);
+
+ lasso_assign_new_string(profile->msg_url, get_response_url(provider, service, "HTTP-POST"));
+ if (! profile->msg_url) {
+ return critical_error(LASSO_PROFILE_ERROR_UNKNOWN_PROFILE_URL);
+ }
+ lasso_assign_new_string(profile->msg_body, lasso_node_export_to_base64(profile->request));
+ if (! profile->msg_body) {
+ return critical_error(LASSO_PROFILE_ERROR_BUILDING_MESSAGE_FAILED);
+ }
+ return 0;
+}
+
+static int
+lasso_saml20_profile_build_redirect_response(LassoProfile *profile, LassoProvider *provider, char
+ *service, gboolean no_signature)
+{
+ LassoSamlp2StatusResponse *status_response = NULL;
+ char *url = NULL, *query = NULL;
+ int rc = 0;
+
+ lasso_bad_param(PROFILE, profile);
+ lasso_null_param(service);
+
+ lasso_extract_node_or_fail(status_response, profile->response, SAMLP2_STATUS_RESPONSE,
+ LASSO_PROFILE_ERROR_MISSING_RESPONSE);
+ if (no_signature) // for authn response
+ status_response->sign_type = LASSO_SIGNATURE_TYPE_NONE;
+ // get url
+ url = get_response_url(provider, service, "HTTP-Redirect");
+ if (! url) {
+ rc = critical_error(LASSO_PROFILE_ERROR_UNKNOWN_PROFILE_URL);
+ goto cleanup;
+ }
+ query = lasso_node_export_to_query(profile->response,
+ profile->server->signature_method,
+ profile->server->private_key);
+ if (! query) {
+ rc = critical_error(LASSO_PROFILE_ERROR_BUILDING_QUERY_FAILED);
+ goto cleanup;
+ }
+ lasso_assign_new_string(profile->msg_url, lasso_concat_url_query(url, query));
+ lasso_release_string(profile->msg_body);
+
+cleanup:
+ lasso_release_string(url);
+ return rc;
+}
+
+static int
+lasso_saml20_profile_build_soap_response(LassoProfile *profile)
+{
+ lasso_bad_param(PROFILE, profile);
+
+ lasso_release_string(profile->msg_url);
+ lasso_assign_new_string(profile->msg_body, lasso_node_export_to_soap(profile->response));
+
+ if (! profile->msg_body) {
+ return LASSO_PROFILE_ERROR_BUILDING_RESPONSE_FAILED;
+ }
+
+ return 0;
+}
+
+int
+lasso_saml20_profile_build_response(LassoProfile *profile, char *service, gboolean no_signature,
+ LassoHttpMethod method)
+{
+ LassoProvider *provider;
+ int rc = 0;
+
+ lasso_bad_param(PROFILE, profile);
+
+ lasso_profile_clean_msg_info(profile);
+ rc = get_provider(profile, &provider);
+ if (rc)
+ goto cleanup;
+
+ rc = lasso_saml20_profile_setup_response_signing(profile);
+ if (rc) goto cleanup;
+ switch (method) {
+ case LASSO_HTTP_METHOD_POST:
+ rc = lasso_saml20_profile_build_post_response(profile, provider, service);
+ break;
+ case LASSO_HTTP_METHOD_REDIRECT:
+ rc = lasso_saml20_profile_build_redirect_response(profile, provider,
+ service, no_signature);
+ break;
+ case LASSO_HTTP_METHOD_SOAP:
+ rc = lasso_saml20_profile_build_soap_response(profile);
+ break;
+ default:
+ rc= LASSO_PROFILE_ERROR_UNSUPPORTED_PROFILE;
+ break;
+ }
+
+cleanup:
+ return rc;
+}
+
+/**
+ * lasso_saml20_profile_process_any_response:
+ * @profile: the SAML 2.0 #LassoProfile object
+ * @status_response: the prototype for the response object
+ * @response_msg: the content of the response message
+ *
+ * Generic method for SAML 2.0 protocol message handling.
+ *
+ * Return value: 0 if successful, an error code otherwise.
+ */
+int
+lasso_saml20_profile_process_any_response(LassoProfile *profile,
+ LassoSamlp2StatusResponse *status_response,
+ char *response_msg)
+{
+ int rc = 0;
+
+ LassoSaml2NameID *name_id = NULL;
+ LassoProvider *remote_provider = NULL;
+ LassoServer *server = NULL;
+ LassoSamlp2StatusResponse *response_abstract = NULL;
+ LassoSamlp2Status *status = NULL;
+ LassoSamlp2StatusCode *status_code1 = NULL;
+ LassoSamlp2StatusCode *status_code2 = NULL;
+ LassoMessageFormat format;
+
+ xmlDoc *doc = NULL;
+ xmlNode *content = NULL;
+
+ lasso_bad_param(PROFILE, profile);
+ lasso_bad_param(SAMLP2_STATUS_RESPONSE, status_response);
+
+ /* reset signature_status */
+ profile->signature_status = 0;
+ format = lasso_node_init_from_message_with_format((LassoNode*)status_response,
+ response_msg, LASSO_MESSAGE_FORMAT_UNKNOWN, &doc, &content);
+ if (format <= LASSO_MESSAGE_FORMAT_UNKNOWN) {
+ rc = LASSO_PROFILE_ERROR_INVALID_MSG;
+ goto cleanup;
+ }
+ lasso_assign_gobject(profile->response, (LassoNode*)status_response);
+ lasso_extract_node_or_fail(response_abstract, profile->response, SAMLP2_STATUS_RESPONSE,
+ LASSO_PROFILE_ERROR_INVALID_MSG);
+ lasso_extract_node_or_fail(server, profile->server, SERVER,
+ LASSO_PROFILE_ERROR_MISSING_SERVER);
+ lasso_extract_node_or_fail(name_id, response_abstract->Issuer, SAML2_NAME_ID,
+ LASSO_PROFILE_ERROR_MISSING_ISSUER);
+ lasso_assign_string(profile->remote_providerID, response_abstract->Issuer->content);
+
+ remote_provider = lasso_server_get_provider(server, profile->remote_providerID);
+ if (remote_provider == NULL) {
+ rc = LASSO_PROFILE_ERROR_UNKNOWN_PROVIDER;
+ goto cleanup;
+ }
+
+ /* verify the signature at the request level */
+ if (content && doc && format != LASSO_MESSAGE_FORMAT_QUERY) {
+ rc = profile->signature_status =
+ lasso_provider_verify_saml_signature(remote_provider, content, doc);
+ } else if (format == LASSO_MESSAGE_FORMAT_QUERY) {
+ rc = profile->signature_status =
+ lasso_provider_verify_query_signature(remote_provider, response_msg);
+ } else {
+ rc = LASSO_PROFILE_ERROR_CANNOT_VERIFY_SIGNATURE;
+ }
+
+ /* verify status code */
+ lasso_extract_node_or_fail(status, status_response->Status, SAMLP2_STATUS,
+ LASSO_PROFILE_ERROR_MISSING_STATUS_CODE);
+ lasso_extract_node_or_fail(status_code1, status->StatusCode, SAMLP2_STATUS_CODE,
+ LASSO_PROFILE_ERROR_MISSING_STATUS_CODE);
+ if (! status_code1->Value) {
+ rc = LASSO_PROFILE_ERROR_MISSING_STATUS_CODE;
+ goto cleanup;
+ }
+ if (status_code1->StatusCode && status_code1->StatusCode->Value)
+ {
+ status_code2 = status_code1->StatusCode;
+ }
+
+ if (strcmp(status_code1->Value, LASSO_SAML2_STATUS_CODE_SUCCESS) != 0) {
+ message(G_LOG_LEVEL_CRITICAL, "Status Code is not Success on a SAML 2.0 response:"
+ "1st leve «%s» 2nd leve «%s»", status_code1->Value, status_code2 ?
+ status_code2->Value : "");
+ rc = LASSO_PROFILE_ERROR_STATUS_NOT_SUCCESS;
+ goto cleanup;
+ }
+
+cleanup:
+ if (rc == LASSO_PROFILE_ERROR_MISSING_STATUS_CODE) {
+ message(G_LOG_LEVEL_CRITICAL,
+ "Status Code is missing in a SAML 2.0 protocol response");
+ }
+ return rc;
+}
+
+/**
+ * lasso_saml20_profile_process_soap_response:
+ *
+ * Generic method for processing SAML 2.0 protocol message as a SOAP response.
+ *
+ * Return value: 0 if successful; an error code otherwise.
+ */
+int
+lasso_saml20_profile_process_soap_response(LassoProfile *profile,
+ char *response_msg)
+{
+ int rc = 0;
+ LassoSaml2NameID *issuer = NULL;
+ LassoProvider *remote_provider = NULL;
+ LassoServer *server = NULL;
+ LassoSamlp2StatusResponse *response_abstract = NULL;
+
+ lasso_bad_param(PROFILE, profile);
+ lasso_null_param(response_msg);
+
+ profile->signature_status = 0;
+ profile->response = lasso_node_new_from_soap(response_msg);
+ lasso_extract_node_or_fail(response_abstract, profile->response, SAMLP2_STATUS_RESPONSE,
+ LASSO_PROFILE_ERROR_INVALID_MSG);
+ lasso_extract_node_or_fail(server, profile->server, SERVER,
+ LASSO_PROFILE_ERROR_MISSING_SERVER);
+ lasso_extract_node_or_fail(issuer, response_abstract->Issuer, SAML2_NAME_ID,
+ LASSO_PROFILE_ERROR_MISSING_ISSUER);
+ lasso_assign_string(profile->remote_providerID, issuer->content);
+
+ remote_provider = lasso_server_get_provider(server, profile->remote_providerID);
+ if (remote_provider == NULL) {
+ rc = LASSO_PROFILE_ERROR_UNKNOWN_PROVIDER;
+ goto cleanup;
+ }
+
+ rc = profile->signature_status = lasso_provider_verify_signature(
+ remote_provider, response_msg, "ID", LASSO_MESSAGE_FORMAT_SOAP);
+
+cleanup:
+ return rc;
+}
diff --git a/lasso/saml-2.0/profileprivate.h b/lasso/saml-2.0/profileprivate.h
index 7fb8c591..988ea49b 100644
--- a/lasso/saml-2.0/profileprivate.h
+++ b/lasso/saml-2.0/profileprivate.h
@@ -30,7 +30,15 @@ extern "C" {
#endif /* __cplusplus */
#include <lasso/id-ff/profile.h>
+#include <lasso/xml/saml-2.0/saml2_name_id.h>
+#include <lasso/xml/saml-2.0/saml2_encrypted_element.h>
+#include "../xml/saml-2.0/samlp2_status_response.h"
+#include "../xml/saml-2.0/samlp2_request_abstract.h"
+#include "../id-ff/provider.h"
+int lasso_saml20_init_request(LassoProfile *profile, char *remote_provider_id,
+ gboolean first_in_session, LassoSamlp2RequestAbstract *request_abstract,
+ LassoHttpMethod http_method, LassoMdProtocolType protocol_type);
char* lasso_saml20_profile_generate_artifact(LassoProfile *profile, int part);
void lasso_saml20_profile_set_response_status(LassoProfile *profile, const char *status_code_value);
int lasso_saml20_profile_init_artifact_resolve(LassoProfile *profile,
@@ -39,6 +47,18 @@ int lasso_saml20_profile_process_artifact_resolve(LassoProfile *profile, const c
int lasso_saml20_profile_build_artifact_response(LassoProfile *profile);
int lasso_saml20_profile_process_artifact_response(LassoProfile *profile, const char *msg);
gint lasso_saml20_profile_set_session_from_dump(LassoProfile *profile);
+gint lasso_saml20_profile_process_name_identifier_decryption(LassoProfile *profile,
+ LassoSaml2NameID **name_id, LassoSaml2EncryptedElement **encrypted_id);
+int lasso_saml20_profile_process_soap_request(LassoProfile *profile, char *request_msg);
+int lasso_saml20_profile_process_soap_response(LassoProfile *profile, char *response_msg);
+int lasso_saml20_profile_process_any_request(LassoProfile *profile, LassoNode *request_node,
+ char *request_msg);
+int lasso_saml20_profile_process_any_response(LassoProfile *profile, LassoSamlp2StatusResponse *response_node, char *response_msg);
+int lasso_saml20_profile_setup_request_signing(LassoProfile *profile);
+int lasso_saml20_profile_build_request_msg(LassoProfile *profile, char *service, gboolean no_signature);
+int lasso_saml20_profile_build_response(LassoProfile *profile, char *service, gboolean no_signature, LassoHttpMethod method);
+int lasso_saml20_profile_init_response(LassoProfile *profile, const char *status_code);
+int lasso_saml20_profile_validate_request(LassoProfile *profile, gboolean needs_identity, LassoSamlp2StatusResponse *status_response, LassoProvider **provider_out);
#ifdef __cplusplus
}