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;
|
remote_provider->role = LASSO_PROVIDER_ROLE_SP;
|
||||||
server->parent.role = LASSO_PROVIDER_ROLE_IDP;
|
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) ||
|
if (((authn_request->ProtocolBinding != NULL) ||
|
||||||
(authn_request->AssertionConsumerServiceURL != NULL)) &&
|
(authn_request->AssertionConsumerServiceURL != NULL)) &&
|
||||||
(authn_request->AssertionConsumerServiceIndex != -1))
|
(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 */
|
/* try to find a protocol profile for sending the response */
|
||||||
protocol_binding = authn_request->ProtocolBinding;
|
protocol_binding = authn_request->ProtocolBinding;
|
||||||
if (protocol_binding == NULL && authn_request->AssertionConsumerServiceIndex) {
|
if (protocol_binding || authn_request->AssertionConsumerServiceURL)
|
||||||
/* protocol binding not set; so it will look into
|
{
|
||||||
* AssertionConsumerServiceIndex
|
const gchar *acs_url_binding = NULL;
|
||||||
* 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(
|
if (authn_request->AssertionConsumerServiceURL) {
|
||||||
remote_provider, service_index);
|
acs_url_binding = lasso_saml20_provider_get_assertion_consumer_service_binding_by_url(
|
||||||
if (binding == NULL) {
|
remote_provider, authn_request->AssertionConsumerServiceURL);
|
||||||
if (service_index == -1)
|
if (! acs_url_binding) {
|
||||||
return LASSO_LOGIN_ERROR_NO_DEFAULT_ENDPOINT;
|
// Sent ACS URL is unknown
|
||||||
} else if (lasso_strisequal(binding,"HTTP-Artifact")) {
|
rc = LASSO_PROFILE_ERROR_INVALID_PROTOCOLPROFILE;
|
||||||
login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_ART;
|
goto cleanup;
|
||||||
} else if (lasso_strisequal(binding,"HTTP-POST")) {
|
}
|
||||||
login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_POST;
|
if (! protocol_binding) {
|
||||||
} else if (lasso_strisequal(binding,"HTTP-Redirect")) {
|
// Only ACS URL sent
|
||||||
login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_REDIRECT;
|
protocol_binding = acs_url_binding;
|
||||||
} 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 (lasso_strisequal(protocol_binding,LASSO_SAML2_METADATA_BINDING_ARTIFACT)) {
|
if (lasso_strisequal(protocol_binding,LASSO_SAML2_METADATA_BINDING_ARTIFACT)) {
|
||||||
login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_ART;
|
login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_ART;
|
||||||
} else if (lasso_strisequal(protocol_binding,LASSO_SAML2_METADATA_BINDING_POST)) {
|
} 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;
|
rc = LASSO_PROFILE_ERROR_INVALID_PROTOCOLPROFILE;
|
||||||
goto cleanup;
|
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
|
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*
|
Suite*
|
||||||
login_saml2_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_idpKeyRollover, test05_sso_idp_with_key_rollover);
|
||||||
tcase_add_test(tc_spKeyRollover, test06_sso_sp_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_hmacSignature, test07_sso_sp_with_hmac_sha1_signatures);
|
||||||
|
tcase_add_test(tc_spLogin, test08_test_authnrequest_flags);
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue