SAML-2.0: Rework protocol profile selection when parsing AuthnRequest messages
This commit also add tests around authn request parsing.
This commit is contained in:
parent
3e597eedb9
commit
05fe802b8d
|
@ -303,7 +303,9 @@ lasso_saml20_login_process_authn_request_msg(LassoLogin *login, const char *auth
|
|||
remote_provider->role = LASSO_PROVIDER_ROLE_SP;
|
||||
server->parent.role = LASSO_PROVIDER_ROLE_IDP;
|
||||
|
||||
/* all those attributes are mutually exclusive */
|
||||
/* Normally those three attributes are mutually exclusive, but Google Apps send
|
||||
* ProtocolBinding and AssertionConsumerServiceURL at the same time, so we support this case
|
||||
* by validating that it matches the same endpoint */
|
||||
if (((authn_request->ProtocolBinding != NULL) ||
|
||||
(authn_request->AssertionConsumerServiceURL != NULL)) &&
|
||||
(authn_request->AssertionConsumerServiceIndex != -1))
|
||||
|
@ -314,41 +316,24 @@ lasso_saml20_login_process_authn_request_msg(LassoLogin *login, const char *auth
|
|||
|
||||
/* try to find a protocol profile for sending the response */
|
||||
protocol_binding = authn_request->ProtocolBinding;
|
||||
if (protocol_binding == NULL && authn_request->AssertionConsumerServiceIndex) {
|
||||
/* protocol binding not set; so it will look into
|
||||
* AssertionConsumerServiceIndex
|
||||
* Also, if AssertionConsumerServiceIndex is not set in request,
|
||||
* its value will be -1, which is just the right value to get
|
||||
* default assertion consumer... (convenient)
|
||||
*/
|
||||
gchar *binding;
|
||||
int service_index = authn_request->AssertionConsumerServiceIndex;
|
||||
if (protocol_binding || authn_request->AssertionConsumerServiceURL)
|
||||
{
|
||||
const gchar *acs_url_binding = NULL;
|
||||
|
||||
binding = lasso_saml20_provider_get_assertion_consumer_service_binding(
|
||||
remote_provider, service_index);
|
||||
if (binding == NULL) {
|
||||
if (service_index == -1)
|
||||
return LASSO_LOGIN_ERROR_NO_DEFAULT_ENDPOINT;
|
||||
} else if (lasso_strisequal(binding,"HTTP-Artifact")) {
|
||||
login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_ART;
|
||||
} else if (lasso_strisequal(binding,"HTTP-POST")) {
|
||||
login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_POST;
|
||||
} else if (lasso_strisequal(binding,"HTTP-Redirect")) {
|
||||
login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_REDIRECT;
|
||||
} else if (lasso_strisequal(binding,"SOAP")) {
|
||||
login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_LECP;
|
||||
} else if (lasso_strisequal(binding,"PAOS")) {
|
||||
login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_LECP;
|
||||
}
|
||||
lasso_release_string(binding);
|
||||
} else {
|
||||
// If we just received an URL, try to find the corresponding protocol binding
|
||||
if (protocol_binding == NULL && authn_request->AssertionConsumerServiceURL) {
|
||||
protocol_binding =
|
||||
lasso_saml20_provider_get_assertion_consumer_service_binding_by_url(
|
||||
remote_provider,
|
||||
authn_request->AssertionConsumerServiceURL);
|
||||
if (authn_request->AssertionConsumerServiceURL) {
|
||||
acs_url_binding = lasso_saml20_provider_get_assertion_consumer_service_binding_by_url(
|
||||
remote_provider, authn_request->AssertionConsumerServiceURL);
|
||||
if (! acs_url_binding) {
|
||||
// Sent ACS URL is unknown
|
||||
rc = LASSO_PROFILE_ERROR_INVALID_PROTOCOLPROFILE;
|
||||
goto cleanup;
|
||||
}
|
||||
if (! protocol_binding) {
|
||||
// Only ACS URL sent
|
||||
protocol_binding = acs_url_binding;
|
||||
}
|
||||
}
|
||||
|
||||
if (lasso_strisequal(protocol_binding,LASSO_SAML2_METADATA_BINDING_ARTIFACT)) {
|
||||
login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_ART;
|
||||
} else if (lasso_strisequal(protocol_binding,LASSO_SAML2_METADATA_BINDING_POST)) {
|
||||
|
@ -364,6 +349,41 @@ lasso_saml20_login_process_authn_request_msg(LassoLogin *login, const char *auth
|
|||
rc = LASSO_PROFILE_ERROR_INVALID_PROTOCOLPROFILE;
|
||||
goto cleanup;
|
||||
}
|
||||
// We received both a protocolbinding and an acs url, check both matches
|
||||
if (acs_url_binding && g_strcmp0(protocol_binding, acs_url_binding) != 0) {
|
||||
rc = LASSO_PROFILE_ERROR_INVALID_PROTOCOLPROFILE;
|
||||
goto cleanup;
|
||||
}
|
||||
} else {
|
||||
/* protocol binding not set; so it will look into
|
||||
* AssertionConsumerServiceIndex
|
||||
* Also, if AssertionConsumerServiceIndex is not set in request,
|
||||
* its value will be -1, which is just the right value to get
|
||||
* default assertion consumer... (convenient)
|
||||
*/
|
||||
gchar *binding;
|
||||
int service_index = authn_request->AssertionConsumerServiceIndex;
|
||||
|
||||
binding = lasso_saml20_provider_get_assertion_consumer_service_binding(
|
||||
remote_provider, service_index);
|
||||
if (binding == NULL) {
|
||||
if (service_index == -1) {
|
||||
goto_cleanup_with_rc(LASSO_LOGIN_ERROR_NO_DEFAULT_ENDPOINT);
|
||||
} else {
|
||||
goto_cleanup_with_rc(LASSO_PROFILE_ERROR_INVALID_PROTOCOLPROFILE);
|
||||
}
|
||||
} else if (lasso_strisequal(binding,"HTTP-Artifact")) {
|
||||
login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_ART;
|
||||
} else if (lasso_strisequal(binding,"HTTP-POST")) {
|
||||
login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_POST;
|
||||
} else if (lasso_strisequal(binding,"HTTP-Redirect")) {
|
||||
login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_REDIRECT;
|
||||
} else if (lasso_strisequal(binding,"SOAP")) {
|
||||
login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_LECP;
|
||||
} else if (lasso_strisequal(binding,"PAOS")) {
|
||||
login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_LECP;
|
||||
}
|
||||
lasso_release_string(binding);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1002,6 +1002,111 @@ START_TEST(test07_sso_sp_with_hmac_sha1_signatures)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
typedef struct {
|
||||
char *assertion_consumer_service_url;
|
||||
char *protocol_binding;
|
||||
gboolean use_assertion_consumer_service_idx;
|
||||
int assertion_consumer_service_idx;
|
||||
gboolean stop_after_build_assertion;
|
||||
} SsoSettings;
|
||||
|
||||
static void
|
||||
sso_initiated_by_sp2(LassoServer *idp_context, LassoServer *sp_context, SsoSettings sso_settings)
|
||||
{
|
||||
LassoLogin *idp_login_context;
|
||||
LassoLogin *sp_login_context;
|
||||
LassoSamlp2AuthnRequest *request;
|
||||
char *authn_request_query;
|
||||
|
||||
check_not_null(idp_login_context = lasso_login_new(idp_context));
|
||||
check_not_null(sp_login_context = lasso_login_new(sp_context))
|
||||
|
||||
/* Create response */
|
||||
check_good_rc(lasso_login_init_authn_request(sp_login_context, NULL, LASSO_HTTP_METHOD_REDIRECT));
|
||||
request = (LassoSamlp2AuthnRequest*)sp_login_context->parent.request;
|
||||
if (sso_settings.assertion_consumer_service_url) {
|
||||
lasso_assign_string(request->AssertionConsumerServiceURL, sso_settings.assertion_consumer_service_url);
|
||||
}
|
||||
if (sso_settings.protocol_binding) {
|
||||
lasso_assign_string(request->ProtocolBinding, sso_settings.protocol_binding);
|
||||
}
|
||||
if (sso_settings.use_assertion_consumer_service_idx) {
|
||||
request->AssertionConsumerServiceIndex = sso_settings.assertion_consumer_service_idx;
|
||||
}
|
||||
lasso_assign_string(LASSO_SAMLP2_AUTHN_REQUEST(sp_login_context->parent.request)->NameIDPolicy->Format,
|
||||
LASSO_SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT);
|
||||
LASSO_SAMLP2_AUTHN_REQUEST(sp_login_context->parent.request)->NameIDPolicy->AllowCreate = 1;
|
||||
check_good_rc(lasso_login_build_authn_request_msg(sp_login_context));
|
||||
check_not_null(sp_login_context->parent.msg_url);
|
||||
authn_request_query = strchr(sp_login_context->parent.msg_url, '?');
|
||||
check_not_null(authn_request_query);
|
||||
authn_request_query += 1;
|
||||
check_good_rc(lasso_login_process_authn_request_msg(idp_login_context, authn_request_query));
|
||||
|
||||
check_good_rc(lasso_login_validate_request_msg(idp_login_context,
|
||||
1, /* authentication_result */
|
||||
0 /* is_consent_obtained */
|
||||
));
|
||||
|
||||
check_good_rc(lasso_login_build_assertion(idp_login_context,
|
||||
LASSO_SAML_AUTHENTICATION_METHOD_PASSWORD,
|
||||
"FIXME: authenticationInstant",
|
||||
"FIXME: reauthenticateOnOrAfter",
|
||||
"FIXME: notBefore",
|
||||
"FIXME: notOnOrAfter"));
|
||||
if (sso_settings.stop_after_build_assertion) {
|
||||
goto cleanup;
|
||||
}
|
||||
check_good_rc(lasso_login_build_authn_response_msg(idp_login_context));
|
||||
check_not_null(idp_login_context->parent.msg_body);
|
||||
check_not_null(idp_login_context->parent.msg_url);
|
||||
|
||||
/* Process response */
|
||||
check_good_rc(lasso_login_process_authn_response_msg(sp_login_context,
|
||||
idp_login_context->parent.msg_body));
|
||||
check_good_rc(lasso_login_accept_sso(sp_login_context));
|
||||
|
||||
/* Cleanup */
|
||||
cleanup:
|
||||
lasso_release_gobject(idp_login_context);
|
||||
lasso_release_gobject(sp_login_context);
|
||||
}
|
||||
|
||||
START_TEST(test08_test_authnrequest_flags)
|
||||
{
|
||||
LassoServer *idp_context = NULL;
|
||||
LassoServer *sp_context = NULL;
|
||||
GList *providers;
|
||||
|
||||
/* Create an IdP context for IdP initiated SSO with provider metadata 1 */
|
||||
make_context(idp_context, "idp5-saml2", "", LASSO_PROVIDER_ROLE_SP, "sp5-saml2", "")
|
||||
make_context(sp_context, "sp5-saml2", "", LASSO_PROVIDER_ROLE_IDP, "idp5-saml2", "")
|
||||
|
||||
block_lasso_logs;
|
||||
sso_initiated_by_sp2(idp_context, sp_context,
|
||||
(SsoSettings) {
|
||||
.use_assertion_consumer_service_idx = 1,
|
||||
.assertion_consumer_service_idx = 0,
|
||||
.stop_after_build_assertion = 1,
|
||||
});
|
||||
sso_initiated_by_sp2(idp_context, sp_context,
|
||||
(SsoSettings) {
|
||||
.assertion_consumer_service_url = "http://sp5/singleSignOnPost",
|
||||
.stop_after_build_assertion = 1,
|
||||
});
|
||||
sso_initiated_by_sp2(idp_context, sp_context,
|
||||
(SsoSettings) {
|
||||
.protocol_binding = LASSO_SAML2_METADATA_BINDING_ARTIFACT,
|
||||
.stop_after_build_assertion = 1,
|
||||
});
|
||||
unblock_lasso_logs;
|
||||
|
||||
/* Cleanup */
|
||||
lasso_release_gobject(idp_context);
|
||||
lasso_release_gobject(sp_context);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
Suite*
|
||||
login_saml2_suite()
|
||||
{
|
||||
|
@ -1027,6 +1132,7 @@ login_saml2_suite()
|
|||
tcase_add_test(tc_idpKeyRollover, test05_sso_idp_with_key_rollover);
|
||||
tcase_add_test(tc_spKeyRollover, test06_sso_sp_with_key_rollover);
|
||||
tcase_add_test(tc_hmacSignature, test07_sso_sp_with_hmac_sha1_signatures);
|
||||
tcase_add_test(tc_spLogin, test08_test_authnrequest_flags);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue