From abd03e3e25263f9559e162385228c378c262de83 Mon Sep 17 00:00:00 2001 From: Ricardo Martin Date: Sat, 23 Mar 2024 15:12:01 +0100 Subject: [PATCH] Validate Saml URLs inside DefaultClientValidationProvider (#142) Closes keycloak/keycloak-private#62 Signed-off-by: rmartinc --- .../DefaultClientValidationProvider.java | 61 ++++++++++++++++++- .../keycloak/testsuite/admin/ClientTest.java | 52 ++++++++++++++++ .../admin/client/InstallationTest.java | 32 +++++----- .../client/ClientRegistrationTest.java | 47 +++++++++++++- 4 files changed, 174 insertions(+), 18 deletions(-) diff --git a/services/src/main/java/org/keycloak/validation/DefaultClientValidationProvider.java b/services/src/main/java/org/keycloak/validation/DefaultClientValidationProvider.java index b2202e2ed781..954da121e7b1 100644 --- a/services/src/main/java/org/keycloak/validation/DefaultClientValidationProvider.java +++ b/services/src/main/java/org/keycloak/validation/DefaultClientValidationProvider.java @@ -27,6 +27,7 @@ import org.keycloak.protocol.oidc.utils.PairwiseSubMapperUtils; import org.keycloak.protocol.oidc.utils.PairwiseSubMapperValidator; import org.keycloak.protocol.oidc.utils.SubjectType; +import org.keycloak.protocol.saml.SamlProtocol; import org.keycloak.representations.idm.ProtocolMapperRepresentation; import org.keycloak.representations.oidc.OIDCClientRepresentation; import org.keycloak.services.util.ResolveRelative; @@ -76,7 +77,52 @@ private enum FieldMessages { TOS_URI(ClientModel.TOS_URI, "Terms of service URL is not a valid URL", "tosURLInvalid", null, null, - "Terms of service URL uses an illegal scheme", "tosURLIllegalSchemeError"); + "Terms of service URL uses an illegal scheme", "tosURLIllegalSchemeError"), + + ADMIN_URL("masterSamlProcessingUrl", + "Master SAML Processing URL is not a valid URL", "adminUrlURLInvalid", + null, null, + "Master SAML Processing URL uses an illegal scheme", "adminUrlURLIllegalSchemeError"), + + SAML_ASSERTION_CONSUMER_URL_POST_URI(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_POST_ATTRIBUTE, + "Assertion Consumer Service POST Binding URL is not a valid URL", "samlAssertionConsumerUrlPostURLInvalid", + null, null, + "Assertion Consumer Service POST Binding URL uses an illegal scheme", "samlAssertionConsumerUrlPostURLIllegalSchemeError"), + + SAML_ASSERTION_CONSUMER_URL_REDIRECT_URI(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_REDIRECT_ATTRIBUTE, + "Assertion Consumer Service Redirect Binding URL is not a valid URL", "samlAssertionConsumerUrlRedirectURLInvalid", + null, null, + "Assertion Consumer Service Redirect Binding URL uses an illegal scheme", "samlAssertionConsumerUrlRedirectURLIllegalSchemeError"), + + SAML_ASSERTION_CONSUMER_URL_ARTIFACT_URI(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_ARTIFACT_ATTRIBUTE, + "Artifact Binding URL is not a valid URL", "samlAssertionConsumerUrlArtifactURLInvalid", + null, null, + "Artifact Binding URL uses an illegal scheme", "samlAssertionConsumerUrlArtifactURLIllegalSchemeError"), + + SAML_SINGLE_LOGOUT_SERVICE_URL_POST_URI(SamlProtocol.SAML_SINGLE_LOGOUT_SERVICE_URL_POST_ATTRIBUTE, + "Logout Service POST Binding URL is not a valid URL", "samlLogoutServiceUrlPostURLInvalid", + null, null, + "Logout Service POST Binding URL uses an illegal scheme", "samlLogoutServiceUrlPostURLIllegalSchemeError"), + + SAML_SINGLE_LOGOUT_SERVICE_URL_ARTIFACT_URI(SamlProtocol.SAML_SINGLE_LOGOUT_SERVICE_URL_ARTIFACT_ATTRIBUTE, + "Logout Service ARTIFACT Binding URL is not a valid URL", "samlLogoutServiceUrlArtifactURLInvalid", + null, null, + "Logout Service ARTIFACT Binding URL uses an illegal scheme", "samlLogoutServiceUrlArtifactURLIllegalSchemeError"), + + SAML_SINGLE_LOGOUT_SERVICE_URL_REDIRECT_URI(SamlProtocol.SAML_SINGLE_LOGOUT_SERVICE_URL_REDIRECT_ATTRIBUTE, + "Logout Service Redirect Binding URL is not a valid URL", "samlLogoutServiceUrlRedirectURLInvalid", + null, null, + "Logout Service Redirect Binding URL uses an illegal scheme", "samlLogoutServiceUrlRedirectURLIllegalSchemeError"), + + SAML_SINGLE_LOGOUT_SERVICE_URL_SOAP_URI(SamlProtocol.SAML_SINGLE_LOGOUT_SERVICE_URL_SOAP_ATTRIBUTE, + "Logout Service SOAP Binding URL is not a valid URL", "samlLogoutServiceUrlSoapURLInvalid", + null, null, + "Logout Service SOAP Binding URL uses an illegal scheme", "samlAssertionConsumerUrlPostURLIllegalSchemeError"), + + SAML_ARTIFACT_RESOLUTION_SERVICE_URL_URI(SamlProtocol.SAML_ARTIFACT_RESOLUTION_SERVICE_URL_ATTRIBUTE, + "Artifact Resolution Service is not a valid URL", "samlAssertionConsumerUrlPostURLInvalid", + null, null, + "Artifact Resolution Service uses an illegal scheme", "samlAssertionConsumerUrlPostURLIllegalSchemeError"); private String fieldId; @@ -174,6 +220,19 @@ private void validateUrls(ValidationContext context) { checkUriLogo(FieldMessages.LOGO_URI, client.getAttribute(ClientModel.LOGO_URI), context); checkUri(FieldMessages.POLICY_URI, client.getAttribute(ClientModel.POLICY_URI), context, true, false); checkUri(FieldMessages.TOS_URI, client.getAttribute(ClientModel.TOS_URI), context, true, false); + + // extra validation URLs for SAML clients + if (SamlProtocol.LOGIN_PROTOCOL.equals(client.getProtocol())) { + checkUri(FieldMessages.ADMIN_URL, client.getManagementUrl(), context, true, false); + checkUri(FieldMessages.SAML_ASSERTION_CONSUMER_URL_POST_URI, client.getAttribute(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_POST_ATTRIBUTE), context, true, false); + checkUri(FieldMessages.SAML_ASSERTION_CONSUMER_URL_REDIRECT_URI, client.getAttribute(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_REDIRECT_ATTRIBUTE), context, true, false); + checkUri(FieldMessages.SAML_ASSERTION_CONSUMER_URL_ARTIFACT_URI, client.getAttribute(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_ARTIFACT_ATTRIBUTE), context, true, false); + checkUri(FieldMessages.SAML_SINGLE_LOGOUT_SERVICE_URL_POST_URI, client.getAttribute(SamlProtocol.SAML_SINGLE_LOGOUT_SERVICE_URL_POST_ATTRIBUTE), context, true, false); + checkUri(FieldMessages.SAML_SINGLE_LOGOUT_SERVICE_URL_ARTIFACT_URI, client.getAttribute(SamlProtocol.SAML_SINGLE_LOGOUT_SERVICE_URL_ARTIFACT_ATTRIBUTE), context, true, false); + checkUri(FieldMessages.SAML_SINGLE_LOGOUT_SERVICE_URL_REDIRECT_URI, client.getAttribute(SamlProtocol.SAML_SINGLE_LOGOUT_SERVICE_URL_REDIRECT_ATTRIBUTE), context, true, false); + checkUri(FieldMessages.SAML_SINGLE_LOGOUT_SERVICE_URL_SOAP_URI, client.getAttribute(SamlProtocol.SAML_SINGLE_LOGOUT_SERVICE_URL_SOAP_ATTRIBUTE), context, true, false); + checkUri(FieldMessages.SAML_ARTIFACT_RESOLUTION_SERVICE_URL_URI, client.getAttribute(SamlProtocol.SAML_ARTIFACT_RESOLUTION_SERVICE_URL_ATTRIBUTE), context, true, false); + } } private void checkUri(FieldMessages field, String url, ValidationContext context, boolean checkValidUrl, boolean checkFragment) { diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ClientTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ClientTest.java index d01281190cd4..2c69ac47293c 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ClientTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ClientTest.java @@ -51,6 +51,7 @@ import org.keycloak.protocol.oidc.OIDCConfigAttributes; import org.keycloak.protocol.oidc.OIDCLoginProtocol; import org.keycloak.protocol.oidc.OIDCLoginProtocolFactory; +import org.keycloak.protocol.saml.SamlProtocol; import org.keycloak.representations.adapters.action.GlobalRequestResult; import org.keycloak.representations.adapters.action.PushNotBeforeAction; import org.keycloak.representations.adapters.action.TestAvailabilityAction; @@ -72,6 +73,7 @@ import java.io.IOException; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; @@ -95,11 +97,18 @@ public void getClients() { } private ClientRepresentation createClient() { + return createClient(null); + } + + private ClientRepresentation createClient(String protocol) { ClientRepresentation rep = new ClientRepresentation(); rep.setClientId("my-app"); rep.setDescription("my-app description"); rep.setEnabled(true); rep.setPublicClient(true); + if (protocol != null) { + rep.setProtocol(protocol); + } Response response = realm.clients().create(rep); response.close(); String id = ApiUtil.getCreatedId(response); @@ -185,6 +194,49 @@ public void testFragmentProhibitedClientValidation() { ); } + @Test + public void testSamlSpecificUrls() { + testSamlSpecificUrls(true, "javascript:alert('TEST')", "data:text/html;base64,PHNjcmlwdD5jb25maXJtKGRvY3VtZW50LmRvbWFpbik7PC9zY3JpcHQ+"); + testSamlSpecificUrls(false, "javascript:alert('TEST')", "data:text/html;base64,PHNjcmlwdD5jb25maXJtKGRvY3VtZW50LmRvbWFpbik7PC9zY3JpcHQ+"); + } + + private void testSamlSpecificUrls(boolean create, String... testUrls) { + ClientRepresentation rep; + if (create) { + rep = new ClientRepresentation(); + rep.setClientId("my-app2"); + rep.setEnabled(true); + rep.setProtocol(SamlProtocol.LOGIN_PROTOCOL); + } + else { + rep = createClient(SamlProtocol.LOGIN_PROTOCOL); + } + rep.setAttributes(new HashMap<>()); + + Map attrs = Map.of( + SamlProtocol.SAML_ASSERTION_CONSUMER_URL_POST_ATTRIBUTE, "Assertion Consumer Service POST Binding URL", + SamlProtocol.SAML_ASSERTION_CONSUMER_URL_REDIRECT_ATTRIBUTE, "Assertion Consumer Service Redirect Binding URL", + SamlProtocol.SAML_ASSERTION_CONSUMER_URL_ARTIFACT_ATTRIBUTE, "Artifact Binding URL", + SamlProtocol.SAML_SINGLE_LOGOUT_SERVICE_URL_POST_ATTRIBUTE, "Logout Service POST Binding URL", + SamlProtocol.SAML_SINGLE_LOGOUT_SERVICE_URL_ARTIFACT_ATTRIBUTE, "Logout Service ARTIFACT Binding URL", + SamlProtocol.SAML_SINGLE_LOGOUT_SERVICE_URL_REDIRECT_ATTRIBUTE, "Logout Service Redirect Binding URL", + SamlProtocol.SAML_SINGLE_LOGOUT_SERVICE_URL_SOAP_ATTRIBUTE, "Logout Service SOAP Binding URL", + SamlProtocol.SAML_ARTIFACT_RESOLUTION_SERVICE_URL_ATTRIBUTE, "Artifact Resolution Service"); + + for (String testUrl : testUrls) { + // admin url + rep.setAdminUrl(testUrl); + createOrUpdateClientExpectingValidationErrors(rep, create, "Master SAML Processing URL uses an illegal scheme"); + rep.setAdminUrl(null); + // attributes + for (Map.Entry entry : attrs.entrySet()) { + rep.getAttributes().put(entry.getKey(), testUrl); + createOrUpdateClientExpectingValidationErrors(rep, create, entry.getValue() + " uses an illegal scheme"); + rep.getAttributes().remove(entry.getKey()); + } + } + } + private void testClientUriValidation(String expectedRootUrlError, String expectedBaseUrlError, String expectedBackchannelLogoutUrlError, String expectedRedirectUrisError, String... testUrls) { testClientUriValidation(false, expectedRootUrlError, expectedBaseUrlError, expectedBackchannelLogoutUrlError, expectedRedirectUrisError, testUrls); testClientUriValidation(true, expectedRootUrlError, expectedBaseUrlError, expectedBackchannelLogoutUrlError, expectedRedirectUrisError, testUrls); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/InstallationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/InstallationTest.java index 92fe730a4759..2cd7ee7f62ca 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/InstallationTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/InstallationTest.java @@ -229,30 +229,30 @@ public void testSamlMetadataSpDescriptorPost() throws Exception { attrNamesAndValues.clear(); //fallback to adminUrl - updater.setAdminUrl("admin-url").update(); + updater.setAdminUrl("https://admin-url").update(); assertAdminEvents.assertEvent(getRealmId(), OperationType.UPDATE, AdminEventPaths.clientResourcePath(samlClientId), ResourceType.CLIENT); doc = getDocumentFromXmlString(updater.getResource().getInstallationProvider(SamlSPDescriptorClientInstallation.SAML_CLIENT_INSTALATION_SP_DESCRIPTOR)); attrNamesAndValues.put("Binding", JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.get()); - attrNamesAndValues.put("Location", "admin-url"); + attrNamesAndValues.put("Location", "https://admin-url"); assertElements(doc, METADATA_NSURI.get(), "SingleLogoutService", attrNamesAndValues); assertElements(doc, METADATA_NSURI.get(), "AssertionConsumerService", attrNamesAndValues); attrNamesAndValues.clear(); //fine grained - updater.setAttribute(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_POST_ATTRIBUTE, "saml-assertion-post-url") - .setAttribute(SamlProtocol.SAML_SINGLE_LOGOUT_SERVICE_URL_POST_ATTRIBUTE, "saml-logout-post-url") - .setAttribute(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_REDIRECT_ATTRIBUTE, "saml-assertion-redirect-url") - .setAttribute(SamlProtocol.SAML_SINGLE_LOGOUT_SERVICE_URL_REDIRECT_ATTRIBUTE, "saml-logout-redirect-url") + updater.setAttribute(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_POST_ATTRIBUTE, "https://saml-assertion-post-url") + .setAttribute(SamlProtocol.SAML_SINGLE_LOGOUT_SERVICE_URL_POST_ATTRIBUTE, "https://saml-logout-post-url") + .setAttribute(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_REDIRECT_ATTRIBUTE, "https://saml-assertion-redirect-url") + .setAttribute(SamlProtocol.SAML_SINGLE_LOGOUT_SERVICE_URL_REDIRECT_ATTRIBUTE, "https://saml-logout-redirect-url") .update(); assertAdminEvents.assertEvent(getRealmId(), OperationType.UPDATE, AdminEventPaths.clientResourcePath(samlClientId), ResourceType.CLIENT); doc = getDocumentFromXmlString(updater.getResource().getInstallationProvider(SamlSPDescriptorClientInstallation.SAML_CLIENT_INSTALATION_SP_DESCRIPTOR)); attrNamesAndValues.put("Binding", JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.get()); - attrNamesAndValues.put("Location", "saml-logout-post-url"); + attrNamesAndValues.put("Location", "https://saml-logout-post-url"); assertElements(doc, METADATA_NSURI.get(), "SingleLogoutService", attrNamesAndValues); attrNamesAndValues.clear(); attrNamesAndValues.put("Binding", JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.get()); - attrNamesAndValues.put("Location", "saml-assertion-post-url"); + attrNamesAndValues.put("Location", "https://saml-assertion-post-url"); assertElements(doc, METADATA_NSURI.get(), "AssertionConsumerService", attrNamesAndValues); } assertAdminEvents.assertEvent(getRealmId(), OperationType.UPDATE, AdminEventPaths.clientResourcePath(samlClientId), ResourceType.CLIENT); @@ -277,29 +277,29 @@ public void testSamlMetadataSpDescriptorRedirect() throws Exception { attrNamesAndValues.clear(); //fallback to adminUrl - updater.setAdminUrl("admin-url").update(); + updater.setAdminUrl("https://admin-url").update(); assertAdminEvents.assertEvent(getRealmId(), OperationType.UPDATE, AdminEventPaths.clientResourcePath(samlClientId), ResourceType.CLIENT); doc = getDocumentFromXmlString(updater.getResource().getInstallationProvider(SamlSPDescriptorClientInstallation.SAML_CLIENT_INSTALATION_SP_DESCRIPTOR)); attrNamesAndValues.put("Binding", JBossSAMLURIConstants.SAML_HTTP_REDIRECT_BINDING.get()); - attrNamesAndValues.put("Location", "admin-url"); + attrNamesAndValues.put("Location", "https://admin-url"); assertElements(doc, METADATA_NSURI.get(), "SingleLogoutService", attrNamesAndValues); assertElements(doc, METADATA_NSURI.get(), "AssertionConsumerService", attrNamesAndValues); attrNamesAndValues.clear(); //fine grained - updater.setAttribute(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_POST_ATTRIBUTE, "saml-assertion-post-url") - .setAttribute(SamlProtocol.SAML_SINGLE_LOGOUT_SERVICE_URL_POST_ATTRIBUTE, "saml-logout-post-url") - .setAttribute(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_REDIRECT_ATTRIBUTE, "saml-assertion-redirect-url") - .setAttribute(SamlProtocol.SAML_SINGLE_LOGOUT_SERVICE_URL_REDIRECT_ATTRIBUTE, "saml-logout-redirect-url") + updater.setAttribute(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_POST_ATTRIBUTE, "https://saml-assertion-post-url") + .setAttribute(SamlProtocol.SAML_SINGLE_LOGOUT_SERVICE_URL_POST_ATTRIBUTE, "https://saml-logout-post-url") + .setAttribute(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_REDIRECT_ATTRIBUTE, "https://saml-assertion-redirect-url") + .setAttribute(SamlProtocol.SAML_SINGLE_LOGOUT_SERVICE_URL_REDIRECT_ATTRIBUTE, "https://saml-logout-redirect-url") .update(); assertAdminEvents.assertEvent(getRealmId(), OperationType.UPDATE, AdminEventPaths.clientResourcePath(samlClientId), ResourceType.CLIENT); doc = getDocumentFromXmlString(updater.getResource().getInstallationProvider(SamlSPDescriptorClientInstallation.SAML_CLIENT_INSTALATION_SP_DESCRIPTOR)); attrNamesAndValues.put("Binding", JBossSAMLURIConstants.SAML_HTTP_REDIRECT_BINDING.get()); - attrNamesAndValues.put("Location", "saml-logout-redirect-url"); + attrNamesAndValues.put("Location", "https://saml-logout-redirect-url"); assertElements(doc, METADATA_NSURI.get(), "SingleLogoutService", attrNamesAndValues); attrNamesAndValues.clear(); attrNamesAndValues.put("Binding", JBossSAMLURIConstants.SAML_HTTP_REDIRECT_BINDING.get()); - attrNamesAndValues.put("Location", "saml-assertion-redirect-url"); + attrNamesAndValues.put("Location", "https://saml-assertion-redirect-url"); assertElements(doc, METADATA_NSURI.get(), "AssertionConsumerService", attrNamesAndValues); } assertAdminEvents.assertEvent(getRealmId(), OperationType.UPDATE, AdminEventPaths.clientResourcePath(samlClientId), ResourceType.CLIENT); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/ClientRegistrationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/ClientRegistrationTest.java index 924cf96dd94e..8a01c462f580 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/ClientRegistrationTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/ClientRegistrationTest.java @@ -36,6 +36,8 @@ import org.keycloak.models.Constants; import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper; +import org.keycloak.protocol.oidc.OIDCLoginProtocol; +import org.keycloak.protocol.saml.SamlProtocol; import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.representations.idm.OAuth2ErrorRepresentation; import org.keycloak.representations.idm.ProtocolMapperRepresentation; @@ -52,7 +54,9 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.HashSet; import java.util.Set; @@ -70,7 +74,6 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import org.keycloak.protocol.oidc.OIDCLoginProtocol; import static org.keycloak.services.clientregistration.ErrorCodes.INVALID_CLIENT_METADATA; import static org.keycloak.services.clientregistration.ErrorCodes.INVALID_REDIRECT_URI; import static org.keycloak.utils.MediaType.APPLICATION_JSON; @@ -273,6 +276,48 @@ public void testFragmentProhibitedClientValidation() { ); } + @Test + public void testSamlSpecificUrls() throws ClientRegistrationException { + testSamlSpecificUrls(true, "javascript:alert('TEST')", "data:text/html;base64,PHNjcmlwdD5jb25maXJtKGRvY3VtZW50LmRvbWFpbik7PC9zY3JpcHQ+"); + testSamlSpecificUrls(false, "javascript:alert('TEST')", "data:text/html;base64,PHNjcmlwdD5jb25maXJtKGRvY3VtZW50LmRvbWFpbik7PC9zY3JpcHQ+"); + } + + private void testSamlSpecificUrls(boolean register, String... testUrls) throws ClientRegistrationException { + ClientRepresentation rep = buildClient(); + rep.setProtocol(SamlProtocol.LOGIN_PROTOCOL); + if (register) { + authCreateClients(); + } else { + authManageClients(); + registerClient(rep); + rep = reg.get(CLIENT_ID); + } + rep.setAttributes(new HashMap<>()); + + Map attrs = Map.of( + SamlProtocol.SAML_ASSERTION_CONSUMER_URL_POST_ATTRIBUTE, "Assertion Consumer Service POST Binding URL", + SamlProtocol.SAML_ASSERTION_CONSUMER_URL_REDIRECT_ATTRIBUTE, "Assertion Consumer Service Redirect Binding URL", + SamlProtocol.SAML_ASSERTION_CONSUMER_URL_ARTIFACT_ATTRIBUTE, "Artifact Binding URL", + SamlProtocol.SAML_SINGLE_LOGOUT_SERVICE_URL_POST_ATTRIBUTE, "Logout Service POST Binding URL", + SamlProtocol.SAML_SINGLE_LOGOUT_SERVICE_URL_ARTIFACT_ATTRIBUTE, "Logout Service ARTIFACT Binding URL", + SamlProtocol.SAML_SINGLE_LOGOUT_SERVICE_URL_REDIRECT_ATTRIBUTE, "Logout Service Redirect Binding URL", + SamlProtocol.SAML_SINGLE_LOGOUT_SERVICE_URL_SOAP_ATTRIBUTE, "Logout Service SOAP Binding URL", + SamlProtocol.SAML_ARTIFACT_RESOLUTION_SERVICE_URL_ATTRIBUTE, "Artifact Resolution Service"); + + for (String testUrl : testUrls) { + // admin url + rep.setAdminUrl(testUrl); + registerOrUpdateClientExpectingValidationErrors(rep, register, false, "Master SAML Processing URL uses an illegal scheme"); + rep.setAdminUrl(null); + // attributes + for (Map.Entry entry : attrs.entrySet()) { + rep.getAttributes().put(entry.getKey(), testUrl); + registerOrUpdateClientExpectingValidationErrors(rep, register, false, entry.getValue() + " uses an illegal scheme"); + rep.getAttributes().remove(entry.getKey()); + } + } + } + @Test public void testUpdateAuthorizationSettings() throws ClientRegistrationException { authManageClients();