diff options
Diffstat (limited to 'lasso')
-rw-r--r-- | lasso/errors.c | 10 | ||||
-rw-r--r-- | lasso/errors.h | 17 | ||||
-rw-r--r-- | lasso/id-ff/login.c | 2 | ||||
-rw-r--r-- | lasso/id-ff/logout.c | 9 | ||||
-rw-r--r-- | lasso/id-ff/profile.c | 83 | ||||
-rw-r--r-- | lasso/id-ff/provider.c | 13 | ||||
-rw-r--r-- | lasso/id-ff/provider.h | 2 | ||||
-rw-r--r-- | lasso/saml-2.0/assertion_query.c | 66 | ||||
-rw-r--r-- | lasso/saml-2.0/ecp.c | 1 | ||||
-rw-r--r-- | lasso/saml-2.0/login.c | 650 | ||||
-rw-r--r-- | lasso/saml-2.0/loginprivate.h | 2 | ||||
-rw-r--r-- | lasso/saml-2.0/logout.c | 334 | ||||
-rw-r--r-- | lasso/saml-2.0/logoutprivate.h | 2 | ||||
-rw-r--r-- | lasso/saml-2.0/name_id_management.c | 38 | ||||
-rw-r--r-- | lasso/saml-2.0/profile.c | 702 | ||||
-rw-r--r-- | lasso/saml-2.0/profileprivate.h | 25 | ||||
-rw-r--r-- | lasso/saml-2.0/provider.c | 2 | ||||
-rw-r--r-- | lasso/saml-2.0/saml2_helper.c | 4 | ||||
-rw-r--r-- | lasso/saml-2.0/saml2_helper.h | 11 | ||||
-rw-r--r-- | lasso/xml/saml-2.0/samlp2_request_abstract.c | 4 | ||||
-rw-r--r-- | lasso/xml/saml-2.0/samlp2_status_response.c | 4 |
21 files changed, 954 insertions, 1027 deletions
diff --git a/lasso/errors.c b/lasso/errors.c index 987cd469..8b324c08 100644 --- a/lasso/errors.c +++ b/lasso/errors.c @@ -117,6 +117,8 @@ lasso_strerror(int error_code) return "SAML signature must contain only one reference"; case LASSO_PROFILE_ERROR_MISSING_SERVICE_TYPE: return "Missing service type"; + case LASSO_PROFILE_ERROR_UNSUPPORTED_BINDING: + return "The responder reported that he does not support this binding"; case LASSO_PROFILE_ERROR_CANNOT_FIND_A_PROVIDER: return "Profile was called without a specific provider and we cannot find one."; case LASSO_DS_ERROR_INVALID_REFERENCE_FOR_SAML: @@ -153,6 +155,8 @@ lasso_strerror(int error_code) return "Invalid signature."; case LASSO_WSF_PROFILE_ERROR_SERVER_INTERACTION_REQUIRED_FOR_DATA: return "redirect requests."; + case LASSO_IDWSF2_DST_ERROR_PARTIAL_FAILURE: + return "Server responded with a partial failure status code."; case LASSO_DS_ERROR_DECRYPTION_FAILED: return "Decryption of an encrypted node failed"; case LASSO_IDWSF2_DISCOVERY_ERROR_NO_RESULTS: @@ -181,6 +185,8 @@ lasso_strerror(int error_code) return "Failed to create session from dump"; case LASSO_PROFILE_ERROR_BUILDING_QUERY_FAILED: return "Error building request QUERY url"; + case LASSO_DS_ERROR_ENCRYPTION_FAILED: + return "Creation of an encrypted node failed"; case LASSO_DST_ERROR_MISSING_SERVICE_DATA: return "Missing service data"; case LASSO_DS_ERROR_CERTIFICATE_LOAD_FAILED: @@ -205,6 +211,8 @@ lasso_strerror(int error_code) return "A response contained an unknown status code."; case LASSO_PROFILE_ERROR_INVALID_QUERY: return "Invalid URL query"; + case LASSO_IDWSF2_DST_ERROR_UNKNOWN_STATUS_CODE: + return "Server response with an unknown status code."; case LASSO_DS_ERROR_SIGNATURE_TMPL_CREATION_FAILED: return "LASSO_DS_ERROR_SIGNATURE_TMPL_CREATION_FAILED"; case LASSO_PROFILE_ERROR_MISSING_RESPONSE: @@ -243,6 +251,8 @@ lasso_strerror(int error_code) return "The error return location should be either NULL or contains a NULL error."; case LASSO_SOAP_ERROR_MISSING_BODY: return "Missing SOAP body"; + case LASSO_IDWSF2_DST_ERROR_ITEM_NOT_FOUND: + return "The item_id was not found in the current query request."; case LASSO_XML_ERROR_INVALID_FILE: return "Invalid XML file"; case LASSO_WSF_PROFILE_ERROR_MISSING_ENDPOINT: diff --git a/lasso/errors.h b/lasso/errors.h index ceadd2bd..059667a3 100644 --- a/lasso/errors.h +++ b/lasso/errors.h @@ -198,7 +198,14 @@ * * Decryption of an encrypted node failed */ -#define LASSO_DS_ERROR_DECRYPTION_FAILED -118 +#define LASSO_DS_ERROR_DECRYPTION_FAILED 118 +/** + * LASSO_DS_ERROR_ENCRYPTION_FAILED: + * + * Creation of an encrypted node failed + */ +#define LASSO_DS_ERROR_ENCRYPTION_FAILED -119 + /* Server */ /** @@ -506,7 +513,6 @@ * Received response does not refer to the request sent */ #define LASSO_PROFILE_ERROR_RESPONSE_DOES_NOT_MATCH_REQUEST -442 - /** * LASSO_PROFILE_ERROR_INVALID_REQUEST: * @@ -520,6 +526,13 @@ * Received request is not of the expected type. */ #define LASSO_PROFILE_ERROR_INVALID_RESPONSE 444 +/** + * LASSO_PROFILE_ERROR_UNSUPPPORTED_BINDING + * + * The responder reported that he does not support this binding + */ +#define LASSO_PROFILE_ERROR_UNSUPPORTED_BINDING 445 + /* functions/methods parameters checking */ /** diff --git a/lasso/id-ff/login.c b/lasso/id-ff/login.c index 7d2c0ef8..52d034e4 100644 --- a/lasso/id-ff/login.c +++ b/lasso/id-ff/login.c @@ -929,7 +929,7 @@ lasso_login_build_authn_request_msg(LassoLogin *login) } IF_SAML2(profile) { - return lasso_saml20_login_build_authn_request_msg(login, remote_provider); + return lasso_saml20_login_build_authn_request_msg(login); } protocolProfile = LASSO_LIB_AUTHN_REQUEST(profile->request)->ProtocolProfile; diff --git a/lasso/id-ff/logout.c b/lasso/id-ff/logout.c index 507a70d3..0d934208 100644 --- a/lasso/id-ff/logout.c +++ b/lasso/id-ff/logout.c @@ -88,6 +88,10 @@ lasso_logout_build_request_msg(LassoLogout *logout) profile = LASSO_PROFILE(logout); lasso_profile_clean_msg_info(profile); + IF_SAML2(profile) { + return lasso_saml20_logout_build_request_msg(logout); + } + if (profile->remote_providerID == NULL) { /* this means lasso_logout_init_request was not called before */ return critical_error(LASSO_PROFILE_ERROR_MISSING_REMOTE_PROVIDERID); @@ -99,10 +103,6 @@ lasso_logout_build_request_msg(LassoLogout *logout) return critical_error(LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND); } - IF_SAML2(profile) { - return lasso_saml20_logout_build_request_msg(logout, remote_provider); - } - /* build the logout request message */ if (logout->initial_http_request_method == LASSO_HTTP_METHOD_SOAP) { /* build the logout request message */ @@ -1100,6 +1100,7 @@ finalize(GObject *object) static void instance_init(LassoLogout *logout) { + logout->initial_http_request_method = LASSO_HTTP_METHOD_NONE; logout->private_data = g_new0(LassoLogoutPrivate, 1); logout->private_data->dispose_has_run = FALSE; } diff --git a/lasso/id-ff/profile.c b/lasso/id-ff/profile.c index 3998ff1c..f378027d 100644 --- a/lasso/id-ff/profile.c +++ b/lasso/id-ff/profile.c @@ -43,6 +43,8 @@ #include "./sessionprivate.h" #include "../saml-2.0/profileprivate.h" +#include "../xml/saml-2.0/saml2_name_id.h" +#include "../xml/saml-2.0/saml2_assertion.h" #include "../utils.h" #include "../debug.h" @@ -50,6 +52,38 @@ /* public functions */ /*****************************************************************************/ +static LassoNode* +_lasso_saml_assertion_get_name_id(LassoSamlAssertion *assertion) +{ + LassoSamlAuthenticationStatement *authn_statement; + LassoSamlSubject *subject; + + goto_cleanup_if_fail(LASSO_IS_SAML_ASSERTION(assertion)); + authn_statement = assertion->AuthenticationStatement; + goto_cleanup_if_fail(LASSO_IS_SAML_AUTHENTICATION_STATEMENT(authn_statement)); + subject = authn_statement->parent.Subject; + goto_cleanup_if_fail(LASSO_IS_SAML_SUBJECT(subject)); + if (LASSO_IS_SAML_NAME_IDENTIFIER(subject->NameIdentifier)) + return (LassoNode*)subject->NameIdentifier; +cleanup: + return NULL; +} + +static LassoNode* +_lasso_saml2_assertion_get_name_id(LassoSaml2Assertion *assertion) +{ + LassoSaml2Subject *subject; + + goto_cleanup_if_fail(LASSO_SAML2_ASSERTION(assertion)); + subject = assertion->Subject; + goto_cleanup_if_fail(LASSO_SAML2_SUBJECT(subject)); + if (LASSO_IS_SAML2_NAME_ID(subject->NameID)) + return (LassoNode*)subject->NameID; + +cleanup: + return NULL; +} + /** * lasso_profile_get_nameIdentifier: * @profile: a #LassoProfile @@ -69,29 +103,48 @@ lasso_profile_get_nameIdentifier(LassoProfile *profile) char *name_id_sp_name_qualifier; g_return_val_if_fail(LASSO_IS_PROFILE(profile), NULL); - + g_return_val_if_fail(LASSO_IS_SERVER(profile->server), NULL); g_return_val_if_fail(LASSO_IS_IDENTITY(profile->identity), NULL); - g_return_val_if_fail(profile->remote_providerID != NULL, NULL); - remote_provider = lasso_server_get_provider(profile->server, profile->remote_providerID); - if (remote_provider == NULL) + if (profile->remote_providerID == NULL) return NULL; - name_id_sp_name_qualifier = lasso_provider_get_sp_name_qualifier(remote_provider); - if (name_id_sp_name_qualifier == NULL) - return NULL; + if (LASSO_IS_IDENTITY(profile->identity)) { + remote_provider = lasso_server_get_provider(profile->server, profile->remote_providerID); + if (remote_provider == NULL) + goto use_session; - federation = g_hash_table_lookup( - profile->identity->federations, - name_id_sp_name_qualifier); - if (federation == NULL) - return NULL; + name_id_sp_name_qualifier = lasso_provider_get_sp_name_qualifier(remote_provider); + if (name_id_sp_name_qualifier == NULL) + goto use_session; - if (federation->remote_nameIdentifier) - return federation->remote_nameIdentifier; + federation = g_hash_table_lookup( + profile->identity->federations, + name_id_sp_name_qualifier); + if (federation == NULL) + goto use_session; - return federation->local_nameIdentifier; + if (federation->remote_nameIdentifier) + return federation->remote_nameIdentifier; + return federation->local_nameIdentifier; + } +use_session: + /* For transient federations, so we must look at assertions no federation object exists */ + if (LASSO_IS_SESSION(profile->session)) { + LassoNode *assertion, *name_id; + + assertion = lasso_session_get_assertion(profile->session, + profile->remote_providerID); + + name_id = _lasso_saml_assertion_get_name_id((LassoSamlAssertion*)assertion); + if (name_id) + return name_id; + name_id = _lasso_saml2_assertion_get_name_id((LassoSaml2Assertion*)assertion); + if (name_id) + return name_id; + } + return NULL; } /** diff --git a/lasso/id-ff/provider.c b/lasso/id-ff/provider.c index 0fd8de69..4cc4f248 100644 --- a/lasso/id-ff/provider.c +++ b/lasso/id-ff/provider.c @@ -1271,6 +1271,19 @@ lasso_provider_set_encryption_mode(LassoProvider *provider, LassoEncryptionMode } /** + * lasso_provider_get_encryption_mode: + * @provider: a #LassoProvider object + * + * Return the current encryption mode. + */ +LassoEncryptionMode +lasso_provider_get_encryption_mode(LassoProvider *provider) { + if (! LASSO_IS_PROVIDER(provider) || ! provider->private_data) + return LASSO_ENCRYPTION_MODE_NONE; + return provider->private_data->encryption_mode; +} + +/** * lasso_provider_set_encryption_sym_key_type: * @provider: provider to set encryption for * @encryption_sym_key_type: enum type for generated symetric key diff --git a/lasso/id-ff/provider.h b/lasso/id-ff/provider.h index c2a74107..a787a525 100644 --- a/lasso/id-ff/provider.h +++ b/lasso/id-ff/provider.h @@ -203,6 +203,8 @@ LASSO_EXPORT LassoProtocolConformance lasso_provider_get_protocol_conformance( LASSO_EXPORT void lasso_provider_set_encryption_mode(LassoProvider *provider, LassoEncryptionMode encryption_mode); +LASSO_EXPORT LassoEncryptionMode lasso_provider_get_encryption_mode(LassoProvider *provider); + LASSO_EXPORT void lasso_provider_set_encryption_sym_key_type(LassoProvider *provider, LassoEncryptionSymKeyType encryption_sym_key_type); diff --git a/lasso/saml-2.0/assertion_query.c b/lasso/saml-2.0/assertion_query.c index 1d083491..9e9c7254 100644 --- a/lasso/saml-2.0/assertion_query.c +++ b/lasso/saml-2.0/assertion_query.c @@ -379,70 +379,18 @@ lasso_assertion_query_process_response_msg( gchar *response_msg) { LassoProfile *profile; - LassoHttpMethod response_method; - LassoProvider *remote_provider; LassoSamlp2StatusResponse *response; - LassoMessageFormat format; - char *status_code_value; int rc; - g_return_val_if_fail(LASSO_IS_ASSERTION_QUERY(assertion_query), - LASSO_PARAM_ERROR_INVALID_VALUE); - g_return_val_if_fail(response_msg != NULL, LASSO_PARAM_ERROR_INVALID_VALUE); - - profile = LASSO_PROFILE(assertion_query); - - if (LASSO_IS_SAMLP2_MANAGE_NAME_ID_RESPONSE(profile->response) == TRUE) { - lasso_node_destroy(profile->response); - profile->response = NULL; - } - - profile->response = lasso_samlp2_response_new(); - format = lasso_node_init_from_message(LASSO_NODE(profile->response), response_msg); - - switch (format) { - case LASSO_MESSAGE_FORMAT_SOAP: - response_method = LASSO_HTTP_METHOD_SOAP; - break; - case LASSO_MESSAGE_FORMAT_QUERY: - response_method = LASSO_HTTP_METHOD_REDIRECT; - break; - default: - return critical_error(LASSO_PROFILE_ERROR_INVALID_MSG); - } - - profile->remote_providerID = g_strdup( - LASSO_SAMLP2_STATUS_RESPONSE(profile->response)->Issuer->content); - - /* get the provider */ - remote_provider = lasso_server_get_provider(profile->server, profile->remote_providerID); - if (LASSO_IS_PROVIDER(remote_provider) == FALSE) { - return critical_error(LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND); - } - - /* verify signature */ - rc = lasso_provider_verify_signature(remote_provider, response_msg, "ID", format); - if (rc == LASSO_DS_ERROR_SIGNATURE_NOT_FOUND) { - /* XXX: is signature mandatory ? */ - message(G_LOG_LEVEL_WARNING, "No signature on response"); - rc = 0; - } - - response = LASSO_SAMLP2_STATUS_RESPONSE(profile->response); - - if (response->Status == NULL || response->Status->StatusCode == NULL - || response->Status->StatusCode->Value == NULL) { - message(G_LOG_LEVEL_CRITICAL, "No Status in Response !"); - return LASSO_PROFILE_ERROR_MISSING_STATUS_CODE; - } - status_code_value = response->Status->StatusCode->Value; + lasso_bad_param(ASSERTION_QUERY, assertion_query); + profile = &assertion_query->parent; + response = (LassoSamlp2StatusResponse*)lasso_samlp2_response_new(); - if (strcmp(status_code_value, LASSO_SAML2_STATUS_CODE_SUCCESS) != 0) { - message(G_LOG_LEVEL_CRITICAL, "Status code is not success: %s", status_code_value); - return LASSO_PROFILE_ERROR_STATUS_NOT_SUCCESS; - } + rc = lasso_saml20_profile_process_any_response(profile, response, NULL, response_msg); - return 0; +/* cleanup: */ + lasso_release_gobject(response); + return rc; } diff --git a/lasso/saml-2.0/ecp.c b/lasso/saml-2.0/ecp.c index 48b0ae77..5d08d7c8 100644 --- a/lasso/saml-2.0/ecp.c +++ b/lasso/saml-2.0/ecp.c @@ -162,6 +162,7 @@ lasso_ecp_process_authn_request_msg(LassoEcp *ecp, const char *authn_request_msg if (xpathObj && xpathObj->nodesetval && xpathObj->nodesetval->nodeNr) { xmlnode = xpathObj->nodesetval->nodeTab[0]; xmlUnlinkNode(xmlnode); + xmlFreeNode(xmlnode); } xmlXPathFreeObject(xpathObj); xmlXPathFreeContext(xpathCtx); diff --git a/lasso/saml-2.0/login.c b/lasso/saml-2.0/login.c index 95c4a3bc..ccce04e9 100644 --- a/lasso/saml-2.0/login.c +++ b/lasso/saml-2.0/login.c @@ -26,10 +26,10 @@ #include <libxml/xpath.h> #include <libxml/xpathInternals.h> -#include "providerprivate.h" -#include "loginprivate.h" -#include "profileprivate.h" -#include "federationprivate.h" +#include "./providerprivate.h" +#include "./loginprivate.h" +#include "./profileprivate.h" +#include "./federationprivate.h" #include "./saml2_helper.h" #include "../id-ff/providerprivate.h" @@ -60,6 +60,8 @@ static gint lasso_saml20_login_process_response_status_and_assertion(LassoLogin static char* lasso_saml20_login_get_assertion_consumer_service_url(LassoLogin *login, LassoProvider *remote_provider); +/* No need to check type of arguments, it has been done in lasso_login_* methods */ + gint lasso_saml20_login_init_authn_request(LassoLogin *login, LassoHttpMethod http_method) { @@ -69,7 +71,6 @@ lasso_saml20_login_init_authn_request(LassoLogin *login, LassoHttpMethod http_me gchar *default_name_id_format = NULL; int rc = 0; - lasso_bad_param(LOGIN, login); profile = &login->parent; lasso_extract_node_or_fail(server, lasso_profile_get_server(profile), SERVER, LASSO_PROFILE_ERROR_MISSING_SERVER); @@ -112,104 +113,98 @@ lasso_saml20_login_init_authn_request(LassoLogin *login, LassoHttpMethod http_me lasso_assign_string(LASSO_SAMLP2_AUTHN_REQUEST(request)->NameIDPolicy->SPNameQualifier, request->Issuer->content); - if (http_method != LASSO_HTTP_METHOD_REDIRECT) { - request->sign_method = LASSO_SIGNATURE_METHOD_RSA_SHA1; - if (profile->server->certificate) { - request->sign_type = LASSO_SIGNATURE_TYPE_WITHX509; - } else { - request->sign_type = LASSO_SIGNATURE_TYPE_SIMPLE; - } - } - cleanup: return rc; } +static gboolean +_lasso_login_must_sign_non_authn_request(LassoLogin *profile) +{ + switch (lasso_profile_get_signature_hint(&profile->parent)) { + case LASSO_PROFILE_SIGNATURE_HINT_MAYBE: + return lasso_flag_add_signature; + case LASSO_PROFILE_SIGNATURE_HINT_FORCE: + return TRUE; + case LASSO_PROFILE_SIGNATURE_HINT_FORBID: + return FALSE; + default: + return TRUE; + } +} -gint -lasso_saml20_login_build_authn_request_msg(LassoLogin *login, LassoProvider *remote_provider) +static gboolean +_lasso_login_must_sign(LassoProfile *profile) { - char *url; char *md_authnRequestsSigned; - gboolean must_sign; - LassoProfile *profile = LASSO_PROFILE(login); + gboolean ret; + + switch (lasso_profile_get_signature_hint(profile)) { + case LASSO_PROFILE_SIGNATURE_HINT_MAYBE: + md_authnRequestsSigned = lasso_provider_get_metadata_one( + LASSO_PROVIDER(profile->server), "AuthnRequestsSigned"); + /* default is to sign ! */ + ret = ! md_authnRequestsSigned || g_strcmp0(md_authnRequestsSigned, "false") != 0; + lasso_release_string(md_authnRequestsSigned); + return ret; + case LASSO_PROFILE_SIGNATURE_HINT_FORCE: + return TRUE; + case LASSO_PROFILE_SIGNATURE_HINT_FORBID: + return FALSE; + default: + return TRUE; + } +} + +gint +lasso_saml20_login_build_authn_request_msg(LassoLogin *login) +{ + char *url = NULL; + gboolean must_sign = TRUE; + LassoProfile *profile; + LassoSamlp2AuthnRequest *authn_request; + int rc = 0; + LassoHttpMethod http_method; - md_authnRequestsSigned = lasso_provider_get_metadata_one( - LASSO_PROVIDER(profile->server), "AuthnRequestsSigned"); - must_sign = (md_authnRequestsSigned && strcmp(md_authnRequestsSigned, "true") == 0); - g_free(md_authnRequestsSigned); + profile = &login->parent; + http_method = login->http_method; - if (! lasso_flag_sign_messages && must_sign) { - message(G_LOG_LEVEL_WARNING, "AuthnRequest message should normally be signed but \"no-sign-messages\" option is activated"); - } + lasso_extract_node_or_fail(authn_request, profile->request, SAMLP2_AUTHN_REQUEST, + LASSO_PROFILE_ERROR_INVALID_REQUEST); - if (login->http_method == LASSO_HTTP_METHOD_REDIRECT) { - return lasso_saml20_build_http_redirect_query_simple(profile, profile->request, - must_sign, "SingleSignOnService", FALSE); - } else { - /* POST, SOAP and Artifact-GET|POST */ - if (must_sign && lasso_flag_sign_messages) { - lasso_assign_string(LASSO_SAMLP2_REQUEST_ABSTRACT(profile->request)->private_key_file, - profile->server->private_key); - lasso_assign_string(LASSO_SAMLP2_REQUEST_ABSTRACT(profile->request)->certificate_file, - profile->server->certificate); - } + /* default is to sign ! */ + must_sign = _lasso_login_must_sign(profile); - if (login->http_method == LASSO_HTTP_METHOD_POST) { - lasso_assign_new_string(profile->msg_url, - lasso_provider_get_metadata_one(remote_provider, - "SingleSignOnService HTTP-POST")); - lasso_assign_new_string(profile->msg_body, - lasso_node_export_to_base64(profile->request)); - } else if (login->http_method == LASSO_HTTP_METHOD_SOAP) { - const char *issuer; - const char *responseConsumerURL; - - issuer = LASSO_PROVIDER(LASSO_PROFILE(login)->server)->ProviderID; - responseConsumerURL = \ - lasso_saml20_login_get_assertion_consumer_service_url( - login, LASSO_PROVIDER(profile->server)); - lasso_release_string(profile->msg_url); - lasso_assign_new_string(profile->msg_body, - lasso_node_export_to_paos_request(profile->request, - issuer, responseConsumerURL, - profile->msg_relayState)); - } else { - /* artifact method */ - char *artifact = lasso_saml20_profile_generate_artifact(profile, 0); - url = lasso_provider_get_metadata_one( - remote_provider, "SingleSignOnService HTTP-Artifact"); - if (login->http_method == LASSO_HTTP_METHOD_ARTIFACT_GET) { - gchar *query; - - if (profile->msg_relayState) { - query = lasso_url_add_parameters(NULL, 0, "SAMLart", artifact, "RelayState", - profile->msg_relayState, NULL); - } else { - query = lasso_url_add_parameters(NULL, 0, "SAMLart", artifact, NULL); - } - lasso_assign_new_string(profile->msg_url, - lasso_concat_url_query(url, query)); - lasso_release_string(query); - lasso_release_string(url); - } else { - /* TODO: ARTIFACT POST */ - } - } + if (! must_sign) { + lasso_node_remove_signature(profile->request); } - return 0; + /* support old way of doing PAOS */ + if (login->http_method == LASSO_HTTP_METHOD_SOAP + && g_strcmp0(authn_request->ProtocolBinding, + LASSO_SAML2_METADATA_BINDING_PAOS) == 0) { + login->http_method = LASSO_HTTP_METHOD_PAOS; + /* PAOS is special, the url passed to build_request is the AssertionConsumerServiceURL of + * this SP, not the destination. */ + url = lasso_saml20_login_get_assertion_consumer_service_url(login, + LASSO_PROVIDER(profile->server)); + } + + lasso_check_good_rc(lasso_saml20_profile_build_request_msg(profile, "SingleSignOnService", + login->http_method, url)); + +cleanup: + return rc; } int lasso_saml20_login_process_authn_request_msg(LassoLogin *login, const char *authn_request_msg) { LassoNode *request; - LassoMessageFormat format; LassoProfile *profile = LASSO_PROFILE(login); LassoSamlp2StatusResponse *response; LassoSamlp2AuthnRequest *authn_request; gchar *protocol_binding; + int rc = 0; if (authn_request_msg == NULL) { if (profile->request == NULL) { @@ -220,23 +215,9 @@ lasso_saml20_login_process_authn_request_msg(LassoLogin *login, const char *auth request = profile->request; } else { request = lasso_samlp2_authn_request_new(); - format = lasso_node_init_from_message(request, authn_request_msg); - if (format == LASSO_MESSAGE_FORMAT_UNKNOWN || - format == LASSO_MESSAGE_FORMAT_ERROR) { - return critical_error(LASSO_PROFILE_ERROR_INVALID_MSG); - } - if (format == LASSO_MESSAGE_FORMAT_QUERY) { - lasso_assign_new_string(profile->msg_relayState, - lasso_get_relaystate_from_query(authn_request_msg)); - } + lasso_check_good_rc(lasso_saml20_profile_process_any_request(profile, request, authn_request_msg)); } - authn_request = LASSO_SAMLP2_AUTHN_REQUEST(request); - - lasso_assign_new_gobject(profile->request, request); - lasso_assign_string(profile->remote_providerID, - LASSO_SAMLP2_REQUEST_ABSTRACT(request)->Issuer->content); - protocol_binding = authn_request->ProtocolBinding; if (protocol_binding == NULL) { /* protocol binding not set; so it will look into @@ -259,46 +240,48 @@ lasso_saml20_login_process_authn_request_msg(LassoLogin *login, const char *auth if (binding == NULL) { if (service_index == -1) return LASSO_LOGIN_ERROR_NO_DEFAULT_ENDPOINT; - } else if (strcmp(binding, "HTTP-Artifact") == 0) { + } else if (g_strcmp0(binding, "HTTP-Artifact") == 0) { login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_ART; - } else if (strcmp(binding, "HTTP-POST") == 0) { + } else if (g_strcmp0(binding, "HTTP-POST") == 0) { login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_POST; - } else if (strcmp(binding, "HTTP-Redirect") == 0) { + } else if (g_strcmp0(binding, "HTTP-Redirect") == 0) { login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_REDIRECT; - } else if (strcmp(binding, "SOAP") == 0) { + } else if (g_strcmp0(binding, "SOAP") == 0) { login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_LECP; - } else if (strcmp(binding, "PAOS") == 0) { + } else if (g_strcmp0(binding, "PAOS") == 0) { login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_LECP; } lasso_release_string(binding); - } else if (strcmp(protocol_binding, LASSO_SAML2_METADATA_BINDING_ARTIFACT) == 0) { + } else if (g_strcmp0(protocol_binding, LASSO_SAML2_METADATA_BINDING_ARTIFACT) == 0) { login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_ART; - } else if (strcmp(protocol_binding, LASSO_SAML2_METADATA_BINDING_POST) == 0) { + } else if (g_strcmp0(protocol_binding, LASSO_SAML2_METADATA_BINDING_POST) == 0) { login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_POST; - } else if (strcmp(protocol_binding, LASSO_SAML2_METADATA_BINDING_SOAP) == 0) { + } else if (g_strcmp0(protocol_binding, LASSO_SAML2_METADATA_BINDING_SOAP) == 0) { login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_LECP; - } else if (strcmp(protocol_binding, LASSO_SAML2_METADATA_BINDING_REDIRECT) == 0) { + } else if (g_strcmp0(protocol_binding, LASSO_SAML2_METADATA_BINDING_REDIRECT) == 0) { login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_REDIRECT; - } else if (strcmp(protocol_binding, LASSO_SAML2_METADATA_BINDING_PAOS) == 0) { + } else if (g_strcmp0(protocol_binding, LASSO_SAML2_METADATA_BINDING_PAOS) == 0) { login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_LECP; } else { message(G_LOG_LEVEL_CRITICAL, "unhandled protocol binding: %s", protocol_binding); } - /* XXX: checks authn request signature */ - lasso_assign_new_gobject(profile->response, lasso_samlp2_response_new()); - response = LASSO_SAMLP2_STATUS_RESPONSE(profile->response); - response->ID = lasso_build_unique_id(32); - lasso_assign_string(response->Version, "2.0"); - response->Issuer = LASSO_SAML2_NAME_ID(lasso_saml2_name_id_new_with_string( - LASSO_PROVIDER(profile->server)->ProviderID)); - response->IssueInstant = lasso_get_current_time(); + response = (LassoSamlp2StatusResponse*) lasso_samlp2_response_new(); + if (profile->signature_status) { + lasso_check_good_rc(lasso_saml20_profile_init_response(profile, response, + LASSO_SAML2_STATUS_CODE_REQUESTER, + LASSO_LIB_STATUS_CODE_INVALID_SIGNATURE)); + rc = profile->signature_status; + } else { + lasso_check_good_rc(lasso_saml20_profile_init_response(profile, response, + LASSO_SAML2_STATUS_CODE_SUCCESS, NULL)); + } lasso_assign_string(response->InResponseTo, LASSO_SAMLP2_REQUEST_ABSTRACT(profile->request)->ID); - /* XXX: adds signature */ - return 0; +cleanup: + return rc; } @@ -308,14 +291,15 @@ lasso_saml20_login_must_authenticate(LassoLogin *login) LassoSamlp2AuthnRequest *request; gboolean matched = TRUE; GList *assertions = NULL; - LassoProfile *profile = LASSO_PROFILE(login); + LassoProfile *profile = &login->parent; - request = LASSO_SAMLP2_AUTHN_REQUEST(LASSO_PROFILE(login)->request); + if (! LASSO_IS_SAMLP2_AUTHN_REQUEST(profile->request)) + return FALSE; + request = LASSO_SAMLP2_AUTHN_REQUEST(profile->request); if (request->ForceAuthn == TRUE && request->IsPassive == FALSE) return TRUE; - assertions = lasso_session_get_assertions(profile->session, NULL); if (request->RequestedAuthnContext) { char *comparison = request->RequestedAuthnContext->Comparison; GList *class_refs = request->RequestedAuthnContext->AuthnContextClassRef; @@ -323,15 +307,15 @@ lasso_saml20_login_must_authenticate(LassoLogin *login) GList *t1, *t2; int compa; - if (comparison == NULL || strcmp(comparison, "exact") == 0) { + if (comparison == NULL || g_strcmp0(comparison, "exact") == 0) { compa = 0; - } else if (strcmp(comparison, "minimum") == 0) { + } else if (g_strcmp0(comparison, "minimum") == 0) { message(G_LOG_LEVEL_CRITICAL, "'minimum' comparison is not implemented"); compa = 0; - } else if (strcmp(comparison, "better") == 0) { + } else if (g_strcmp0(comparison, "better") == 0) { message(G_LOG_LEVEL_CRITICAL, "'better' comparison is not implemented"); compa = 0; - } else if (strcmp(comparison, "maximum") == 0) { + } else if (g_strcmp0(comparison, "maximum") == 0) { message(G_LOG_LEVEL_CRITICAL, "'maximum' comparison is not implemented"); compa = 0; } @@ -340,6 +324,7 @@ lasso_saml20_login_must_authenticate(LassoLogin *login) matched = FALSE; } + assertions = lasso_session_get_assertions(profile->session, NULL); for (t1 = class_refs; t1 && !matched; t1 = g_list_next(t1)) { class_ref = t1->data; for (t2 = assertions; t2 && !matched; t2 = g_list_next(t2)) { @@ -370,7 +355,7 @@ lasso_saml20_login_must_authenticate(LassoLogin *login) method = as->AuthnContext->AuthnContextClassRef; if (compa == 0) { /* exact */ - if (strcmp(method, class_ref) == 0) { + if (g_strcmp0(method, class_ref) == 0) { matched = TRUE; break; } @@ -383,7 +368,6 @@ lasso_saml20_login_must_authenticate(LassoLogin *login) } } } - } else { /* if nothing specific was asked; don't look for any * particular assertions, one is enough @@ -391,19 +375,17 @@ lasso_saml20_login_must_authenticate(LassoLogin *login) matched = (profile->session != NULL && \ lasso_session_count_assertions(profile->session) > 0); } - g_list_free(assertions); - + if (assertions) { + g_list_free(assertions); + } if (matched == FALSE && request->IsPassive == FALSE) return TRUE; - if (profile->identity == NULL && request->IsPassive) { lasso_saml20_profile_set_response_status_responder(LASSO_PROFILE(login), LASSO_SAML2_STATUS_CODE_NO_PASSIVE); return FALSE; } - return FALSE; - } static gboolean @@ -421,7 +403,7 @@ lasso_saml20_login_must_ask_for_consent_private(LassoLogin *login) if (name_id_policy) { char *format = name_id_policy->Format; - if (strcmp(format, LASSO_SAML2_NAME_IDENTIFIER_FORMAT_TRANSIENT) == 0) { + if (g_strcmp0(format, LASSO_SAML2_NAME_IDENTIFIER_FORMAT_TRANSIENT) == 0) { goto_cleanup_with_rc (FALSE) } if (name_id_policy->AllowCreate == FALSE) { @@ -448,22 +430,22 @@ lasso_saml20_login_must_ask_for_consent_private(LassoLogin *login) if (consent == NULL) goto_cleanup_with_rc (FALSE) - if (strcmp(consent, LASSO_SAML2_CONSENT_OBTAINED) == 0) + if (g_strcmp0(consent, LASSO_SAML2_CONSENT_OBTAINED) == 0) goto_cleanup_with_rc (FALSE) - if (strcmp(consent, LASSO_SAML2_CONSENT_PRIOR) == 0) + if (g_strcmp0(consent, LASSO_SAML2_CONSENT_PRIOR) == 0) goto_cleanup_with_rc (FALSE) - if (strcmp(consent, LASSO_SAML2_CONSENT_IMPLICIT) == 0) + if (g_strcmp0(consent, LASSO_SAML2_CONSENT_IMPLICIT) == 0) goto_cleanup_with_rc (FALSE) - if (strcmp(consent, LASSO_SAML2_CONSENT_EXPLICIT) == 0) + if (g_strcmp0(consent, LASSO_SAML2_CONSENT_EXPLICIT) == 0) goto_cleanup_with_rc (FALSE) - if (strcmp(consent, LASSO_SAML2_CONSENT_UNAVAILABLE) == 0) + if (g_strcmp0(consent, LASSO_SAML2_CONSENT_UNAVAILABLE) == 0) goto_cleanup_with_rc (TRUE) - if (strcmp(consent, LASSO_SAML2_CONSENT_INAPPLICABLE) == 0) + if (g_strcmp0(consent, LASSO_SAML2_CONSENT_INAPPLICABLE) == 0) goto_cleanup_with_rc (TRUE) cleanup: @@ -498,14 +480,14 @@ lasso_saml20_login_validate_request_msg(LassoLogin *login, gboolean authenticati } if (profile->signature_status == LASSO_DS_ERROR_INVALID_SIGNATURE) { - lasso_saml20_profile_set_response_status_responder(profile, - LASSO_SAML2_STATUS_CODE_REQUEST_DENIED); + lasso_saml20_profile_set_response_status_requester(profile, + LASSO_LIB_STATUS_CODE_INVALID_SIGNATURE); return LASSO_LOGIN_ERROR_INVALID_SIGNATURE; } if (profile->signature_status == LASSO_DS_ERROR_SIGNATURE_NOT_FOUND) { - lasso_saml20_profile_set_response_status_responder(profile, - LASSO_SAML2_STATUS_CODE_REQUEST_DENIED); + lasso_saml20_profile_set_response_status_requester(profile, + LASSO_LIB_STATUS_CODE_INVALID_SIGNATURE); return LASSO_LOGIN_ERROR_UNSIGNED_AUTHN_REQUEST; } @@ -516,7 +498,7 @@ lasso_saml20_login_validate_request_msg(LassoLogin *login, gboolean authenticati LASSO_LIB_STATUS_CODE_FEDERATION_DOES_NOT_EXIST); return ret; } - /* Only possibility, consent not obtained. */ + /* PROVIDER_NOT_FOUND, CONSENT_NOT_OBTAINED */ if (ret) { lasso_saml20_profile_set_response_status_responder(profile, LASSO_SAML2_STATUS_CODE_REQUEST_DENIED); @@ -554,7 +536,7 @@ lasso_saml20_login_process_federation(LassoLogin *login, gboolean is_consent_obt lasso_assign_string(login->nameIDPolicy, name_id_policy_format); - if (name_id_policy_format && strcmp(name_id_policy_format, + if (name_id_policy_format && g_strcmp0(name_id_policy_format, LASSO_SAML2_NAME_IDENTIFIER_FORMAT_TRANSIENT) == 0) { goto_cleanup_with_rc (0) } @@ -618,6 +600,18 @@ cleanup: return rc; } +static LassoFederation* +_lasso_login_saml20_get_federation(LassoLogin *login) { + LassoFederation *federation = NULL; + char *name_id_sp_name_qualifier; + + + name_id_sp_name_qualifier = lasso_provider_get_sp_name_qualifier( + lasso_server_get_provider(login->parent.server, login->parent.remote_providerID)); + federation = lasso_identity_get_federation(login->parent.identity, name_id_sp_name_qualifier); + lasso_release_string(name_id_sp_name_qualifier); + return federation; +} int lasso_saml20_login_build_assertion(LassoLogin *login, @@ -626,44 +620,40 @@ lasso_saml20_login_build_assertion(LassoLogin *login, const char *notBefore, const char *notOnOrAfter) { - LassoProfile *profile = LASSO_PROFILE(login); - LassoFederation *federation; - LassoSaml2Assertion *assertion; - LassoSaml2AudienceRestriction *audience_restriction; - LassoSamlp2NameIDPolicy *name_id_policy; + LassoProfile *profile = &login->parent; +#if 0 + LassoFederation *federation = NULL; +#endif + LassoSaml2Assertion *assertion = NULL; + LassoSaml2AudienceRestriction *audience_restriction = NULL; + LassoSamlp2NameIDPolicy *name_id_policy = NULL; LassoSaml2NameID *name_id = NULL; LassoSaml2AuthnStatement *authentication_statement; LassoProvider *provider = NULL; - LassoSaml2EncryptedElement *encrypted_element = 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 (! LASSO_IS_PROVIDER(provider)) { - return LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND; + 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 (profile->request && LASSO_IS_SAMLP2_REQUEST_ABSTRACT(profile->request)) { - request_abstract = LASSO_SAMLP2_REQUEST_ABSTRACT(profile->request); + 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); - if (profile->identity && strcmp(login->nameIDPolicy, - LASSO_SAML2_NAME_IDENTIFIER_FORMAT_TRANSIENT) != 0) { - char *name_id_sp_name_qualifier; - name_id_sp_name_qualifier = lasso_provider_get_sp_name_qualifier(provider); - - if (name_id_sp_name_qualifier != NULL) { - federation = g_hash_table_lookup(profile->identity->federations, - name_id_sp_name_qualifier); - lasso_release_string(name_id_sp_name_qualifier); - } - if (federation == NULL) { - message(G_LOG_LEVEL_WARNING, "can't find federation for identity"); - } - } else { - federation = NULL; - } + response = (LassoSamlp2Response*)profile->response; assertion = LASSO_SAML2_ASSERTION(lasso_saml2_assertion_new()); assertion->ID = lasso_build_unique_id(32); @@ -678,7 +668,6 @@ lasso_saml20_login_build_assertion(LassoLogin *login, lasso_assign_string(audience_restriction->Audience, profile->remote_providerID); lasso_list_add_new_gobject(assertion->Conditions->AudienceRestriction, audience_restriction); - name_id_policy = LASSO_SAMLP2_AUTHN_REQUEST(profile->request)->NameIDPolicy; assertion->Subject = LASSO_SAML2_SUBJECT(lasso_saml2_subject_new()); assertion->Subject->SubjectConfirmation = LASSO_SAML2_SUBJECT_CONFIRMATION( lasso_saml2_subject_confirmation_new()); @@ -691,10 +680,12 @@ lasso_saml20_login_build_assertion(LassoLogin *login, notBefore); assertion->Subject->SubjectConfirmation->SubjectConfirmationData->NotOnOrAfter = g_strdup( notOnOrAfter); - if (request_abstract) { - lasso_assign_string(assertion->Subject->SubjectConfirmation->SubjectConfirmationData->InResponseTo, - request_abstract->ID); + + /* 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>, @@ -702,49 +693,46 @@ lasso_saml20_login_build_assertion(LassoLogin *login, */ lasso_release_string(assertion->Subject->SubjectConfirmation->SubjectConfirmationData->NotBefore); } + name_id_policy = authn_request->NameIDPolicy; } - - if (name_id_policy && (strcmp(name_id_policy->Format, - LASSO_SAML2_NAME_IDENTIFIER_FORMAT_EMAIL) == 0 || - strcmp(name_id_policy->Format, - LASSO_SAML2_NAME_IDENTIFIER_FORMAT_UNSPECIFIED) == 0)) { - /* 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; - } else if (federation == NULL || - (name_id_policy && strcmp(name_id_policy->Format, - LASSO_SAML2_NAME_IDENTIFIER_FORMAT_TRANSIENT) == 0)) { - /* transient -> don't use a federation */ - name_id = LASSO_SAML2_NAME_ID(lasso_saml2_name_id_new_with_string( - lasso_build_unique_id(32))); + /* TRANSIENT */ + if (!name_id_policy || g_strcmp0(name_id_policy->Format, + LASSO_SAML2_NAME_IDENTIFIER_FORMAT_TRANSIENT) == 0) { + name_id = (LassoSaml2NameID*)lasso_saml2_name_id_new_with_string( + lasso_build_unique_id(32)); lasso_assign_string(name_id->NameQualifier, - LASSO_PROVIDER(profile->server)->ProviderID); + 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; - } else { - if (provider && name_id_policy && strcmp(name_id_policy->Format, + /* FEDERATED */ + } else if (g_strcmp0(name_id_policy->Format, + LASSO_SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT) == 0 || + g_strcmp0(name_id_policy->Format, + LASSO_SAML2_NAME_IDENTIFIER_FORMAT_ENCRYPTED) == 0) { + LassoFederation *federation; + + federation = _lasso_login_saml20_get_federation(login); + goto_cleanup_if_fail_with_rc(federation != NULL, + LASSO_PROFILE_ERROR_FEDERATION_NOT_FOUND); + + if (g_strcmp0(name_id_policy->Format, LASSO_SAML2_NAME_IDENTIFIER_FORMAT_ENCRYPTED) == 0) { - provider->private_data->encryption_mode |= LASSO_ENCRYPTION_MODE_NAMEID; + do_encrypt_nameid = TRUE; } lasso_assign_gobject(assertion->Subject->NameID, federation->local_nameIdentifier); - } - - /* Encrypt NameID */ - if (provider && provider->private_data->encryption_mode & LASSO_ENCRYPTION_MODE_NAMEID - && provider->private_data->encryption_public_key != NULL - && assertion->Subject->NameID->content != NULL) { - encrypted_element = LASSO_SAML2_ENCRYPTED_ELEMENT(lasso_node_encrypt( - LASSO_NODE(assertion->Subject->NameID), - provider->private_data->encryption_public_key, - provider->private_data->encryption_sym_key_type)); - if (encrypted_element != NULL) { - assertion->Subject->EncryptedID = encrypted_element; - g_object_unref(assertion->Subject->NameID); - assertion->Subject->NameID = NULL; + /* 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; } } @@ -755,20 +743,34 @@ lasso_saml20_login_build_assertion(LassoLogin *login, lasso_saml2_authn_context_new()); authentication_statement->AuthnContext->AuthnContextClassRef = g_strdup( authenticationMethod); - - assertion->AuthnStatement = g_list_append(NULL, authentication_statement); + lasso_list_add_new_gobject(assertion->AuthnStatement, authentication_statement); /* Save signing material in assertion private datas to be able to sign later */ - lasso_server_saml2_assertion_setup_signature(profile->server, assertion); + lasso_check_good_rc(lasso_server_saml2_assertion_setup_signature(profile->server, + assertion)); + + + /* Encrypt NameID */ + if (do_encrypt_nameid) { + /* 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)); + 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 (provider && provider->private_data->encryption_mode & LASSO_ENCRYPTION_MODE_ASSERTION - && provider->private_data->encryption_public_key != NULL) { + if (do_encrypt_assertion) { assertion->encryption_activated = TRUE; - assertion->encryption_public_key_str = g_strdup( - provider->private_data->encryption_public_key_str); + lasso_assign_string(assertion->encryption_public_key_str, + provider->private_data->encryption_public_key_str); assertion->encryption_sym_key_type = - provider->private_data->encryption_sym_key_type; + lasso_provider_get_encryption_sym_key_type(provider); } /* store assertion in session object */ @@ -780,11 +782,11 @@ lasso_saml20_login_build_assertion(LassoLogin *login, LASSO_NODE(assertion)); response = LASSO_SAMLP2_RESPONSE(profile->response); - lasso_list_add_new_gobject(response->Assertion, assertion); - + lasso_list_add_gobject(response->Assertion, assertion); lasso_assign_gobject(login->private_data->saml2_assertion, assertion); - - return 0; +cleanup: + lasso_release_gobject(assertion); + return rc; } gint @@ -792,12 +794,12 @@ lasso_saml20_login_build_artifact_msg(LassoLogin *login, LassoHttpMethod http_me { LassoProfile *profile; LassoProvider *remote_provider; - char *artifact; char *url; LassoSaml2Assertion *assertion; LassoSamlp2StatusResponse *response; + int rc = 0; - profile = LASSO_PROFILE(login); + profile = &login->parent; if (profile->remote_providerID == NULL) return critical_error(LASSO_PROFILE_ERROR_MISSING_REMOTE_PROVIDERID); @@ -806,54 +808,36 @@ lasso_saml20_login_build_artifact_msg(LassoLogin *login, LassoHttpMethod http_me return critical_error(LASSO_PROFILE_ERROR_INVALID_HTTP_METHOD); } + if (! LASSO_IS_SAMLP2_RESPONSE(profile->response)) { + return critical_error(LASSO_PROFILE_ERROR_MISSING_RESPONSE); + } + response = (LassoSamlp2StatusResponse*)profile->response; + /* XXX: why checking now ? */ + if (response->Status == NULL || response->Status->StatusCode == NULL + || response->Status->StatusCode->Value == NULL) { + return critical_error(LASSO_PROFILE_ERROR_MISSING_STATUS_CODE); + } + remote_provider = lasso_server_get_provider(profile->server, profile->remote_providerID); if (LASSO_IS_PROVIDER(remote_provider) == FALSE) return critical_error(LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND); url = lasso_saml20_login_get_assertion_consumer_service_url(login, remote_provider); assertion = login->private_data->saml2_assertion; - if (LASSO_IS_SAML2_ASSERTION(assertion) == TRUE) { - assertion->Subject->SubjectConfirmation->SubjectConfirmationData->Recipient = - g_strdup(url); - } - - artifact = lasso_saml20_profile_generate_artifact(profile, 1); - lasso_assign_string(login->assertionArtifact, artifact); - if (http_method == LASSO_HTTP_METHOD_ARTIFACT_GET) { - gchar *query; - - if (profile->msg_relayState) { - query = lasso_url_add_parameters(NULL, 0, "SAMLart", artifact, "RelayState", - profile->msg_relayState, NULL); - } else { - query = lasso_url_add_parameters(NULL, 0, "SAMLart", artifact, NULL); - } - lasso_assign_new_string(profile->msg_url, lasso_concat_url_query(url, query)); - lasso_release_string(query); - } else { - /* XXX: ARTIFACT POST */ - } - lasso_release_string(url); + if (LASSO_IS_SAML2_ASSERTION(assertion) && url) { + LassoSaml2SubjectConfirmationData *subject_confirmation_data; - response = LASSO_SAMLP2_STATUS_RESPONSE(profile->response); - if (response->Status == NULL || response->Status->StatusCode == NULL - || response->Status->StatusCode->Value == NULL) { - return critical_error(LASSO_PROFILE_ERROR_MISSING_STATUS_CODE); + subject_confirmation_data = + lasso_saml2_assertion_get_subject_confirmation_data(assertion, TRUE); + lasso_assign_string(subject_confirmation_data->Recipient, url); } - if (strcmp(LASSO_SAMLP2_STATUS_RESPONSE(profile->response)->Status->StatusCode->Value, - "samlp:Success") != 0) { - if (profile->session == NULL) - profile->session = lasso_session_new(); - - lasso_session_add_status(profile->session, profile->remote_providerID, - g_object_ref(LASSO_SAMLP2_STATUS_RESPONSE( - profile->response)->Status)); - } else { - lasso_session_remove_status(profile->session, profile->remote_providerID); - } + lasso_check_good_rc(lasso_saml20_profile_build_response_msg(profile, NULL, http_method, + url)); - return 0; +cleanup: + lasso_release_string(url); + return rc; } @@ -870,23 +854,15 @@ gint lasso_saml20_login_build_request_msg(LassoLogin *login) { LassoProfile *profile; - LassoProvider *remote_provider; - - profile = LASSO_PROFILE(login); - lasso_assign_string(LASSO_SAMLP2_REQUEST_ABSTRACT(profile->request)->private_key_file, - profile->server->private_key); - lasso_assign_string(LASSO_SAMLP2_REQUEST_ABSTRACT(profile->request)->certificate_file, - profile->server->certificate); - lasso_assign_new_string(profile->msg_body, lasso_node_export_to_soap(profile->request)); - - remote_provider = lasso_server_get_provider(profile->server, profile->remote_providerID); - if (LASSO_IS_PROVIDER(remote_provider) == FALSE) { - return critical_error(LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND); + profile = &login->parent; + if (_lasso_login_must_sign_non_authn_request(login)) { + lasso_profile_saml20_setup_message_signature(profile, profile->request); + } else { + lasso_node_remove_signature(profile->request); } - lasso_assign_new_string(profile->msg_url, lasso_provider_get_metadata_one(remote_provider, - "ArtifactResolutionService SOAP")); - return 0; + return lasso_saml20_profile_build_request_msg(profile, "ArtifactResolutionService", + LASSO_HTTP_METHOD_SOAP, NULL); } gint @@ -910,25 +886,13 @@ lasso_saml20_login_build_response_msg(LassoLogin *login) LassoProfile *profile = LASSO_PROFILE(login); LassoProvider *remote_provider; LassoSaml2Assertion *assertion; + int rc = 0; if (login->protocolProfile == LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_LECP) { const char *assertionConsumerURL; - if (profile->server->certificate) { - LASSO_SAMLP2_STATUS_RESPONSE(profile->response)->sign_type = - LASSO_SIGNATURE_TYPE_WITHX509; - } else { - LASSO_SAMLP2_STATUS_RESPONSE(profile->response)->sign_type = - LASSO_SIGNATURE_TYPE_SIMPLE; - } - LASSO_SAMLP2_STATUS_RESPONSE(profile->response)->sign_method = - LASSO_SIGNATURE_METHOD_RSA_SHA1; - - lasso_assign_string(LASSO_SAMLP2_STATUS_RESPONSE(profile->response)->private_key_file, - profile->server->private_key); - lasso_assign_string(LASSO_SAMLP2_STATUS_RESPONSE(profile->response)->certificate_file, - profile->server->certificate); - + lasso_check_good_rc(lasso_profile_saml20_setup_message_signature(profile, + profile->response)); remote_provider = lasso_server_get_provider(profile->server, profile->remote_providerID); if (LASSO_IS_PROVIDER(remote_provider) == FALSE) return critical_error(LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND); @@ -945,10 +909,13 @@ lasso_saml20_login_build_response_msg(LassoLogin *login) /* build an ECP SOAP Response */ lasso_assign_new_string(profile->msg_body, lasso_node_export_to_ecp_soap_response( LASSO_NODE(profile->response), assertionConsumerURL)); - return 0; + return rc; } return lasso_saml20_profile_build_artifact_response(LASSO_PROFILE(login)); + +cleanup: + return rc; } gint @@ -957,7 +924,6 @@ lasso_saml20_login_process_paos_response_msg(LassoLogin *login, gchar *msg) LassoProfile *profile; int rc1, rc2; - lasso_bad_param(LOGIN, login); lasso_null_param(msg); profile = LASSO_PROFILE(login); @@ -989,14 +955,13 @@ lasso_saml20_login_process_authn_response_msg(LassoLogin *login, gchar *authn_re int rc1, rc2, message_signature_status; LassoSamlp2Response *samlp2_response = NULL; - lasso_bad_param(LOGIN, login); lasso_null_param(authn_response_msg); /* parse the message */ profile = LASSO_PROFILE(login); samlp2_response = (LassoSamlp2Response*)lasso_samlp2_response_new(); rc1 = lasso_saml20_profile_process_any_response(profile, - (LassoSamlp2StatusResponse*)samlp2_response, + (LassoSamlp2StatusResponse*)samlp2_response, NULL, authn_response_msg); message_signature_status = profile->signature_status; @@ -1043,7 +1008,6 @@ lasso_saml20_login_check_assertion_signature(LassoLogin *login, LassoProvider *remote_provider; int rc = 0; - lasso_bad_param(LOGIN, login); lasso_bad_param(SAML2_ASSERTION, assertion); profile = (LassoProfile*)login; @@ -1055,7 +1019,7 @@ lasso_saml20_login_check_assertion_signature(LassoLogin *login, if (! Issuer || /* No issuer */ ! Issuer->content || /* No issuer content */ (Issuer->Format && - strcmp(Issuer->Format, LASSO_SAML2_NAME_IDENTIFIER_FORMAT_ENTITY) != 0)) + g_strcmp0(Issuer->Format, LASSO_SAML2_NAME_IDENTIFIER_FORMAT_ENTITY) != 0)) /* Issuer format is not entity */ { rc = LASSO_PROFILE_ERROR_MISSING_ISSUER; @@ -1121,19 +1085,19 @@ lasso_saml20_login_process_response_status_and_assertion(LassoLogin *login) } status_value = response->Status->StatusCode->Value; - if (status_value && strcmp(status_value, LASSO_SAML2_STATUS_CODE_SUCCESS) != 0) { - if (strcmp(status_value, LASSO_SAML2_STATUS_CODE_REQUEST_DENIED) == 0) + if (status_value && g_strcmp0(status_value, LASSO_SAML2_STATUS_CODE_SUCCESS) != 0) { + if (g_strcmp0(status_value, LASSO_SAML2_STATUS_CODE_REQUEST_DENIED) == 0) return LASSO_LOGIN_ERROR_REQUEST_DENIED; - if (strcmp(status_value, LASSO_SAML2_STATUS_CODE_RESPONDER) == 0) { + if (g_strcmp0(status_value, LASSO_SAML2_STATUS_CODE_RESPONDER) == 0) { /* samlp:Responder */ if (response->Status->StatusCode->StatusCode && response->Status->StatusCode->StatusCode->Value) { status_value = response->Status->StatusCode->StatusCode->Value; - if (strcmp(status_value, + if (g_strcmp0(status_value, LASSO_LIB_STATUS_CODE_FEDERATION_DOES_NOT_EXIST) == 0) { return LASSO_LOGIN_ERROR_FEDERATION_NOT_FOUND; } - if (strcmp(status_value, + if (g_strcmp0(status_value, LASSO_LIB_STATUS_CODE_UNKNOWN_PRINCIPAL) == 0) { return LASSO_LOGIN_ERROR_UNKNOWN_PRINCIPAL; } @@ -1204,7 +1168,7 @@ lasso_saml20_login_process_response_status_and_assertion(LassoLogin *login) assertion->Subject->SubjectConfirmation == NULL || assertion->Subject->SubjectConfirmation->SubjectConfirmationData == NULL || assertion->Subject->SubjectConfirmation->SubjectConfirmationData->InResponseTo == NULL || - strcmp(assertion->Subject->SubjectConfirmation->SubjectConfirmationData->InResponseTo, login->private_data->request_id) != 0)) { + g_strcmp0(assertion->Subject->SubjectConfirmation->SubjectConfirmationData->InResponseTo, login->private_data->request_id) != 0)) { return LASSO_LOGIN_ERROR_ASSERTION_DOES_NOT_MATCH_REQUEST_ID; } @@ -1256,7 +1220,7 @@ lasso_saml20_login_accept_sso(LassoLogin *login) ta = t->data; - if (strcmp(ta->ID, assertion->ID) == 0) { + if (g_strcmp0(ta->ID, assertion->ID) == 0) { g_list_free(previous_assertions); return LASSO_LOGIN_ERROR_ASSERTION_REPLAY; } @@ -1273,7 +1237,9 @@ lasso_saml20_login_accept_sso(LassoLogin *login) } /* create federation, only if nameidentifier format is Federated */ - if (ni && ni->Format && strcmp(ni->Format, LASSO_SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT) == 0) { + if (ni && ni->Format + && g_strcmp0(ni->Format, + LASSO_SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT) == 0) { federation = lasso_federation_new(LASSO_PROFILE(login)->remote_providerID); lasso_assign_gobject(federation->local_nameIdentifier, ni); @@ -1287,65 +1253,57 @@ lasso_saml20_login_accept_sso(LassoLogin *login) gint lasso_saml20_login_build_authn_response_msg(LassoLogin *login) { - LassoProfile *profile = LASSO_PROFILE(login); - LassoProvider *remote_provider; - LassoSaml2Assertion *assertion; + LassoProfile *profile; + LassoProvider *remote_provider = NULL; + LassoSaml2Assertion *assertion = NULL; + LassoHttpMethod http_method; + char *url = NULL; + int rc = 0; + + profile = &login->parent; if (login->protocolProfile != LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_POST && login->protocolProfile != LASSO_LOGIN_PROTOCOL_PROFILE_REDIRECT) { return critical_error(LASSO_PROFILE_ERROR_INVALID_PROTOCOLPROFILE); } - if (profile->server->certificate) { - LASSO_SAMLP2_STATUS_RESPONSE(profile->response)->sign_type = - LASSO_SIGNATURE_TYPE_WITHX509; + if (_lasso_login_must_sign_non_authn_request(login)) { + lasso_check_good_rc(lasso_profile_saml20_setup_message_signature(profile, + profile->response)); } else { - LASSO_SAMLP2_STATUS_RESPONSE(profile->response)->sign_type = - LASSO_SIGNATURE_TYPE_SIMPLE; + lasso_node_remove_signature(profile->response); } - LASSO_SAMLP2_STATUS_RESPONSE(profile->response)->sign_method = - LASSO_SIGNATURE_METHOD_RSA_SHA1; - - lasso_assign_string(LASSO_SAMLP2_STATUS_RESPONSE(profile->response)->private_key_file, - profile->server->private_key); - lasso_assign_string(LASSO_SAMLP2_STATUS_RESPONSE(profile->response)->certificate_file, - profile->server->certificate); remote_provider = lasso_server_get_provider(profile->server, profile->remote_providerID); if (LASSO_IS_PROVIDER(remote_provider) == FALSE) return critical_error(LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND); - lasso_assign_new_string(profile->msg_url, lasso_saml20_login_get_assertion_consumer_service_url( - login, remote_provider)); - if (profile->msg_url == NULL) { - return LASSO_PROFILE_ERROR_UNKNOWN_PROFILE_URL; - } + url = lasso_saml20_login_get_assertion_consumer_service_url(login, remote_provider); assertion = login->private_data->saml2_assertion; - if (LASSO_IS_SAML2_ASSERTION(assertion) == TRUE) { - assertion->Subject->SubjectConfirmation->SubjectConfirmationData->Recipient = - g_strdup(profile->msg_url); - } + if (LASSO_IS_SAML2_ASSERTION(assertion) && url) { + LassoSaml2SubjectConfirmationData *subject_confirmation_data; - - if (login->protocolProfile == LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_POST) { - /* build an lib:AuthnResponse base64 encoded */ - lasso_assign_new_string(profile->msg_body, lasso_node_export_to_base64(LASSO_NODE(profile->response))); - } else { - int rc; - char *acsUrl; - - acsUrl = profile->msg_url; - rc = lasso_saml20_profile_build_http_redirect(profile, profile->response, 1, acsUrl); - lasso_release_string(acsUrl); - if (rc != 0) { - return rc; - } + subject_confirmation_data = + lasso_saml2_assertion_get_subject_confirmation_data(assertion, TRUE); + lasso_assign_string(subject_confirmation_data->Recipient, url); } + switch (login->protocolProfile) { + case LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_POST: + http_method = LASSO_HTTP_METHOD_POST; + break; + case LASSO_LOGIN_PROTOCOL_PROFILE_REDIRECT: + http_method = LASSO_HTTP_METHOD_REDIRECT; + break; + default: + g_critical("Cannot happen"); + break; + } + lasso_check_good_rc(lasso_saml20_profile_build_request_msg(profile, NULL, http_method, url)); - return 0; - +cleanup: + return rc; } static char* @@ -1394,7 +1352,6 @@ lasso_saml20_login_init_idp_initiated_authn_request(LassoLogin *login, gchar *default_name_id_format = NULL; int rc = 0; - lasso_bad_param(LOGIN, login); profile = &login->parent; lasso_extract_node_or_fail(server, lasso_profile_get_server(profile), SERVER, LASSO_PROFILE_ERROR_MISSING_SERVER); @@ -1402,10 +1359,7 @@ lasso_saml20_login_init_idp_initiated_authn_request(LassoLogin *login, if (! LASSO_IS_PROVIDER(provider)) return LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND; - rc = lasso_login_init_authn_request(login, remote_providerID, LASSO_HTTP_METHOD_POST); - if (rc) - return rc; - + lasso_check_good_rc(lasso_login_init_authn_request(login, remote_providerID, LASSO_HTTP_METHOD_ANY)); lasso_release_string(LASSO_SAMLP2_REQUEST_ABSTRACT(profile->request)->ID); lasso_assign_string(LASSO_SAMLP2_REQUEST_ABSTRACT(profile->request)->Issuer->content, remote_providerID); diff --git a/lasso/saml-2.0/loginprivate.h b/lasso/saml-2.0/loginprivate.h index 0e3f9a7d..b17a4b99 100644 --- a/lasso/saml-2.0/loginprivate.h +++ b/lasso/saml-2.0/loginprivate.h @@ -32,7 +32,7 @@ extern "C" { #include "../id-ff/login.h" gint lasso_saml20_login_init_authn_request(LassoLogin *login, LassoHttpMethod http_method); -gint lasso_saml20_login_build_authn_request_msg(LassoLogin *login, LassoProvider *remote_provider); +gint lasso_saml20_login_build_authn_request_msg(LassoLogin *login); gint lasso_saml20_login_build_authn_response_msg(LassoLogin *login); gint lasso_saml20_login_process_authn_request_msg(LassoLogin *login, const char *authn_request_msg); gboolean lasso_saml20_login_must_authenticate(LassoLogin *login); diff --git a/lasso/saml-2.0/logout.c b/lasso/saml-2.0/logout.c index 386a1f3e..20717295 100644 --- a/lasso/saml-2.0/logout.c +++ b/lasso/saml-2.0/logout.c @@ -45,156 +45,90 @@ static void check_soap_support(gchar *key, LassoProvider *provider, LassoProfile *profile); +static char* +_lasso_saml2_assertion_get_session_index(LassoSaml2Assertion *assertion) +{ + if (! LASSO_IS_SAML2_AUTHN_STATEMENT(assertion->AuthnStatement->data)) + return NULL; + return((LassoSaml2AuthnStatement*)assertion->AuthnStatement->data)->SessionIndex; +} + int lasso_saml20_logout_init_request(LassoLogout *logout, LassoProvider *remote_provider, LassoHttpMethod http_method) { - LassoProfile *profile = LASSO_PROFILE(logout); - LassoNode *assertion_n; - LassoSaml2Assertion *assertion; - LassoSaml2NameID *name_id; - LassoSession *session; - LassoSamlp2RequestAbstract *request; - LassoSaml2EncryptedElement *encrypted_element = NULL; - char *assertion_SessionIndex = NULL; + LassoProfile *profile = &logout->parent; + LassoNode *assertion_n = NULL; + LassoSaml2Assertion *assertion = NULL; + //LassoSaml2NameID *name_id = NULL; + LassoSession *session = NULL; + //LassoSamlp2RequestAbstract *request = NULL; + //LassoSaml2EncryptedElement *encrypted_element = NULL; + LassoSamlp2LogoutRequest *logout_request = NULL; + //char *assertion_SessionIndex = NULL; + int rc = 0; + + logout_request = (LassoSamlp2LogoutRequest*) lasso_samlp2_logout_request_new(); + + lasso_check_good_rc(lasso_saml20_init_request(profile, + remote_provider->ProviderID, + FALSE, + &logout_request->parent, + http_method, + LASSO_MD_PROTOCOL_TYPE_SINGLE_LOGOUT)); /* session existence has been checked in id-ff/ */ session = lasso_profile_get_session(profile); - assertion_n = lasso_session_get_assertion(session, profile->remote_providerID); if (LASSO_IS_SAML2_ASSERTION(assertion_n) == FALSE) { return critical_error(LASSO_PROFILE_ERROR_MISSING_ASSERTION); } + lasso_ref(assertion_n); + assertion = (LassoSaml2Assertion*)assertion_n; - assertion = LASSO_SAML2_ASSERTION(assertion_n); - - if (assertion->Subject == NULL) { - return LASSO_PROFILE_ERROR_MISSING_SUBJECT; - } - - if (assertion->Subject->NameID == NULL) { - return LASSO_PROFILE_ERROR_MISSING_NAME_IDENTIFIER; - } - - name_id = assertion->Subject->NameID; - /* Just send back the NameID from the assertion. */ - lasso_assign_gobject(profile->nameIdentifier, name_id); - - if (http_method == LASSO_HTTP_METHOD_ANY) { - http_method = lasso_provider_get_first_http_method( - LASSO_PROVIDER(profile->server), - remote_provider, - LASSO_MD_PROTOCOL_TYPE_SINGLE_LOGOUT); - } else { - if (lasso_provider_accept_http_method(LASSO_PROVIDER(profile->server), - remote_provider, - LASSO_MD_PROTOCOL_TYPE_SINGLE_LOGOUT, - http_method, - TRUE) == FALSE) { - if (http_method == LASSO_HTTP_METHOD_REDIRECT) { - /* it was probably used as last resort, and - * failed, since the remote provider doesn't - * support any logout. remove assertion - * unconditionnaly. */ - lasso_session_remove_assertion(profile->session, - profile->remote_providerID); - if (logout->initial_remote_providerID && logout->initial_request) { - lasso_assign_string(profile->remote_providerID, - logout->initial_remote_providerID); - /* XXX: create response - profile->response = lasso_lib_logout_response_new_full( - LASSO_PROVIDER(profile->server)->ProviderID, - LASSO_SAML_STATUS_CODE_SUCCESS, - LASSO_LIB_LOGOUT_REQUEST(logout->initial_request), - LASSO_SIGNATURE_TYPE_NONE, - 0); - */ - } - } - return LASSO_PROFILE_ERROR_UNSUPPORTED_PROFILE; - } - } - - lasso_assign_new_gobject(profile->request, lasso_samlp2_logout_request_new()); - request = LASSO_SAMLP2_REQUEST_ABSTRACT(profile->request); - lasso_assign_new_string(request->ID, lasso_build_unique_id(32)); - lasso_assign_string(request->Version, "2.0"); - lasso_assign_new_gobject(request->Issuer, - LASSO_SAML2_NAME_ID(lasso_saml2_name_id_new_with_string( - LASSO_PROVIDER(profile->server)->ProviderID))); - lasso_assign_new_string(request->IssueInstant, lasso_get_current_time()); - - lasso_assign_gobject(LASSO_SAMLP2_LOGOUT_REQUEST(request)->NameID, profile->nameIdentifier); - - /* set the session index */ - if (assertion->AuthnStatement) { - if (! LASSO_IS_SAML2_AUTHN_STATEMENT(assertion->AuthnStatement->data)) { - - return LASSO_PROFILE_ERROR_BAD_SESSION_DUMP; - } - assertion_SessionIndex = - ((LassoSaml2AuthnStatement*)assertion->AuthnStatement->data)->SessionIndex; - if (assertion_SessionIndex) { - lasso_assign_string(LASSO_SAMLP2_LOGOUT_REQUEST(request)->SessionIndex, assertion_SessionIndex); - } - } + /* set the nameid */ + lasso_assign_gobject(logout_request->NameID, profile->nameIdentifier); + /* Encrypt NameID */ + rc = lasso_saml20_profile_setup_encrypted_node(remote_provider, (LassoNode**)&logout_request->NameID, + (LassoNode**)&logout_request->EncryptedID); + /* set the session index if one is found */ + lasso_assign_string(logout_request->SessionIndex, + _lasso_saml2_assertion_get_session_index(assertion)); + lasso_session_remove_assertion(profile->session, + profile->remote_providerID); +cleanup: + /* special case: we suppose REDIRECT is the last resort method, so we force assertion + * removal and create a possible response message with a second level status of PARTIAL. */ + if (rc == LASSO_PROFILE_ERROR_UNSUPPORTED_PROFILE + && http_method == LASSO_HTTP_METHOD_REDIRECT) { + lasso_session_remove_assertion(profile->session, + profile->remote_providerID); + if (logout->initial_remote_providerID && logout->initial_request) { + LassoSamlp2StatusResponse *response; - /* Encrypt NameID */ - if (remote_provider && - remote_provider->private_data->encryption_mode & LASSO_ENCRYPTION_MODE_NAMEID - && remote_provider->private_data->encryption_public_key != NULL) { - encrypted_element = LASSO_SAML2_ENCRYPTED_ELEMENT(lasso_node_encrypt( - LASSO_NODE(LASSO_SAMLP2_LOGOUT_REQUEST(request)->NameID), - remote_provider->private_data->encryption_public_key, - remote_provider->private_data->encryption_sym_key_type)); - if (encrypted_element != NULL) { - lasso_assign_new_gobject(LASSO_SAMLP2_LOGOUT_REQUEST(request)->EncryptedID, encrypted_element); - lasso_release_gobject(LASSO_SAMLP2_LOGOUT_REQUEST(request)->NameID) + logout->private_data->partial_logout = TRUE; + lasso_assign_string(profile->remote_providerID, + logout->initial_remote_providerID); + response = (LassoSamlp2StatusResponse*) lasso_samlp2_logout_response_new(); + /* ignore return code */ + lasso_saml20_profile_init_response(profile, response, LASSO_SAML2_STATUS_CODE_SUCCESS, + LASSO_SAML2_STATUS_CODE_PARTIAL_LOGOUT); + lasso_release_gobject(response); } } - - logout->initial_http_request_method = http_method; - - return 0; + lasso_release_gobject(logout_request); + lasso_release_gobject(assertion_n); + return rc; } - int -lasso_saml20_logout_build_request_msg(LassoLogout *logout, LassoProvider *remote_provider) +lasso_saml20_logout_build_request_msg(LassoLogout *logout) { - LassoProfile *profile = LASSO_PROFILE(logout); - - LASSO_SAMLP2_REQUEST_ABSTRACT(profile->request)->sign_method = - LASSO_SIGNATURE_METHOD_RSA_SHA1; - if (profile->server->certificate) { - LASSO_SAMLP2_REQUEST_ABSTRACT(profile->request)->sign_type = - LASSO_SIGNATURE_TYPE_WITHX509; - } else { - LASSO_SAMLP2_REQUEST_ABSTRACT(profile->request)->sign_type = - LASSO_SIGNATURE_TYPE_SIMPLE; - } - lasso_assign_string(LASSO_SAMLP2_REQUEST_ABSTRACT(profile->request)->private_key_file, - profile->server->private_key); - lasso_assign_string(LASSO_SAMLP2_REQUEST_ABSTRACT(profile->request)->certificate_file, - profile->server->certificate); - - if (logout->initial_http_request_method == LASSO_HTTP_METHOD_SOAP) { - lasso_assign_new_string(profile->msg_url, - lasso_provider_get_metadata_one(remote_provider, "SingleLogoutService SOAP")); - lasso_assign_string(LASSO_SAMLP2_REQUEST_ABSTRACT(profile->request)->Destination, - profile->msg_url); - lasso_assign_new_string(profile->msg_body, lasso_node_export_to_soap(profile->request)); - return 0; - } - if (logout->initial_http_request_method == LASSO_HTTP_METHOD_REDIRECT) { - return lasso_saml20_build_http_redirect_query_simple(profile, profile->request, - TRUE, "SingleLogoutService", FALSE); - } + LassoProfile *profile = &logout->parent; - /* XXX: artifact support */ - - return critical_error(LASSO_PROFILE_ERROR_INVALID_HTTP_METHOD); + return lasso_saml20_profile_build_request_msg(profile, "SingleLogoutService", + logout->parent.http_request_method, NULL); } int @@ -216,12 +150,13 @@ lasso_saml20_logout_process_request_msg(LassoLogout *logout, char *request_msg) if (rc1 && ! logout_request) { return rc1; } + /* remember initial request method, for setting it for generating response */ + logout->initial_http_request_method = profile->http_request_method; rc2 = lasso_saml20_profile_process_name_identifier_decryption(profile, &logout_request->NameID, &logout_request->EncryptedID); - lasso_release_gobject(logout_request); if (profile->signature_status) { return profile->signature_status; @@ -230,7 +165,6 @@ lasso_saml20_logout_process_request_msg(LassoLogout *logout, char *request_msg) return rc1; } return rc2; - } int @@ -244,41 +178,24 @@ lasso_saml20_logout_validate_request(LassoLogout *logout) LassoSaml2Assertion *assertion; LassoSamlp2LogoutRequest *logout_request; char *assertion_SessionIndex = NULL; + int rc = 0; if (LASSO_IS_SAMLP2_LOGOUT_REQUEST(profile->request) == FALSE) return LASSO_PROFILE_ERROR_MISSING_REQUEST; - logout_request = (LassoSamlp2LogoutRequest*)profile->request; + /* check the issuer */ lasso_assign_string(profile->remote_providerID, - LASSO_SAMLP2_REQUEST_ABSTRACT(profile->request)->Issuer->content); - - /* get the provider */ + logout_request->parent.Issuer->content); remote_provider = lasso_server_get_provider(profile->server, profile->remote_providerID); if (LASSO_IS_PROVIDER(remote_provider) == FALSE) { return critical_error(LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND); } - lasso_assign_new_gobject(profile->response, lasso_samlp2_logout_response_new()); - response = LASSO_SAMLP2_STATUS_RESPONSE(profile->response); - lasso_assign_new_string(response->ID, lasso_build_unique_id(32)); - lasso_assign_string(response->Version, "2.0"); - lasso_assign_new_gobject(response->Issuer, - LASSO_SAML2_NAME_ID(lasso_saml2_name_id_new_with_string( - LASSO_PROVIDER(profile->server)->ProviderID))); - lasso_assign_new_string(response->IssueInstant, lasso_get_current_time()); - lasso_assign_string(response->InResponseTo, - LASSO_SAMLP2_REQUEST_ABSTRACT(profile->request)->ID); - lasso_saml20_profile_set_response_status_success(profile, NULL); - - response->sign_method = LASSO_SIGNATURE_METHOD_RSA_SHA1; - if (profile->server->certificate) { - response->sign_type = LASSO_SIGNATURE_TYPE_WITHX509; - } else { - response->sign_type = LASSO_SIGNATURE_TYPE_SIMPLE; - } - response->private_key_file = g_strdup(profile->server->private_key); - response->certificate_file = g_strdup(profile->server->certificate); + /* create the response */ + response = (LassoSamlp2StatusResponse*)lasso_samlp2_logout_response_new(); + lasso_check_good_rc(lasso_saml20_profile_init_response(profile, response, + LASSO_SAML2_STATUS_CODE_SUCCESS, NULL)); /* verify signature status */ if (profile->signature_status != 0) { @@ -313,7 +230,8 @@ lasso_saml20_logout_validate_request(LassoLogout *logout) /* Verify name identifier and session matching */ if (assertion->Subject == NULL) { lasso_saml20_profile_set_response_status(profile, - LASSO_SAML2_STATUS_CODE_RESPONDER, "http://lasso.entrouvert.org/error/MalformedAssertion"); + LASSO_SAML2_STATUS_CODE_RESPONDER, + "http://lasso.entrouvert.org/error/MalformedAssertion"); return LASSO_PROFILE_ERROR_MISSING_SUBJECT; } @@ -335,7 +253,7 @@ lasso_saml20_logout_validate_request(LassoLogout *logout) ((LassoSaml2AuthnStatement*)assertion->AuthnStatement->data)->SessionIndex; if (g_strcmp0(logout_request->SessionIndex, assertion_SessionIndex) != 0) { lasso_saml20_profile_set_response_status_responder(profile, - LASSO_SAML2_STATUS_CODE_UNKNOWN_PRINCIPAL); + LASSO_SAML2_STATUS_CODE_REQUEST_DENIED); return LASSO_LOGOUT_ERROR_UNKNOWN_PRINCIPAL; } } @@ -371,9 +289,9 @@ lasso_saml20_logout_validate_request(LassoLogout *logout) lasso_transfer_gobject(logout->initial_response, profile->response); } - return 0; - - +cleanup: + lasso_release_gobject(response); + return rc; } static void @@ -407,93 +325,41 @@ lasso_saml20_logout_build_response_msg(LassoLogout *logout) { LassoProfile *profile = LASSO_PROFILE(logout); LassoSamlp2StatusResponse *response; + int rc = 0; if (profile->response == NULL) { /* no response set here means request denied */ - lasso_assign_new_gobject(profile->response, lasso_samlp2_logout_response_new()); - response = LASSO_SAMLP2_STATUS_RESPONSE(profile->response); - lasso_assign_new_string(response->ID, lasso_build_unique_id(32)); - lasso_assign_string(response->Version, "2.0"); - lasso_assign_new_gobject(response->Issuer, LASSO_SAML2_NAME_ID(lasso_saml2_name_id_new_with_string( - LASSO_PROVIDER(profile->server)->ProviderID))); - lasso_assign_new_string(response->IssueInstant, lasso_get_current_time()); - if (profile->request) { - lasso_assign_string(response->InResponseTo, - LASSO_SAMLP2_REQUEST_ABSTRACT(profile->request)->ID); - } - lasso_saml20_profile_set_response_status_responder(profile, - LASSO_SAML2_STATUS_CODE_REQUEST_DENIED); - - response->sign_method = LASSO_SIGNATURE_METHOD_RSA_SHA1; - if (profile->server->certificate) { - response->sign_type = LASSO_SIGNATURE_TYPE_WITHX509; - } else { - response->sign_type = LASSO_SIGNATURE_TYPE_SIMPLE; - } - lasso_assign_string(response->private_key_file, profile->server->private_key); - lasso_assign_string(response->certificate_file, profile->server->certificate); + response = (LassoSamlp2StatusResponse*) lasso_samlp2_logout_response_new(); + lasso_check_good_rc(lasso_saml20_profile_init_response(profile, response, + LASSO_SAML2_STATUS_CODE_RESPONDER, + LASSO_SAML2_STATUS_CODE_REQUEST_DENIED)); } /* build logout response message */ - if (profile->http_request_method == LASSO_HTTP_METHOD_SOAP) { - lasso_release_string(profile->msg_url); - lasso_assign_new_string(profile->msg_body, lasso_node_export_to_soap(profile->response)); - return 0; - } + /* FIXME: should allow to override default response method, should just match that + * request/response are of the same type synchronous or asynchronous */ + rc = lasso_saml20_profile_build_response_msg(profile, "SingleLogoutService", + logout->initial_http_request_method, NULL); - if (profile->http_request_method == LASSO_HTTP_METHOD_REDIRECT) { - return lasso_saml20_build_http_redirect_query_simple(profile, profile->response, TRUE, "SingleLogoutService", TRUE); - } - - return LASSO_PROFILE_ERROR_MISSING_REQUEST; +cleanup: + lasso_release_gobject(response); + return rc; } int lasso_saml20_logout_process_response_msg(LassoLogout *logout, const char *response_msg) { - LassoProfile *profile = LASSO_PROFILE(logout); + LassoProfile *profile = &logout->parent; LassoHttpMethod response_method; LassoProvider *remote_provider = NULL; LassoSamlp2StatusResponse *response = NULL; - LassoMessageFormat format; char *status_code_value = NULL; - int rc; - - lasso_assign_new_gobject(profile->response, lasso_samlp2_logout_response_new()); - format = lasso_node_init_from_message(LASSO_NODE(profile->response), response_msg); - - switch (format) { - case LASSO_MESSAGE_FORMAT_SOAP: - response_method = LASSO_HTTP_METHOD_SOAP; - break; - case LASSO_MESSAGE_FORMAT_QUERY: - response_method = LASSO_HTTP_METHOD_REDIRECT; - break; - default: - return critical_error(LASSO_PROFILE_ERROR_INVALID_MSG); - } + int rc = 0; - lasso_assign_string(profile->remote_providerID, - LASSO_SAMLP2_STATUS_RESPONSE(profile->response)->Issuer->content); - - /* get the provider */ - remote_provider = lasso_server_get_provider(profile->server, profile->remote_providerID); - if (LASSO_IS_PROVIDER(remote_provider) == FALSE) { - return critical_error(LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND); - } - - /* verify signature */ - rc = lasso_provider_verify_signature(remote_provider, response_msg, "ID", format); - - response = LASSO_SAMLP2_STATUS_RESPONSE(profile->response); - - if (response->Status == NULL || response->Status->StatusCode == NULL - || response->Status->StatusCode->Value == NULL) { - rc = LASSO_PROFILE_ERROR_MISSING_STATUS_CODE; - } else { - status_code_value = response->Status->StatusCode->Value; - } + response = (LassoSamlp2StatusResponse*)profile->response; + lasso_check_good_rc(lasso_saml20_profile_process_any_response(profile, response, &response_method, response_msg)); + status_code_value = response->Status->StatusCode->Value; if (status_code_value && strcmp(status_code_value, LASSO_SAML2_STATUS_CODE_SUCCESS) != 0) { /* If at SP, if the request method was a SOAP type, then * rebuild the request message with HTTP method */ @@ -507,6 +373,7 @@ lasso_saml20_logout_process_response_msg(LassoLogout *logout, const char *respon } if (status_code_value == NULL) { rc = LASSO_PROFILE_ERROR_MISSING_STATUS_CODE; + goto cleanup; } } if (strcmp(status_code_value, LASSO_SAML2_STATUS_CODE_REQUEST_DENIED) == 0) { @@ -515,15 +382,16 @@ lasso_saml20_logout_process_response_msg(LassoLogout *logout, const char *respon lasso_session_remove_assertion( profile->session, profile->remote_providerID); rc = LASSO_LOGOUT_ERROR_REQUEST_DENIED; + goto cleanup; } if (strcmp(status_code_value, LASSO_SAML2_STATUS_CODE_UNKNOWN_PRINCIPAL) == 0) { rc = LASSO_LOGOUT_ERROR_UNKNOWN_PRINCIPAL; + goto cleanup; } rc = LASSO_PROFILE_ERROR_STATUS_NOT_SUCCESS; + goto cleanup; } - /* LogoutResponse status code value is ok */ - /* XXX: handle RelayState if necessary */ /* if SOAP method or, if IDP provider type and HTTP Redirect, * then remove assertion */ @@ -543,7 +411,7 @@ lasso_saml20_logout_process_response_msg(LassoLogout *logout, const char *respon if (logout->initial_remote_providerID && lasso_session_count_assertions(profile->session) == 0) { remote_provider = lasso_server_get_provider(profile->server, profile->remote_providerID); - if (remote_provider->role == LASSO_PROVIDER_ROLE_SP) { + if (remote_provider->role & LASSO_PROVIDER_ROLE_SP) { lasso_transfer_string(profile->remote_providerID, logout->initial_remote_providerID); lasso_transfer_gobject(profile->request, logout->initial_request); @@ -565,6 +433,8 @@ lasso_saml20_logout_process_response_msg(LassoLogout *logout, const char *respon lasso_session_remove_assertion(profile->session, profile->remote_providerID); } +cleanup: + lasso_release_gobject(response); return rc; } diff --git a/lasso/saml-2.0/logoutprivate.h b/lasso/saml-2.0/logoutprivate.h index b3452abb..ae10d918 100644 --- a/lasso/saml-2.0/logoutprivate.h +++ b/lasso/saml-2.0/logoutprivate.h @@ -34,7 +34,7 @@ extern "C" { int lasso_saml20_logout_init_request(LassoLogout *logout, LassoProvider *remote_provider, LassoHttpMethod http_method); -int lasso_saml20_logout_build_request_msg(LassoLogout *logout, LassoProvider *remote_provider); +int lasso_saml20_logout_build_request_msg(LassoLogout *logout); int lasso_saml20_logout_process_request_msg(LassoLogout *logout, char *request_msg); diff --git a/lasso/saml-2.0/name_id_management.c b/lasso/saml-2.0/name_id_management.c index 99c12e18..c9a43d73 100644 --- a/lasso/saml-2.0/name_id_management.c +++ b/lasso/saml-2.0/name_id_management.c @@ -53,7 +53,10 @@ * @http_method: if set, then it get the protocol profile in metadata * corresponding of this HTTP request method. * - * Initializes a new Name Id Management Request. + * Initializes a new Name Id Management Request. If @new_name_id is NULL, it is a Termination + * request, if not and we are an IdP is a NameID change request, if we are a SP, it is a request to + * add a SP provided Id to the NameID of the IdP. It can be useful if the SP do not want to store + * the federation, instead he can export its own identifiers to the IdP. * * Return value: 0 on success; or a negative value otherwise. **/ @@ -73,10 +76,8 @@ lasso_name_id_management_init_request(LassoNameIdManagement *name_id_management, request = (LassoSamlp2RequestAbstract*)lasso_samlp2_manage_name_id_request_new(); manage_name_id_request = LASSO_SAMLP2_MANAGE_NAME_ID_REQUEST(request); - rc = lasso_saml20_init_request(profile, remote_provider_id, TRUE, request, http_method, - LASSO_MD_PROTOCOL_TYPE_MANAGE_NAME_ID); - if (rc) - goto cleanup; + lasso_check_good_rc(lasso_saml20_init_request(profile, remote_provider_id, TRUE, request, + http_method, LASSO_MD_PROTOCOL_TYPE_MANAGE_NAME_ID)); lasso_assign_gobject(manage_name_id_request->NameID, (LassoSaml2NameID*)profile->nameIdentifier); if (new_name_id) { @@ -84,6 +85,11 @@ lasso_name_id_management_init_request(LassoNameIdManagement *name_id_management, } else { lasso_assign_new_gobject(manage_name_id_request->Terminate, LASSO_SAMLP2_TERMINATE(lasso_samlp2_terminate_new())); + /* if we are the IdP we can apply termination immediately. */ + if (profile->server->parent.role & LASSO_PROVIDER_ROLE_IDP) { + lasso_identity_remove_federation(profile->identity, + profile->remote_providerID); + } } cleanup: @@ -106,7 +112,7 @@ lasso_name_id_management_build_request_msg(LassoNameIdManagement *name_id_manage { lasso_bad_param(NAME_ID_MANAGEMENT, name_id_management); - return lasso_saml20_profile_build_request_msg(&name_id_management->parent, "ManageNameIDService", FALSE); + return lasso_saml20_profile_build_request_msg(&name_id_management->parent, "ManageNameIDService", name_id_management->parent.http_request_method, NULL); } @@ -267,21 +273,21 @@ int lasso_name_id_management_build_response_msg(LassoNameIdManagement *name_id_management) { LassoProfile *profile = NULL; - gint rc = 0; + LassoSamlp2StatusResponse *response; lasso_bad_param(NAME_ID_MANAGEMENT, name_id_management); profile = &name_id_management->parent; /* no response set here means request denied */ - if (! profile->response) { - profile->response = lasso_samlp2_manage_name_id_response_new(); - lasso_saml20_profile_init_response(profile, LASSO_SAML2_STATUS_CODE_RESPONDER, + if (! LASSO_IS_SAMLP2_STATUS_RESPONSE(profile->response)) { + response = (LassoSamlp2StatusResponse*)lasso_samlp2_manage_name_id_response_new(); + lasso_saml20_profile_init_response(profile, response, LASSO_SAML2_STATUS_CODE_RESPONDER, LASSO_SAML2_STATUS_CODE_REQUEST_DENIED); + lasso_release_gobject(response); } - rc = lasso_saml20_profile_build_response(profile, "ManageNameIDService", FALSE, profile->http_request_method); - - return rc; + /* use the same binding as for the request */ + return lasso_saml20_profile_build_response_msg(profile, "ManageNameIDService", profile->http_request_method, NULL); } @@ -308,11 +314,9 @@ lasso_name_id_management_process_response_msg( lasso_bad_param(NAME_ID_MANAGEMENT, name_id_management); lasso_null_param(response_msg); - profile = (LassoProfile*)name_id_management; + profile = &name_id_management->parent; response = (LassoSamlp2StatusResponse*)lasso_samlp2_manage_name_id_response_new(); - rc = lasso_saml20_profile_process_any_response(profile, response, response_msg); - if (rc) - goto cleanup; + lasso_check_good_rc(lasso_saml20_profile_process_any_response(profile, response, NULL, response_msg)); /* Stop here if signature validation failed. */ goto_cleanup_if_fail_with_rc(profile->signature_status == 0, profile->signature_status); diff --git a/lasso/saml-2.0/profile.c b/lasso/saml-2.0/profile.c index 0b10edb0..a2aef281 100644 --- a/lasso/saml-2.0/profile.c +++ b/lasso/saml-2.0/profile.c @@ -26,15 +26,17 @@ #include <xmlsec/base64.h> #include "../utils.h" -#include "providerprivate.h" -#include "profileprivate.h" -#include "profile.h" +#include "./providerprivate.h" +#include "./profileprivate.h" +#include "./profile.h" +#include "./provider.h" #include "../id-ff/providerprivate.h" #include "../id-ff/profile.h" #include "../id-ff/profileprivate.h" #include "../id-ff/serverprivate.h" -#include <../id-ff/sessionprivate.h> +#include "../id-ff/sessionprivate.h" +#include "../id-ff/login.h" #include "../xml/private.h" #include "../xml/saml-2.0/samlp2_request_abstract.h" @@ -48,16 +50,23 @@ #include "../debug.h" static char* lasso_saml20_profile_build_artifact(LassoProvider *provider); -static int lasso_saml20_profile_export_to_query(LassoProfile *profile, LassoNode *msg, int sign, char **query); +static int lasso_saml20_profile_export_to_query(LassoProfile *profile, LassoNode *msg, char **query, + LassoSignatureMethod method, const char *private_key); static gint lasso_profile_saml20_build_artifact_get_request_msg(LassoProfile *profile, - LassoProvider *provider, const char *service); + const char *service); static gint lasso_profile_saml20_build_artifact_post_request_msg(LassoProfile *profile, - LassoProvider *provider, const char *service); + const char *service); static gint lasso_profile_saml20_build_artifact_get_response_msg(LassoProfile *profile, - LassoProvider *provider, const char *service); + const char *service); static gint lasso_profile_saml20_build_artifact_post_response_msg(LassoProfile *profile, - LassoProvider *provider, const char *service); -static gboolean has_signature(LassoNode *node); + const char *service); +static gboolean has_signature(LassoNode *node, LassoSignatureMethod *signature_method, const char + **private_key_file); + +#define check_msg_body \ + if (! profile->msg_body) { \ + return critical_error(LASSO_PROFILE_ERROR_BUILDING_MESSAGE_FAILED); \ + } /* * Helper functions @@ -84,7 +93,7 @@ cleanup: } static char * -get_url(LassoProvider *provider, char *service, char *binding) +get_url(LassoProvider *provider, const char *service, const char *binding) { char *meta; char *result; @@ -96,7 +105,7 @@ get_url(LassoProvider *provider, char *service, char *binding) } static char * -get_response_url(LassoProvider *provider, char *service, char *binding) +get_response_url(LassoProvider *provider, const char *service, const char *binding) { char *meta; char *result; @@ -110,6 +119,28 @@ get_response_url(LassoProvider *provider, char *service, char *binding) return result; } +static const char* +http_method_to_binding(LassoHttpMethod method) { + switch (method) { + case LASSO_HTTP_METHOD_POST: + return "HTTP-POST"; + case LASSO_HTTP_METHOD_REDIRECT: + return "HTTP-Redirect"; + case LASSO_HTTP_METHOD_SOAP: + return "SOAP"; + case LASSO_HTTP_METHOD_ARTIFACT_GET: + case LASSO_HTTP_METHOD_ARTIFACT_POST: + return "HTTP-Artifact"; + case LASSO_HTTP_METHOD_PAOS: + return "PAOS"; + default: + return ""; + } +} + +/* + * Artifact Handling functions + */ /** * lasso_saml20_profile_generate_artifact @@ -125,11 +156,13 @@ char* lasso_saml20_profile_generate_artifact(LassoProfile *profile, int part) { lasso_assign_new_string(profile->private_data->artifact, - lasso_saml20_profile_build_artifact(LASSO_PROVIDER(profile->server))); + lasso_saml20_profile_build_artifact(&profile->server->parent)); if (part == 0) { - lasso_assign_new_string(profile->private_data->artifact_message, lasso_node_dump(profile->request)); + lasso_assign_new_string(profile->private_data->artifact_message, + lasso_node_dump(profile->request)); } else if (part == 1) { - lasso_assign_new_string(profile->private_data->artifact_message, lasso_node_dump(profile->response)); + lasso_assign_new_string(profile->private_data->artifact_message, + lasso_node_dump(profile->response)); } else { /* XXX: RequestDenied here? */ } @@ -162,44 +195,71 @@ lasso_saml20_profile_build_artifact(LassoProvider *provider) return ret; } -int -lasso_saml20_profile_set_response_status(LassoProfile *profile, - const char *code1, const char *code2) +/* + * this function factorize all case for producing SAML artifact messages + */ +static gint +lasso_profile_saml20_build_artifact_msg(LassoProfile *profile, + const char *url, int request_or_response, int get_or_post) { - 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); + char *artifact = lasso_saml20_profile_generate_artifact(profile, request_or_response); - if (! LASSO_IS_SAMLP2_STATUS(status_response->Status)) { - lasso_assign_new_gobject(status_response->Status, - (LassoSamlp2Status*)lasso_samlp2_status_new()); + if (artifact == NULL) { + return critical_error(LASSO_PROFILE_ERROR_BUILDING_QUERY_FAILED); } - status = status_response->Status; - if (! LASSO_IS_SAMLP2_STATUS_CODE(status->StatusCode)) { - lasso_assign_new_gobject(status->StatusCode, - (LassoSamlp2StatusCode*)lasso_samlp2_status_code_new()); + /* hack... */ + if (LASSO_IS_LOGIN(profile)) { + LassoLogin *login = (LassoLogin*)profile; + lasso_assign_string(login->assertionArtifact, artifact); } - 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()); + if (get_or_post == 0) { + char *query; + if (profile->msg_relayState) { + query = lasso_url_add_parameters(NULL, 0, "SAMLart", artifact, "RelayState", + profile->msg_relayState, NULL); + } else { + query = lasso_url_add_parameters(NULL, 0, "SAMLart", artifact, NULL); } - status_code2 = status_code1->StatusCode; - lasso_assign_string(status_code2->Value, code2); + lasso_assign_new_string(profile->msg_url, + lasso_concat_url_query(url, query)); + lasso_release_string(query); + } else { + lasso_assign_string(profile->msg_url, url); + lasso_assign_string(profile->msg_body, artifact); } + return 0; +} -cleanup: - return rc; +enum { + REQUEST = 0, + RESPONSE = 1, + GET = 0, + POST = 1 +}; + +static gint +lasso_profile_saml20_build_artifact_get_request_msg(LassoProfile *profile, const char *url) +{ + return lasso_profile_saml20_build_artifact_msg(profile, url, REQUEST, GET); +} + +static gint +lasso_profile_saml20_build_artifact_post_request_msg(LassoProfile *profile, const char *url) +{ + return lasso_profile_saml20_build_artifact_msg(profile, url, REQUEST, POST); +} + +static gint +lasso_profile_saml20_build_artifact_get_response_msg(LassoProfile *profile, const char *url) +{ + return lasso_profile_saml20_build_artifact_msg(profile, url, RESPONSE, GET); +} + +static gint +lasso_profile_saml20_build_artifact_post_response_msg(LassoProfile *profile, const char *url) +{ + return lasso_profile_saml20_build_artifact_msg(profile, url, RESPONSE, POST); } int @@ -337,26 +397,24 @@ cleanup: int lasso_saml20_profile_process_artifact_response(LassoProfile *profile, const char *msg) { - LassoNode *response; LassoSamlp2ArtifactResponse *artifact_response; + int rc = 0; - /* XXX: handle errors properly */ - - response = lasso_node_new_from_soap(msg); - if (!LASSO_IS_SAMLP2_ARTIFACT_RESPONSE(response)) { - lasso_assign_new_gobject(profile->response, lasso_samlp2_response_new()); - return LASSO_PROFILE_ERROR_INVALID_ARTIFACT; - } - artifact_response = LASSO_SAMLP2_ARTIFACT_RESPONSE(response); - + artifact_response = (LassoSamlp2ArtifactResponse*)lasso_samlp2_artifact_response_new(); + lasso_check_good_rc(lasso_saml20_profile_process_any_response(profile, + &artifact_response->parent, NULL, msg)); + /* XXX: check signature status */ + goto_cleanup_if_fail_with_rc(profile->response != NULL, + critical_error(LASSO_PROFILE_ERROR_INVALID_RESPONSE)); if (artifact_response->any == NULL) { - lasso_assign_new_gobject(profile->response, lasso_samlp2_response_new()); - return LASSO_PROFILE_ERROR_MISSING_RESPONSE; + lasso_release_gobject(profile->response); + goto_cleanup_with_rc(LASSO_PROFILE_ERROR_INVALID_ARTIFACT); } lasso_assign_gobject(profile->response, artifact_response->any); - lasso_release_gobject(response); - return 0; +cleanup: + lasso_release_gobject(artifact_response); + return rc; } /** @@ -384,7 +442,6 @@ lasso_profile_is_saml_query(const gchar *query) return FALSE; } - static void lasso_saml20_profile_set_session_from_dump_decrypt( LassoSaml2Assertion *assertion, G_GNUC_UNUSED gpointer data) @@ -423,7 +480,8 @@ lasso_saml20_profile_set_session_from_dump(LassoProfile *profile) * 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 + * @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 @@ -473,6 +531,10 @@ cleanup: return rc; } +/* + * Request handling functions + */ + /** * lasso_saml20_profile_process_any_request: * @profile: a #LassoProfile object @@ -493,7 +555,7 @@ cleanup: int lasso_saml20_profile_process_any_request(LassoProfile *profile, LassoNode *request_node, - char *request_msg) + const char *request_msg) { int rc = 0; LassoSaml2NameID *name_id = NULL; @@ -562,7 +624,7 @@ cleanup: int lasso_saml20_profile_process_soap_request(LassoProfile *profile, - char *request_msg) + const char *request_msg) { int rc = 0; LassoSaml2NameID *issuer = NULL; @@ -592,7 +654,7 @@ cleanup: int lasso_saml20_init_request(LassoProfile *profile, - char *remote_provider_id, + const char *remote_provider_id, gboolean first_in_session, LassoSamlp2RequestAbstract *request_abstract, LassoHttpMethod http_method, @@ -677,154 +739,184 @@ lasso_saml20_init_request(LassoProfile *profile, lasso_assign_new_string(request_abstract->IssueInstant, lasso_get_current_time()); lasso_assign_gobject(profile->request, LASSO_NODE(request_abstract)); + /* set signature */ + lasso_check_good_rc(lasso_profile_saml20_setup_message_signature(profile, profile->request)); + cleanup: return rc; } static int -lasso_saml20_profile_build_post_request_msg(LassoProfile *profile, - LassoProvider *provider, char *service) +lasso_saml20_profile_build_redirect_request_msg(LassoProfile *profile, const char *url) { - 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); + return lasso_saml20_profile_build_http_redirect(profile, + profile->request, + url); +} - 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); - } +static int +lasso_saml20_profile_build_post_request_msg(LassoProfile *profile, + const char *url) +{ + lasso_assign_string(profile->msg_url, 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; + lasso_node_export_to_base64(profile->request)); + check_msg_body; + return 0; } static int -lasso_saml20_profile_build_soap_request_msg(LassoProfile *profile, LassoProvider *provider, - char *service) +lasso_saml20_profile_build_soap_request_msg(LassoProfile *profile, const char *url) { - 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_string(profile->msg_url, url); 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; + lasso_node_export_to_soap(profile->request)); + check_msg_body; + return 0; } +/** + * the url parameters is special for this function, it does not give the destination of the message + * (it's implicit for the caller of this function) but where response should be posted later) */ static int -lasso_saml20_profile_build_redirect_request_msg(LassoProfile *profile, LassoProvider *provider, - char *service) +lasso_profile_saml20_build_paos_request_msg(LassoProfile *profile, const char *url) { - int rc = 0; - char *url = NULL; - - url = get_url(provider, service, "HTTP-Redirect"); - rc = lasso_saml20_profile_build_http_redirect(profile, - profile->request, - url); - -cleanup: - lasso_release_string(url); - return rc; - + lasso_assign_new_string(profile->msg_body, + lasso_node_export_to_paos_request(profile->request, + profile->server->parent.ProviderID, url, + profile->msg_relayState)); + check_msg_body; + return 0; } int -lasso_saml20_profile_build_request_msg(LassoProfile *profile, char *service) +lasso_saml20_profile_build_request_msg(LassoProfile *profile, const char *service, + LassoHttpMethod method, const char *_url) { LassoProvider *provider; + char *made_url = NULL, *url; int rc = 0; lasso_bad_param(PROFILE, profile); lasso_profile_clean_msg_info(profile); lasso_check_good_rc(get_provider(profile, &provider)); + url = (char*)_url; + + /* check presence of a request */ + if (! LASSO_IS_SAMLP2_REQUEST_ABSTRACT(profile->request)) { + return critical_error(LASSO_PROFILE_ERROR_MISSING_REQUEST); + } - switch (profile->http_request_method) { + /* if not explicitely given, automatically determine an URI from the metadatas */ + if (url == NULL) { + made_url = url = get_url(provider, service, http_method_to_binding(method)); + } + + switch (method) { case LASSO_HTTP_METHOD_SOAP: - rc = lasso_saml20_profile_build_soap_request_msg(profile, provider, - service); + rc = lasso_saml20_profile_build_soap_request_msg(profile, url); break; case LASSO_HTTP_METHOD_POST: - rc = lasso_saml20_profile_build_post_request_msg(profile, provider, - service); + rc = lasso_saml20_profile_build_post_request_msg(profile, url); break; case LASSO_HTTP_METHOD_REDIRECT: - rc = lasso_saml20_profile_build_redirect_request_msg(profile, provider, - service); + rc = lasso_saml20_profile_build_redirect_request_msg(profile, url); break; case LASSO_HTTP_METHOD_ARTIFACT_GET: - rc = lasso_profile_saml20_build_artifact_get_request_msg(profile, provider, - service); + rc = lasso_profile_saml20_build_artifact_get_request_msg(profile, url); break; - case LASSO_HTTP_METHOD_ARTIFACT_GET: - rc = lasso_profile_saml20_build_artifact_post_request_msg(profile, provider, - service); + case LASSO_HTTP_METHOD_ARTIFACT_POST: + rc = lasso_profile_saml20_build_artifact_post_request_msg(profile, url); break; + case LASSO_HTTP_METHOD_PAOS: + rc = lasso_profile_saml20_build_paos_request_msg(profile, url); default: rc = LASSO_PROFILE_ERROR_INVALID_HTTP_METHOD; break; } cleanup: + lasso_release_string(made_url); return rc; } +/* + * Response handling functions + */ + int -lasso_saml20_profile_init_response(LassoProfile *profile, const char *status_code1, const char *status_code2) +lasso_saml20_profile_set_response_status(LassoProfile *profile, + const char *code1, const char *code2) { LassoSamlp2StatusResponse *status_response = NULL; - LassoSamlp2RequestAbstract *request_abstract = NULL; - LassoServer *server = 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); - 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); + + 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); + } + +cleanup: + return rc; +} + + +int +lasso_saml20_profile_init_response(LassoProfile *profile, LassoSamlp2StatusResponse *status_response, + const char *status_code1, const char *status_code2) +{ + LassoSamlp2RequestAbstract *request_abstract = NULL; + int rc = 0; + + lasso_bad_param(PROFILE, profile); + if (! LASSO_IS_SAMLP2_STATUS_RESPONSE(status_response)) + return LASSO_PROFILE_ERROR_MISSING_RESPONSE; + lasso_assign_gobject(profile->response, status_response); 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))); + if (LASSO_IS_SERVER(profile->server)) { + lasso_assign_new_gobject(status_response->Issuer, + LASSO_SAML2_NAME_ID(lasso_saml2_name_id_new_with_string( + profile->server->parent.ProviderID))); + } lasso_assign_new_string(status_response->IssueInstant, lasso_get_current_time()); - lasso_assign_string(status_response->InResponseTo, request_abstract->ID); + if (LASSO_IS_SAMLP2_REQUEST_ABSTRACT(profile->request)) { + lasso_assign_string(status_response->InResponseTo, + ((LassoSamlp2RequestAbstract*)request_abstract)->ID); + } lasso_check_good_rc(lasso_profile_saml20_setup_message_signature(profile, profile->response)); - if (status_code1) + if (status_code1) { lasso_saml20_profile_set_response_status(profile, status_code1, status_code2); + } cleanup: return rc; @@ -860,8 +952,8 @@ lasso_saml20_profile_validate_request(LassoProfile *profile, gboolean needs_iden goto cleanup; /* init the response */ - lasso_assign_gobject(profile->response, &status_response->parent); - lasso_saml20_profile_init_response(profile, LASSO_SAML2_STATUS_CODE_SUCCESS, NULL); + lasso_saml20_profile_init_response(profile, status_response, + LASSO_SAML2_STATUS_CODE_SUCCESS, NULL); if (profile->signature_status) { message(G_LOG_LEVEL_WARNING, "Request signature is invalid"); @@ -878,59 +970,6 @@ cleanup: } -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) -{ - LassoSamlp2StatusResponse *status_response = NULL; - char *url = NULL; - int rc = 0; - - lasso_null_param(service); - - url = get_response_url(provider, service, "HTTP-Redirect"); - rc = lasso_saml20_profile_build_http_redirect(profile, - profile->response, - lasso_flag_add_signature, - url); - -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; -} - /** * lasso_saml20_profile_export_to_query: * @profile: a #LassoProfile @@ -938,41 +977,35 @@ lasso_saml20_profile_build_soap_response(LassoProfile *profile) * @sign: TRUE if query must signed, FALSE otherwise * * Create a query following the DEFLATE encoding of the SAML 2.0 HTTP - * Redirect binding. + * Redirect binding. If the root message node has an XML signature, signature is removed and query + * is signed. * - * Return value: a newly allocated string containing the query string if successfull, NULL otherwise. + * Return value: a newly allocated string containing the query string if successfull, NULL + * otherwise. */ static int -lasso_saml20_profile_export_to_query(LassoProfile *profile, LassoNode *msg, int sign, char **query) { +lasso_saml20_profile_export_to_query(LassoProfile *profile, LassoNode *msg, char **query, + LassoSignatureMethod signature_method, const char *private_key_file) { char *unsigned_query = NULL; char *result = NULL; int rc = 0; - lasso_bad_param(PROFILE, profile); - lasso_bad_param(NODE, msg); - unsigned_query = lasso_node_build_query(msg); goto_cleanup_if_fail_with_rc(unsigned_query != NULL, LASSO_PROFILE_ERROR_BUILDING_QUERY_FAILED); if (profile->msg_relayState) { - unsigned_query = lasso_url_add_parameters(unsigned_query, 1, "RelayState", profile->msg_relayState, NULL); + unsigned_query = lasso_url_add_parameters(unsigned_query, 1, "RelayState", + profile->msg_relayState, NULL); if (strlen(profile->msg_relayState) > 80) { - g_warning("Encoded a RelayState of more than 80 bytes, see #3.4.3 of" - " saml-bindings-2.0-os"); + message(G_LOG_LEVEL_WARNING, "Encoded a RelayState of more than 80 bytes, " + "see #3.4.3 of saml-bindings-2.0-os"); } } - if (sign && lasso_flag_add_signature) { - LassoServer *server = profile->server; - goto_cleanup_if_fail_with_rc (LASSO_IS_SERVER(server), - LASSO_PROFILE_ERROR_MISSING_SERVER); - goto_cleanup_if_fail_with_rc ( - profile->server->signature_method != LASSO_SIGNATURE_TYPE_NONE && - profile->server->private_key, - LASSO_DS_ERROR_PRIVATE_KEY_LOAD_FAILED); - result = lasso_query_sign(unsigned_query, profile->server->signature_method, - profile->server->private_key); - goto_cleanup_if_fail_with_rc(result != NULL, LASSO_PROFILE_ERROR_BUILDING_QUERY_FAILED); + if (signature_method && private_key_file && lasso_flag_add_signature) { + result = lasso_query_sign(unsigned_query, signature_method, private_key_file); + goto_cleanup_if_fail_with_rc(result != NULL, + LASSO_PROFILE_ERROR_BUILDING_QUERY_FAILED); lasso_transfer_string(*query, result); } else { lasso_transfer_string(*query, unsigned_query); @@ -983,37 +1016,24 @@ cleanup: return rc; } -static void -remove_signature(LassoNode *node) { - LassoNodeClass *klass; - - if (node == NULL) - return; - - klass = LASSO_NODE_GET_CLASS(node); - /* follow the class parenting chain */ - while (klass && LASSO_IS_NODE_CLASS(klass)) { - if (klass && klass->node_data && klass->node_data->sign_type_offset != 0) { - G_STRUCT_MEMBER(LassoSignatureType, node, klass->node_data->sign_type_offset) = - LASSO_SIGNATURE_TYPE_NONE; - } - klass = g_type_class_peek_parent(klass); - } -} - static gboolean -has_signature(LassoNode *node) { +has_signature(LassoNode *node, LassoSignatureMethod *method, const char **private_key_file) { LassoNodeClass *klass; if (node == NULL) - return; + return FALSE; klass = LASSO_NODE_GET_CLASS(node); /* follow the class parenting chain */ while (klass && LASSO_IS_NODE_CLASS(klass)) { if (klass && klass->node_data && klass->node_data->sign_type_offset != 0) { - if (G_STRUCT_MEMBER(LassoSignatureType, node, klass->node_data->sign_type_offset) != - LASSO_SIGNATURE_TYPE_NONE) { + if (G_STRUCT_MEMBER(LassoSignatureType, node, + klass->node_data->sign_type_offset) + != LASSO_SIGNATURE_TYPE_NONE) { + *method = G_STRUCT_MEMBER(LassoSignatureMethod, node, + klass->node_data->sign_method_offset); + *private_key_file = G_STRUCT_MEMBER(char*, node, + klass->node_data->private_key_file_offset); return TRUE; } } @@ -1042,54 +1062,102 @@ lasso_saml20_profile_build_http_redirect(LassoProfile *profile, char *query = NULL; int rc = 0; gboolean must_sign = FALSE; + LassoSignatureMethod signature_method = 0; + const char *private_key_file = NULL; - if (url == NULL) { - return critical_error(LASSO_PROFILE_ERROR_UNKNOWN_PROFILE_URL); - } + goto_cleanup_if_fail_with_rc (url != NULL, LASSO_PROFILE_ERROR_UNKNOWN_PROFILE_URL); /* if message is signed, remove XML signature, add query signature */ - if (has_signature(msg)) { + if (has_signature(msg, &signature_method, (const char **)&private_key_file)) { must_sign = TRUE; - remove_signature(msg); + lasso_node_remove_signature(msg); } - /* No signature on the XML message */ - rc = lasso_saml20_profile_export_to_query(profile, msg, must_sign, &query); - if (rc) - return rc; + lasso_check_good_rc(lasso_saml20_profile_export_to_query(profile, msg, &query, + signature_method, private_key_file)); lasso_assign_new_string(profile->msg_url, lasso_concat_url_query(url, query)); lasso_release(profile->msg_body); lasso_release(query); +cleanup: + return rc; +} + +static int +lasso_saml20_profile_build_redirect_response_msg(LassoProfile *profile, const char *url) +{ + return lasso_saml20_profile_build_http_redirect(profile, + profile->response, + url); +} + +static int +lasso_saml20_profile_build_post_response_msg(LassoProfile *profile, const char *url) +{ + lasso_assign_string(profile->msg_url, url); + lasso_assign_new_string(profile->msg_body, lasso_node_export_to_base64(profile->request)); + check_msg_body; + return 0; +} + +static int +lasso_saml20_profile_build_soap_response_msg(LassoProfile *profile) +{ + lasso_release_string(profile->msg_url); + lasso_assign_new_string(profile->msg_body, lasso_node_export_to_soap(profile->response)); + check_msg_body; return 0; } + int -lasso_saml20_profile_build_response_msg(LassoProfile *profile, char *service, LassoHttpMethod method) +lasso_saml20_profile_build_response_msg(LassoProfile *profile, char *service, + LassoHttpMethod method, const char *_url) { LassoProvider *provider; + char *made_url = NULL, *url; int rc = 0; lasso_bad_param(PROFILE, profile); lasso_profile_clean_msg_info(profile); lasso_check_good_rc(get_provider(profile, &provider)); + url = (char*)_url; + + /* check presence of a request */ + if (! LASSO_IS_SAMLP2_STATUS_RESPONSE(profile->response)) { + return critical_error(LASSO_PROFILE_ERROR_MISSING_RESPONSE); + } + + /* if not explicitely given, automatically determine an URI from the metadatas */ + if (url == NULL && service) { + made_url = url = get_response_url(provider, service, http_method_to_binding(method)); + } switch (method) { case LASSO_HTTP_METHOD_POST: - rc = lasso_saml20_profile_build_post_response(profile, provider, service); + case LASSO_HTTP_METHOD_REDIRECT: + case LASSO_HTTP_METHOD_ARTIFACT_GET: + case LASSO_HTTP_METHOD_ARTIFACT_POST: + goto_cleanup_with_rc(critical_error(LASSO_PROFILE_ERROR_UNKNOWN_PROFILE_URL)); + default: + break; + } + + switch (method) { + case LASSO_HTTP_METHOD_POST: + rc = lasso_saml20_profile_build_post_response_msg(profile, url); break; case LASSO_HTTP_METHOD_REDIRECT: - rc = lasso_saml20_profile_build_redirect_response(profile, provider, - service); + rc = lasso_saml20_profile_build_redirect_response_msg(profile, url); break; case LASSO_HTTP_METHOD_SOAP: - rc = lasso_saml20_profile_build_soap_response(profile); + rc = lasso_saml20_profile_build_soap_response_msg(profile); break; case LASSO_HTTP_METHOD_ARTIFACT_GET: - rc = lasso_profile_saml20_build_artifact_get_response_msg(profile, provider, service); + rc = lasso_profile_saml20_build_artifact_get_response_msg(profile, url); break; - case LASSO_HTTP_METHOD_ARTIFACT_GET: - rc = lasso_profile_saml20_build_artifact_post_response_msg(profile, provider, service); + case LASSO_HTTP_METHOD_ARTIFACT_POST: + rc = lasso_profile_saml20_build_artifact_post_response_msg(profile, url); break; default: rc= LASSO_PROFILE_ERROR_UNSUPPORTED_PROFILE; @@ -1097,6 +1165,7 @@ lasso_saml20_profile_build_response_msg(LassoProfile *profile, char *service, La } cleanup: + lasso_release_string(made_url); return rc; } @@ -1118,7 +1187,8 @@ cleanup: int lasso_saml20_profile_process_any_response(LassoProfile *profile, LassoSamlp2StatusResponse *status_response, - char *response_msg) + LassoHttpMethod *response_method, + const char *response_msg) { int rc = 0; @@ -1128,7 +1198,6 @@ lasso_saml20_profile_process_any_response(LassoProfile *profile, LassoSamlp2StatusResponse *response_abstract = NULL; LassoSamlp2Status *status = NULL; LassoSamlp2StatusCode *status_code1 = NULL; - LassoSamlp2StatusCode *status_code2 = NULL; LassoMessageFormat format; xmlDoc *doc = NULL; @@ -1145,6 +1214,21 @@ lasso_saml20_profile_process_any_response(LassoProfile *profile, rc = LASSO_PROFILE_ERROR_INVALID_MSG; goto cleanup; } + if (response_method) { + switch (format) { + case LASSO_MESSAGE_FORMAT_SOAP: + *response_method = LASSO_HTTP_METHOD_SOAP; + break; + case LASSO_MESSAGE_FORMAT_QUERY: + *response_method = LASSO_HTTP_METHOD_REDIRECT; + break; + case LASSO_MESSAGE_FORMAT_BASE64: + *response_method = LASSO_HTTP_METHOD_POST; + break; + default: + return LASSO_PROFILE_ERROR_UNSUPPORTED_PROFILE; + } + } 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); @@ -1195,7 +1279,7 @@ cleanup: */ int lasso_saml20_profile_process_soap_response(LassoProfile *profile, - char *response_msg) + const char *response_msg) { int rc = 0; LassoSaml2NameID *issuer = NULL; @@ -1269,11 +1353,20 @@ lasso_profile_saml20_setup_message_signature(LassoProfile *profile, LassoNode *r { lasso_bad_param(PROFILE, profile); - if (! lasso_flag_sign_messages) { - message(G_LOG_LEVEL_WARNING, "message should be signed but no-sign-messages flag is " \ - "activated, so it won't be"); - return 0; + switch (lasso_profile_get_signature_hint(profile)) { + case LASSO_PROFILE_SIGNATURE_HINT_MAYBE: + if (! lasso_flag_sign_messages) { + message(G_LOG_LEVEL_WARNING, "message should be signed but no-sign-messages flag is " \ + "activated, so it won't be"); + return 0; + } + break; + case LASSO_PROFILE_SIGNATURE_HINT_FORBID: + return 0; + default: + break; } + if (! LASSO_IS_SERVER(profile->server)) { return LASSO_PROFILE_ERROR_MISSING_SERVER; } @@ -1314,63 +1407,22 @@ lasso_profile_saml20_setup_message_signature(LassoProfile *profile, LassoNode *r return 0; } -/* - * this function factorize all case for producing SAML artifact messages - */ -static gint -lasso_profile_saml20_build_artifact_msg(LassoProfile *profile, - LassoProvider *provider, const char *service, int request_or_response, int get_or_post) +gint +lasso_saml20_profile_setup_encrypted_node(LassoProvider *provider, + LassoNode **node_to_encrypt, LassoNode **node_destination) { - char *artifact = lasso_saml20_profile_generate_artifact(profile, request_or_response); - if (request_or_response == 0) { - url = get_url(provider, service, "HTTP-Artifact"); - } else { - url = get_response_url(provider, service, "HTTP-Artifact"); + LassoNode *encrypted_node; + + if (! LASSO_IS_PROVIDER(provider)) { + return critical_error(LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND); } - if (! url) { - return LASSO_PROFILE_ERROR_UNKNOWN_PROFILE_URL; + encrypted_node = (LassoNode*)lasso_node_encrypt(*node_to_encrypt, + lasso_provider_get_encryption_public_key(provider), + lasso_provider_get_encryption_sym_key_type(provider)); + if (! encrypted_node) { + return LASSO_DS_ERROR_ENCRYPTION_FAILED; } - if (get_or_post == 0) { - if (profile->msg_relayState) { - query = lasso_url_add_parameters(NULL, 0, "SAMLart", artifact, "RelayState", - profile->msg_relayState, NULL); - } else { - query = lasso_url_add_parameters(NULL, 0, "SAMLart", artifact, NULL); - } - lasso_assign_new_string(profile->msg_url, - lasso_concat_url_query(url, query)); - lasso_release_string(query); - lasso_release_string(url); - } else { - lasso_assign_new_string(profile->msg_url, url); - lasso_assign_string(profile->msg_body, artifact); - } -} - -static gint -lasso_profile_saml20_build_artifact_get_request_msg(LassoProfile *profile, - LassoProvider *provider, const char *service) -{ - return lasso_profile_saml20_build_artifact_msg(profile, provider, service, 0, 0); -} - -static gint -lasso_profile_saml20_build_artifact_post_request_msg(LassoProfile *profile, - LassoProvider *provider, const char *service) -{ - return lasso_profile_saml20_build_artifact_msg(profile, provider, service, 0, 1); -} - -static gint -lasso_profile_saml20_build_artifact_get_response_msg(LassoProfile *profile, - LassoProvider *provider, const char *service) -{ - return lasso_profile_saml20_build_artifact_msg(profile, provider, service, 1, 0); -} - -static gint -lasso_profile_saml20_build_artifact_post_response_msg(LassoProfile *profile, - LassoProvider *provider, const char *service) -{ - return lasso_profile_saml20_build_artifact_msg(profile, provider, service, 1, 1); + lasso_assign_new_gobject(*node_destination, encrypted_node); + lasso_release_gobject(*node_to_encrypt); + return 0; } diff --git a/lasso/saml-2.0/profileprivate.h b/lasso/saml-2.0/profileprivate.h index 9fb8cc63..6efc7f4d 100644 --- a/lasso/saml-2.0/profileprivate.h +++ b/lasso/saml-2.0/profileprivate.h @@ -36,7 +36,7 @@ extern "C" { #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, +int lasso_saml20_init_request(LassoProfile *profile, const 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); @@ -57,23 +57,26 @@ int lasso_saml20_profile_process_artifact_response(LassoProfile *profile, const 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_soap_request(LassoProfile *profile, const char *request_msg); +int lasso_saml20_profile_process_soap_response(LassoProfile *profile, const 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); + const char *request_msg); +int lasso_saml20_profile_process_any_response(LassoProfile *profile, LassoSamlp2StatusResponse *response_node, LassoHttpMethod *response_method, const 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_code1, - const char *status_code2); +int lasso_saml20_profile_build_request_msg(LassoProfile *profile, const char *service, LassoHttpMethod method, const char *url); +int lasso_saml20_profile_build_response_msg(LassoProfile *profile, char *service, + LassoHttpMethod method, const char *_url); +int lasso_saml20_profile_init_response(LassoProfile *profile, + LassoSamlp2StatusResponse *status_response, const char *status_code1, const char *status_code2); int lasso_saml20_profile_validate_request(LassoProfile *profile, gboolean needs_identity, LassoSamlp2StatusResponse *status_response, LassoProvider **provider_out); gint lasso_saml20_build_http_redirect_query_simple(LassoProfile *profile, LassoNode *msg, - gboolean must_sign, const char *profile_name, gboolean is_response); + const char *profile_name, gboolean is_response); gint lasso_saml20_profile_build_http_redirect(LassoProfile *profile, LassoNode *msg, - gboolean must_sign, const char *url); + const char *url); gint lasso_profile_saml20_setup_message_signature(LassoProfile *profile, LassoNode *request_or_response); +gint lasso_saml20_profile_setup_encrypted_node(LassoProvider *provider, + LassoNode **node_to_encrypt, LassoNode **node_destination); #ifdef __cplusplus } diff --git a/lasso/saml-2.0/provider.c b/lasso/saml-2.0/provider.c index 5598fd60..613de792 100644 --- a/lasso/saml-2.0/provider.c +++ b/lasso/saml-2.0/provider.c @@ -223,7 +223,7 @@ lasso_saml20_provider_get_first_http_method(LassoProvider *provider, LassoHttpMethod method = LASSO_HTTP_METHOD_NONE; int i; const char *possible_bindings[] = { - "HTTP-Redirect", "HTTP-Post", "SOAP", NULL + "HTTP-Redirect", "HTTP-Post", "SOAP", "HTTP-Artifact", NULL }; LassoHttpMethod method_bindings[] = { LASSO_HTTP_METHOD_SOAP, LASSO_HTTP_METHOD_REDIRECT, LASSO_HTTP_METHOD_POST diff --git a/lasso/saml-2.0/saml2_helper.c b/lasso/saml-2.0/saml2_helper.c index fe830f25..4b8d5503 100644 --- a/lasso/saml-2.0/saml2_helper.c +++ b/lasso/saml-2.0/saml2_helper.c @@ -178,7 +178,7 @@ lasso_saml2_assertion_get_subject_confirmation(LassoSaml2Assertion *saml2_assert return subject->SubjectConfirmation; } -static LassoSaml2SubjectConfirmationData* +LassoSaml2SubjectConfirmationData* lasso_saml2_assertion_get_subject_confirmation_data(LassoSaml2Assertion *saml2_assertion, gboolean create) { LassoSaml2SubjectConfirmation *subject_confirmation; @@ -707,5 +707,3 @@ lasso_saml2_assertion_add_attribute_with_node(LassoSaml2Assertion *assertion, co cleanup: return rc; } - - diff --git a/lasso/saml-2.0/saml2_helper.h b/lasso/saml-2.0/saml2_helper.h index 1b99185a..adeea482 100644 --- a/lasso/saml-2.0/saml2_helper.h +++ b/lasso/saml-2.0/saml2_helper.h @@ -57,8 +57,9 @@ LASSO_EXPORT gboolean lasso_saml2_assertion_is_audience_restricted( LASSO_EXPORT LassoSaml2NameID* lasso_saml2_name_id_build_persistent(const char *id, const char *idpID, const char *providerID); -LASSO_EXPORT LassoSaml2EncryptedElement* lasso_saml2_encrypted_element_build_encrypted_persistent_name_id( - const char *id, const char *idpID, const LassoProvider *provider); +LASSO_EXPORT LassoSaml2EncryptedElement* + lasso_saml2_encrypted_element_build_encrypted_persistent_name_id(const char *id, + const char *idpID, const LassoProvider *provider); LASSO_EXPORT void lasso_saml2_assertion_set_subject_name_id(LassoSaml2Assertion *saml2_assertion, LassoNode *node); @@ -88,8 +89,12 @@ LASSO_EXPORT LassoProvider* lasso_saml2_assertion_get_issuer_provider( LASSO_EXPORT int lasso_server_saml2_assertion_setup_signature(LassoServer *server, LassoSaml2Assertion *saml2_assertion); -LASSO_EXPORT int lasso_saml2_assertion_add_attribute_with_node(LassoSaml2Assertion *assertion, const char *name, const char *nameformat, LassoNode *content); +LASSO_EXPORT int lasso_saml2_assertion_add_attribute_with_node(LassoSaml2Assertion *assertion, const + char *name, const char *nameformat, LassoNode *content); +LASSO_EXPORT LassoSaml2SubjectConfirmationData* + lasso_saml2_assertion_get_subject_confirmation_data(LassoSaml2Assertion *saml2_assertion, + gboolean create); #ifdef __cplusplus } diff --git a/lasso/xml/saml-2.0/samlp2_request_abstract.c b/lasso/xml/saml-2.0/samlp2_request_abstract.c index 772b5c91..0c16930c 100644 --- a/lasso/xml/saml-2.0/samlp2_request_abstract.c +++ b/lasso/xml/saml-2.0/samlp2_request_abstract.c @@ -170,9 +170,9 @@ class_init(LassoSamlp2RequestAbstractClass *klass) LassoSamlp2RequestAbstract, sign_type); nclass->node_data->sign_method_offset = G_STRUCT_OFFSET( LassoSamlp2RequestAbstract, sign_method); - nclass->node_data->private_key_file_offset = G_STRUCT_OFFSET(LassoSaml2Assertion, + nclass->node_data->private_key_file_offset = G_STRUCT_OFFSET(LassoSamlp2RequestAbstract, private_key_file); - nclass->node_data->certificate_file_offset = G_STRUCT_OFFSET(LassoSaml2Assertion, + nclass->node_data->certificate_file_offset = G_STRUCT_OFFSET(LassoSamlp2RequestAbstract, certificate_file); } diff --git a/lasso/xml/saml-2.0/samlp2_status_response.c b/lasso/xml/saml-2.0/samlp2_status_response.c index d530dcab..96febdd9 100644 --- a/lasso/xml/saml-2.0/samlp2_status_response.c +++ b/lasso/xml/saml-2.0/samlp2_status_response.c @@ -173,9 +173,9 @@ class_init(LassoSamlp2StatusResponseClass *klass) LassoSamlp2StatusResponse, sign_type); nclass->node_data->sign_method_offset = G_STRUCT_OFFSET( LassoSamlp2StatusResponse, sign_method); - nclass->node_data->private_key_file_offset = G_STRUCT_OFFSET(LassoSaml2StatusResponse, + nclass->node_data->private_key_file_offset = G_STRUCT_OFFSET(LassoSamlp2StatusResponse, private_key_file); - nclass->node_data->certificate_file_offset = G_STRUCT_OFFSET(LassoSaml2StatusResponse, + nclass->node_data->certificate_file_offset = G_STRUCT_OFFSET(LassoSamlp2StatusResponse, certificate_file); nclass->node_data->keep_xmlnode = TRUE; } |