diff options
| author | Benjamin Dauvergne <bdauvergne@entrouvert.com> | 2010-02-10 00:34:59 +0000 |
|---|---|---|
| committer | Benjamin Dauvergne <bdauvergne@entrouvert.com> | 2010-02-10 00:34:59 +0000 |
| commit | a93d3e5f5cf556436404c91e5525a3b82f0835ad (patch) | |
| tree | 1f2e0191f53f4e2feba653d9f32cd01c0c18ce8f | |
| parent | f648941f018cbbaa9f3bd095f1bbf1ef63f5c8b6 (diff) | |
SAML 2.0: separate lasso_saml20_login_process_response_status_and_assertion into multiple functions
* lasso/saml-2.0/login.c:
in lasso_saml20_login_process_response_status_and_assertion, extract assertion
decryption, and issuer checking into their own function.
| -rw-r--r-- | lasso/saml-2.0/login.c | 175 |
1 files changed, 100 insertions, 75 deletions
diff --git a/lasso/saml-2.0/login.c b/lasso/saml-2.0/login.c index 3a6d8fa2..6361f541 100644 --- a/lasso/saml-2.0/login.c +++ b/lasso/saml-2.0/login.c @@ -1050,25 +1050,87 @@ cleanup: return rc; } +static gboolean +_lasso_check_assertion_issuer(LassoSaml2Assertion *assertion, const gchar *provider_id) +{ + if (! LASSO_SAML2_ASSERTION(assertion) || ! provider_id) + return FALSE; + + if (! assertion->Issuer || ! assertion->Issuer->content) + return FALSE; + + return g_strcmp0(assertion->Issuer->content, provider_id) == 0; +} + +static gint +_lasso_saml20_login_decrypt_assertion(LassoLogin *login, LassoSamlp2Response *samlp2_response) +{ + xmlSecKey *encryption_private_key; + GList *it; + gboolean at_least_one_decryption_failture = FALSE; + gboolean at_least_one_malformed_element = FALSE; + + if (! samlp2_response->EncryptedAssertion) + return 0; /* nothing to do */ + + encryption_private_key = lasso_server_get_encryption_private_key(login->parent.server); + if (! encryption_private_key) { + message(G_LOG_LEVEL_WARNING, "Missing private encryption key, cannot decrypt assertions."); + return LASSO_DS_ERROR_DECRYPTION_FAILED_MISSING_PRIVATE_KEY; + } + + lasso_foreach (it, samlp2_response->EncryptedAssertion) { + LassoSaml2EncryptedElement *encrypted_assertion; + LassoSaml2Assertion * assertion = NULL; + int rc1 = 0; + + if (! LASSO_IS_SAML2_ENCRYPTED_ELEMENT(it->data)) { + message(G_LOG_LEVEL_WARNING, "EncryptedAssertion contains a non EncryptedElement object"); + at_least_one_malformed_element |= TRUE; + continue; + } + encrypted_assertion = (LassoSaml2EncryptedElement*)it->data; + rc1 = lasso_saml2_encrypted_element_decrypt(encrypted_assertion, encryption_private_key, (LassoNode**)&assertion); + + if (rc1) { + message(G_LOG_LEVEL_WARNING, "Could not decrypt an assertion: %s", lasso_strerror(rc1)); + at_least_one_decryption_failture |= TRUE; + continue; + } + + if (! LASSO_IS_SAML2_ASSERTION(assertion)) { + message(G_LOG_LEVEL_WARNING, "EncryptedAssertion contains something that is not an assertion"); + lasso_release_gobject(assertion); + continue; + } + /* copy the assertion to the clear assertion list */ + lasso_list_add_new_gobject(samlp2_response->Assertion, assertion); + } + + if (at_least_one_decryption_failture) { + return LASSO_DS_ERROR_DECRYPTION_FAILED; + } + if (at_least_one_malformed_element) { + return LASSO_XML_ERROR_SCHEMA_INVALID_FRAGMENT; + } + return 0; +} + static gint lasso_saml20_login_process_response_status_and_assertion(LassoLogin *login) { LassoSamlp2StatusResponse *response; LassoSamlp2Response *samlp2_response = NULL; LassoProfile *profile; - xmlSecKey *encryption_private_key = NULL; char *status_value; - GList *it = NULL; - int rc = 0, rc1 = 0; + int rc = 0, rc1 = 0, message_signature_status; - g_return_val_if_fail(LASSO_IS_LOGIN(login), LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); - - profile = LASSO_PROFILE(login); - response = LASSO_SAMLP2_STATUS_RESPONSE(profile->response); + profile = &login->parent; lasso_extract_node_or_fail(response, profile->response, SAMLP2_STATUS_RESPONSE, LASSO_PROFILE_ERROR_INVALID_MSG); lasso_extract_node_or_fail(samlp2_response, response, SAMLP2_RESPONSE, LASSO_PROFILE_ERROR_INVALID_MSG); + message_signature_status = profile->signature_status; if (response->Status == NULL || ! LASSO_IS_SAMLP2_STATUS(response->Status) || response->Status->StatusCode == NULL || @@ -1095,91 +1157,54 @@ lasso_saml20_login_process_response_status_and_assertion(LassoLogin *login) } } } - return LASSO_LOGIN_ERROR_STATUS_NOT_SUCCESS; } - - if (LASSO_IS_SERVER(profile->server) && profile->server->private_data) { - encryption_private_key = profile->server->private_data->encryption_private_key; - } - /* Decrypt all EncryptedAssertions */ - it = samlp2_response->EncryptedAssertion; - for (;it;it = it->next) { - LassoSaml2EncryptedElement *encrypted_assertion; - LassoSaml2Assertion * assertion = NULL; - - if (! encryption_private_key) { - message(G_LOG_LEVEL_WARNING, "Missing private encryption key, cannot decrypt assertions."); - break; - } - - if (! LASSO_IS_SAML2_ENCRYPTED_ELEMENT(it->data)) { - message(G_LOG_LEVEL_WARNING, "EncryptedAssertion contains a non EncryptedElement object"); - continue; - } - encrypted_assertion = (LassoSaml2EncryptedElement*)it->data; - rc1 = lasso_saml2_encrypted_element_decrypt(encrypted_assertion, encryption_private_key, (LassoNode**)&assertion); - - if (rc1) { - message(G_LOG_LEVEL_WARNING, "Could not decrypt an assertion"); - continue; - } + rc1 = _lasso_saml20_login_decrypt_assertion(login, samlp2_response); + /* traverse all assertions */ + goto_cleanup_if_fail_with_rc (samlp2_response->Assertion != NULL, + LASSO_PROFILE_ERROR_MISSING_ASSERTION); - if (! LASSO_IS_SAML2_ASSERTION(assertion)) { - message(G_LOG_LEVEL_WARNING, "EncryptedAssertion contains something that is not an assertion"); - lasso_release_gobject(assertion); - continue; - } - lasso_list_add_gobject(samlp2_response->Assertion, assertion); - lasso_release_gobject(assertion); - } - - /** FIXME: treat more than the first assertion ? */ - if (samlp2_response->Assertion != NULL) { - LassoSaml2Subject *subject; - LassoSaml2Assertion *assertion = samlp2_response->Assertion->data; + lasso_foreach_full_begin(LassoSaml2Assertion*, assertion, it, samlp2_response->Assertion); + LassoSaml2Subject *subject = NULL; int rc2 = 0; lasso_assign_gobject (login->private_data->saml2_assertion, assertion); - /* If no signature was validated on the response, check the signature at the - * assertion level */ - if (profile->signature_status == LASSO_DS_ERROR_SIGNATURE_NOT_FOUND) { - profile->signature_status = rc2 = lasso_saml20_login_check_assertion_signature(login, assertion); + /* If signature has already been verified on the message, and assertion has the same + * issuer as the message, the assertion is covered. So no need to verify a second + * time */ + if (message_signature_status != 0 + || ! _lasso_check_assertion_issuer(assertion, + profile->remote_providerID)) { + rc2 = lasso_saml20_login_check_assertion_signature(login, assertion); + if (! profile->signature_status) { + profile->signature_status = rc2; + } } - if (! LASSO_IS_SAML2_SUBJECT(assertion->Subject)) { - return LASSO_PROFILE_ERROR_MISSING_SUBJECT; - } - subject = assertion->Subject; + goto_cleanup_if_fail_with_rc (profile->signature_status == 0, + LASSO_LOGIN_ERROR_INVALID_ASSERTION_SIGNATURE); + lasso_extract_node_or_fail(subject, assertion->Subject, SAML2_SUBJECT, + LASSO_PROFILE_ERROR_MISSING_SUBJECT); /* Verify Subject->SubjectConfirmationData->InResponseTo */ - if (login->private_data->request_id && ( - assertion->Subject->SubjectConfirmation == NULL || - assertion->Subject->SubjectConfirmation->SubjectConfirmationData == NULL || - assertion->Subject->SubjectConfirmation->SubjectConfirmationData->InResponseTo == NULL || - g_strcmp0(assertion->Subject->SubjectConfirmation->SubjectConfirmationData->InResponseTo, login->private_data->request_id) != 0)) { - return LASSO_LOGIN_ERROR_ASSERTION_DOES_NOT_MATCH_REQUEST_ID; - } - - /** Handle nameid */ - rc2 = lasso_saml20_profile_process_name_identifier_decryption(profile, &subject->NameID, &subject->EncryptedID); + if (login->private_data->request_id) { + const char *in_response_to = lasso_saml2_assertion_get_in_response_to(assertion); - if (rc2) { - rc = rc2; - } - } else { - if (rc1) { - rc = rc1; - } else { - rc = LASSO_PROFILE_ERROR_MISSING_ASSERTION; + if (g_strcmp0(in_response_to, login->private_data->request_id) != 0) { + rc = LASSO_LOGIN_ERROR_ASSERTION_DOES_NOT_MATCH_REQUEST_ID; + goto cleanup; + } } - } + /** Handle nameid */ + lasso_check_good_rc(lasso_saml20_profile_process_name_identifier_decryption(profile, + &subject->NameID, &subject->EncryptedID)); + lasso_foreach_full_end(); + cleanup: - return rc; } |
