From eac3329d225a58b43b0bc97300423596063b33c1 Mon Sep 17 00:00:00 2001 From: mposolda Date: Thu, 7 Jan 2021 14:52:19 +0100 Subject: [PATCH] KEYCLOAK-14019 Improvements for request_uri parameter (cherry picked from commit da38b36297a5bd9890f7df031696b516268d6cff) --- .../OIDCConfigurationRepresentation.java | 11 +++ .../oidc/OIDCAdvancedConfigWrapper.java | 28 ++++++++ .../protocol/oidc/OIDCConfigAttributes.java | 2 + .../protocol/oidc/OIDCWellKnownProvider.java | 1 + ...izationEndpointRequestParserProcessor.java | 11 ++- .../protocol/oidc/utils/RedirectUtils.java | 2 +- .../oidc/DescriptionConverter.java | 7 ++ .../client/ClientPolicyBasicsTest.java | 1 + .../client/OIDCClientRegistrationTest.java | 17 +++++ .../oidc/OIDCAdvancedRequestParamsTest.java | 72 ++++++++++++++++++- .../oidc/OIDCWellKnownProviderTest.java | 1 + .../testsuite/util/ClientManager.java | 13 +++- .../messages/admin-messages_en.properties | 2 + .../admin/resources/js/controllers/clients.js | 31 ++++++++ .../resources/partials/client-detail.html | 19 +++++ 15 files changed, 214 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/org/keycloak/protocol/oidc/representations/OIDCConfigurationRepresentation.java b/core/src/main/java/org/keycloak/protocol/oidc/representations/OIDCConfigurationRepresentation.java index 175d348ecb..c9d10978fe 100755 --- a/core/src/main/java/org/keycloak/protocol/oidc/representations/OIDCConfigurationRepresentation.java +++ b/core/src/main/java/org/keycloak/protocol/oidc/representations/OIDCConfigurationRepresentation.java @@ -109,6 +109,9 @@ public class OIDCConfigurationRepresentation { @JsonProperty("request_uri_parameter_supported") private Boolean requestUriParameterSupported; + @JsonProperty("require_request_uri_registration") + private Boolean requireRequestUriRegistration; + // KEYCLOAK-7451 OAuth Authorization Server Metadata for Proof Key for Code Exchange @JsonProperty("code_challenge_methods_supported") private List codeChallengeMethodsSupported; @@ -343,6 +346,14 @@ public class OIDCConfigurationRepresentation { this.requestUriParameterSupported = requestUriParameterSupported; } + public Boolean getRequireRequestUriRegistration() { + return requireRequestUriRegistration; + } + + public void setRequireRequestUriRegistration(Boolean requireRequestUriRegistration) { + this.requireRequestUriRegistration = requireRequestUriRegistration; + } + // KEYCLOAK-7451 OAuth Authorization Server Metadata for Proof Key for Code Exchange public List getCodeChallengeMethodsSupported() { return codeChallengeMethodsSupported; diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OIDCAdvancedConfigWrapper.java b/services/src/main/java/org/keycloak/protocol/oidc/OIDCAdvancedConfigWrapper.java index b2323a8889..c8bfcbdf99 100644 --- a/services/src/main/java/org/keycloak/protocol/oidc/OIDCAdvancedConfigWrapper.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCAdvancedConfigWrapper.java @@ -20,9 +20,13 @@ package org.keycloak.protocol.oidc; import org.keycloak.authentication.authenticators.client.X509ClientAuthenticator; import org.keycloak.jose.jws.Algorithm; import org.keycloak.models.ClientModel; +import org.keycloak.models.Constants; import org.keycloak.representations.idm.ClientRepresentation; +import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; +import java.util.List; /** * @author Marek Posolda @@ -79,6 +83,14 @@ public class OIDCAdvancedConfigWrapper { setAttribute(OIDCConfigAttributes.REQUEST_OBJECT_REQUIRED, requestObjectRequired); } + public List getRequestUris() { + return getAttributeMultivalued(OIDCConfigAttributes.REQUEST_URIS); + } + + public void setRequestUris(List requestUris) { + setAttributeMultivalued(OIDCConfigAttributes.REQUEST_URIS, requestUris); + } + public boolean isUseJwksUrl() { String useJwksUrl = getAttribute(OIDCConfigAttributes.USE_JWKS_URL); return Boolean.parseBoolean(useJwksUrl); @@ -244,4 +256,20 @@ public class OIDCAdvancedConfigWrapper { } } } + + private List getAttributeMultivalued(String attrKey) { + String attrValue = getAttribute(attrKey); + if (attrValue == null) return Collections.emptyList(); + return Arrays.asList(Constants.CFG_DELIMITER_PATTERN.split(attrValue)); + } + + private void setAttributeMultivalued(String attrKey, List attrValues) { + if (attrValues == null || attrValues.size() == 0) { + // Remove attribute + setAttribute(attrKey, null); + } else { + String attrValueFull = String.join(Constants.CFG_DELIMITER, attrValues); + setAttribute(attrKey, attrValueFull); + } + } } diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OIDCConfigAttributes.java b/services/src/main/java/org/keycloak/protocol/oidc/OIDCConfigAttributes.java index 458b35a1b0..8d6897e048 100644 --- a/services/src/main/java/org/keycloak/protocol/oidc/OIDCConfigAttributes.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCConfigAttributes.java @@ -27,6 +27,8 @@ public final class OIDCConfigAttributes { public static final String REQUEST_OBJECT_REQUIRED_REQUEST = "request only"; public static final String REQUEST_OBJECT_REQUIRED_REQUEST_URI = "request_uri only"; + public static final String REQUEST_URIS = "request.uris"; + public static final String JWKS_URL = "jwks.url"; public static final String USE_JWKS_URL = "use.jwks.url"; diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProvider.java b/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProvider.java index 6c8de7a0d6..1cbda5116f 100755 --- a/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProvider.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProvider.java @@ -133,6 +133,7 @@ public class OIDCWellKnownProvider implements WellKnownProvider { config.setRequestParameterSupported(true); config.setRequestUriParameterSupported(true); + config.setRequireRequestUriRegistration(true); // KEYCLOAK-7451 OAuth Authorization Server Metadata for Proof Key for Code Exchange config.setCodeChallengeMethodsSupported(DEFAULT_CODE_CHALLENGE_METHODS_SUPPORTED); diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/request/AuthorizationEndpointRequestParserProcessor.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/request/AuthorizationEndpointRequestParserProcessor.java index 7f5befabba..de8253117c 100644 --- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/request/AuthorizationEndpointRequestParserProcessor.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/request/AuthorizationEndpointRequestParserProcessor.java @@ -26,6 +26,7 @@ import org.keycloak.models.KeycloakSession; import org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper; import org.keycloak.protocol.oidc.OIDCConfigAttributes; import org.keycloak.protocol.oidc.OIDCLoginProtocol; +import org.keycloak.protocol.oidc.utils.RedirectUtils; import org.keycloak.services.ErrorPageException; import org.keycloak.services.ServicesLogger; import org.keycloak.services.messages.Messages; @@ -33,6 +34,7 @@ import org.keycloak.services.messages.Messages; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; import java.io.InputStream; +import java.util.HashSet; import java.util.List; /** @@ -75,7 +77,14 @@ public class AuthorizationEndpointRequestParserProcessor { if (requestParam != null) { new AuthzEndpointRequestObjectParser(session, requestParam, client).parseRequest(request); } else if (requestUriParam != null) { - try (InputStream is = session.getProvider(HttpClientProvider.class).get(requestUriParam)) { + // Validate "requestUriParam" with allowed requestUris + List requestUris = OIDCAdvancedConfigWrapper.fromClientModel(client).getRequestUris(); + String requestUri = RedirectUtils.verifyRedirectUri(session, client.getRootUrl(), requestUriParam, new HashSet<>(requestUris), false); + if (requestUri == null) { + throw new RuntimeException("Specified 'request_uri' not allowed for this client."); + } + + try (InputStream is = session.getProvider(HttpClientProvider.class).get(requestUri)) { String retrievedRequest = StreamUtil.readString(is); new AuthzEndpointRequestObjectParser(session, retrievedRequest, client).parseRequest(request); } diff --git a/services/src/main/java/org/keycloak/protocol/oidc/utils/RedirectUtils.java b/services/src/main/java/org/keycloak/protocol/oidc/utils/RedirectUtils.java index d05c3a1628..b192e50d00 100644 --- a/services/src/main/java/org/keycloak/protocol/oidc/utils/RedirectUtils.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/utils/RedirectUtils.java @@ -78,7 +78,7 @@ public class RedirectUtils { .collect(Collectors.toSet()); } - private static String verifyRedirectUri(KeycloakSession session, String rootUrl, String redirectUri, Set validRedirects, boolean requireRedirectUri) { + public static String verifyRedirectUri(KeycloakSession session, String rootUrl, String redirectUri, Set validRedirects, boolean requireRedirectUri) { KeycloakUriInfo uriInfo = session.getContext().getUri(); RealmModel realm = session.getContext().getRealm(); diff --git a/services/src/main/java/org/keycloak/services/clientregistration/oidc/DescriptionConverter.java b/services/src/main/java/org/keycloak/services/clientregistration/oidc/DescriptionConverter.java index 1d44b460b5..9ef1a467d5 100644 --- a/services/src/main/java/org/keycloak/services/clientregistration/oidc/DescriptionConverter.java +++ b/services/src/main/java/org/keycloak/services/clientregistration/oidc/DescriptionConverter.java @@ -142,6 +142,10 @@ public class DescriptionConverter { configWrapper.setIdTokenEncryptedResponseEnc(clientOIDC.getIdTokenEncryptedResponseEnc()); } + if (clientOIDC.getRequestUris() != null) { + configWrapper.setRequestUris(clientOIDC.getRequestUris()); + } + configWrapper.setTokenEndpointAuthSigningAlg(clientOIDC.getTokenEndpointAuthSigningAlg()); configWrapper.setBackchannelLogoutUrl(clientOIDC.getBackchannelLogoutUri()); @@ -253,6 +257,9 @@ public class DescriptionConverter { if (config.getIdTokenEncryptedResponseEnc() != null) { response.setIdTokenEncryptedResponseEnc(config.getIdTokenEncryptedResponseEnc()); } + if (config.getRequestUris() != null) { + response.setRequestUris(config.getRequestUris()); + } if (config.getTokenEndpointAuthSigningAlg() != null) { response.setTokenEndpointAuthSigningAlg(config.getTokenEndpointAuthSigningAlg()); } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/ClientPolicyBasicsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/ClientPolicyBasicsTest.java index a9fededbaa..5bf4ebfd7f 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/ClientPolicyBasicsTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/ClientPolicyBasicsTest.java @@ -721,6 +721,7 @@ public class ClientPolicyBasicsTest extends AbstractKeycloakTest { String clientSecret = "secret"; String cid = createClientByAdmin(clientId, (ClientRepresentation clientRep) -> { clientRep.setSecret(clientSecret); + OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setRequestUris(Arrays.asList(TestApplicationResourceUrls.clientRequestUri())); }); adminClient.realm(REALM_NAME).clients().get(cid).roles().create(RoleBuilder.create().name("sample-client-role").build()); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/OIDCClientRegistrationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/OIDCClientRegistrationTest.java index d5bc6b8ae7..85bf14c173 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/OIDCClientRegistrationTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/OIDCClientRegistrationTest.java @@ -531,4 +531,21 @@ public class OIDCClientRegistrationTest extends AbstractClientRegistrationTest { assertTrue(realmDefaultClientScopes.equals(new HashSet<>(registeredDefaultClientScopes))); } + + @Test + public void testRequestUris() throws Exception { + OIDCClientRepresentation clientRep = null; + OIDCClientRepresentation response = null; + + clientRep = createRep(); + clientRep.setRequestUris(Arrays.asList("http://host/foo", "https://host2/bar")); + + response = reg.oidc().create(clientRep); + Assert.assertNames(response.getRequestUris(), "http://host/foo", "https://host2/bar"); + + // Test Keycloak representation + ClientRepresentation kcClient = getClient(response.getClientId()); + OIDCAdvancedConfigWrapper config = OIDCAdvancedConfigWrapper.fromClientRepresentation(kcClient); + Assert.assertNames(config.getRequestUris(), "http://host/foo", "https://host2/bar"); + } } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/OIDCAdvancedRequestParamsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/OIDCAdvancedRequestParamsTest.java index c57c89115c..10a04ef168 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/OIDCAdvancedRequestParamsTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/OIDCAdvancedRequestParamsTest.java @@ -30,6 +30,7 @@ import org.keycloak.admin.client.resource.UserResource; import org.keycloak.authentication.authenticators.client.JWTClientAuthenticator; import org.keycloak.common.Profile; import org.keycloak.common.util.Time; +import org.keycloak.common.util.UriUtils; import org.keycloak.events.Details; import org.keycloak.events.EventType; import org.keycloak.jose.jws.Algorithm; @@ -121,7 +122,10 @@ public class OIDCAdvancedRequestParamsTest extends AbstractTestRealmKeycloakTest @Before public void clientConfiguration() { - ClientManager.realm(adminClient.realm("test")).clientId("test-app").directAccessGrant(true); + ClientManager.realm(adminClient.realm("test")).clientId("test-app") + .directAccessGrant(true) + .setRequestUris(TestApplicationResourceUrls.clientRequestUri()); + /* * Configure the default client ID. Seems like OAuthClient is keeping the state of clientID * For example: If some test case configure oauth.clientId("sample-public-client"), other tests @@ -786,6 +790,72 @@ public class OIDCAdvancedRequestParamsTest extends AbstractTestRealmKeycloakTest assertTrue(appPage.isCurrent()); } + @Test + public void requestUriParamWithAllowedRequestUris() throws Exception { + oauth.stateParamHardcoded("mystate1"); + String validRedirectUri = oauth.getRedirectUri(); + TestOIDCEndpointsApplicationResource oidcClientEndpointsResource = testingClient.testApp().oidcClientEndpoints(); + oidcClientEndpointsResource.setOIDCRequest("test", "test-app", validRedirectUri, "10", Algorithm.none.toString()); + ClientManager.ClientManagerBuilder clientMgrBuilder = ClientManager.realm(adminClient.realm("test")).clientId("test-app"); + + oauth.requestUri(TestApplicationResourceUrls.clientRequestUri()); + + // Test with the relative allowed request_uri - should pass + String absoluteRequestUri = TestApplicationResourceUrls.clientRequestUri(); + String requestUri = absoluteRequestUri.substring(UriUtils.getOrigin(absoluteRequestUri).length()); + clientMgrBuilder.setRequestUris(requestUri); + + oauth.openLoginForm(); + Assert.assertFalse(errorPage.isCurrent()); + loginPage.assertCurrent(); + + // Test with the relative and star at the end - should pass + requestUri = requestUri.replace("/get-oidc-request", "/*"); + clientMgrBuilder.setRequestUris(requestUri); + + oauth.openLoginForm(); + Assert.assertFalse(errorPage.isCurrent()); + loginPage.assertCurrent(); + + // Test absolute and wildcard at the end - should pass + requestUri = absoluteRequestUri.replace("/get-oidc-request", "/*"); + clientMgrBuilder.setRequestUris(requestUri); + + oauth.openLoginForm(); + Assert.assertFalse(errorPage.isCurrent()); + loginPage.assertCurrent(); + + // Test star only as wildcard - should pass + clientMgrBuilder.setRequestUris("*"); + + oauth.openLoginForm(); + Assert.assertFalse(errorPage.isCurrent()); + loginPage.assertCurrent(); + + // Test with multiple request_uris - should pass + clientMgrBuilder.setRequestUris("/foo", requestUri); + + oauth.openLoginForm(); + Assert.assertFalse(errorPage.isCurrent()); + loginPage.assertCurrent(); + + // Test invalid request_uris - should fail + clientMgrBuilder.setRequestUris("/foo", requestUri.replace("/*", "/foo")); + + oauth.openLoginForm(); + errorPage.assertCurrent(); + + // Test with no request_uri set at all - should fail + clientMgrBuilder.setRequestUris(); + + oauth.openLoginForm(); + errorPage.assertCurrent(); + + // Revert + clientMgrBuilder.setRequestUris(TestApplicationResourceUrls.clientRequestUri()); + + } + @Test public void requestUriParamSigned() throws Exception { oauth.stateParamHardcoded("mystate3"); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/OIDCWellKnownProviderTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/OIDCWellKnownProviderTest.java index c798ee0335..ddeccf9566 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/OIDCWellKnownProviderTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/OIDCWellKnownProviderTest.java @@ -152,6 +152,7 @@ public class OIDCWellKnownProviderTest extends AbstractKeycloakTest { // Request and Request_Uri Assert.assertTrue(oidcConfig.getRequestParameterSupported()); Assert.assertTrue(oidcConfig.getRequestUriParameterSupported()); + Assert.assertTrue(oidcConfig.getRequireRequestUriRegistration()); // KEYCLOAK-7451 OAuth Authorization Server Metadata for Proof Key for Code Exchange // PKCE support diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/ClientManager.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/ClientManager.java index 0848a227b0..7244795656 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/ClientManager.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/ClientManager.java @@ -2,11 +2,14 @@ package org.keycloak.testsuite.util; import org.keycloak.admin.client.resource.ClientResource; import org.keycloak.admin.client.resource.RealmResource; +import org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper; +import org.keycloak.protocol.oidc.OIDCConfigAttributes; import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.representations.idm.ProtocolMapperRepresentation; import org.keycloak.representations.idm.RoleRepresentation; import org.keycloak.representations.idm.UserRepresentation; +import java.util.Arrays; import java.util.Collections; import java.util.LinkedHashMap; import java.util.LinkedList; @@ -68,10 +71,11 @@ public class ClientManager { clientResource.update(app); } - public void directAccessGrant(Boolean enable) { + public ClientManagerBuilder directAccessGrant(Boolean enable) { ClientRepresentation app = clientResource.toRepresentation(); app.setDirectAccessGrantsEnabled(enable); clientResource.update(app); + return this; } public ClientManagerBuilder standardFlow(Boolean enable) { @@ -158,6 +162,13 @@ public class ClientManager { clientResource.update(app); } + // Set valid values of "request_uri" parameter + public void setRequestUris(String... requestUris) { + ClientRepresentation app = clientResource.toRepresentation(); + OIDCAdvancedConfigWrapper.fromClientRepresentation(app).setRequestUris(Arrays.asList(requestUris)); + clientResource.update(app); + } + public UserRepresentation getServiceAccountUser() { return clientResource.getServiceAccountUser(); } diff --git a/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties b/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties index 450f6ec547..50375a7307 100644 --- a/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties +++ b/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties @@ -387,6 +387,8 @@ request-object-signature-alg=Request Object Signature Algorithm request-object-signature-alg.tooltip=JWA algorithm, which client needs to use when sending OIDC request object specified by 'request' or 'request_uri' parameters. If set to 'any', Request object can be signed by any algorithm (including 'none' ). request-object-required=Request Object Required request-object-required.tooltip=Specifies if the client needs to provide a request object with their authorization requests, and what method they can use for this. If set to "not required", providing a request object is optional. In all other cases, providing a request object is mandatory. If set to "request", the request object must be provided by value. If set to "request_uri", the request object must be provided by reference. If set to "request or request_uri", either method can be used. +request-uris=Valid Request URIs +request-uris.tooltip=List of valid URIs, which can be used as values of 'request_uri' parameter during OpenID Connect authentication request. There is support for the same capabilities like for Valid Redirect URIs. For example wildcards or relative paths. fine-saml-endpoint-conf=Fine Grain SAML Endpoint Configuration fine-saml-endpoint-conf.tooltip=Expand this section to configure exact URLs for Assertion Consumer and Single Logout Service. assertion-consumer-post-binding-url=Assertion Consumer Service POST Binding URL diff --git a/themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js b/themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js index 731eb510a0..ee16d06706 100755 --- a/themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js +++ b/themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js @@ -1319,6 +1319,13 @@ module.controller('ClientDetailCtrl', function($scope, realm, client, flows, $ro $scope.backchannelLogoutRevokeOfflineSessions = false; } } + + + if ($scope.client.attributes["request.uris"] && $scope.client.attributes["request.uris"].length > 0) { + $scope.client.requestUris = $scope.client.attributes["request.uris"].split("##"); + } else { + $scope.client.requestUris = []; + } } if (!$scope.create) { @@ -1456,6 +1463,9 @@ module.controller('ClientDetailCtrl', function($scope, realm, client, flows, $ro if ($scope.newWebOrigin && $scope.newWebOrigin.length > 0) { return true; } + if ($scope.newRequestUri && $scope.newRequestUri.length > 0) { + return true; + } return false; } @@ -1543,6 +1553,10 @@ module.controller('ClientDetailCtrl', function($scope, realm, client, flows, $ro $scope.changed = isChanged(); }, true); + $scope.$watch('newRequestUri', function() { + $scope.changed = isChanged(); + }, true); + $scope.deleteWebOrigin = function(index) { $scope.clientEdit.webOrigins.splice(index, 1); } @@ -1550,6 +1564,13 @@ module.controller('ClientDetailCtrl', function($scope, realm, client, flows, $ro $scope.clientEdit.webOrigins.push($scope.newWebOrigin); $scope.newWebOrigin = ""; } + $scope.deleteRequestUri = function(index) { + $scope.clientEdit.requestUris.splice(index, 1); + } + $scope.addRequestUri = function() { + $scope.clientEdit.requestUris.push($scope.newRequestUri); + $scope.newRequestUri = ""; + } $scope.deleteRedirectUri = function(index) { $scope.clientEdit.redirectUris.splice(index, 1); } @@ -1568,6 +1589,16 @@ module.controller('ClientDetailCtrl', function($scope, realm, client, flows, $ro $scope.addWebOrigin(); } + if ($scope.newRequestUri && $scope.newRequestUri.length > 0) { + $scope.addRequestUri(); + } + if ($scope.clientEdit.requestUris && $scope.clientEdit.requestUris.length > 0) { + $scope.clientEdit.attributes["request.uris"] = $scope.clientEdit.requestUris.join("##"); + } else { + $scope.clientEdit.attributes["request.uris"] = null; + } + delete $scope.clientEdit.requestUris; + if ($scope.samlServerSignature == true) { $scope.clientEdit.attributes["saml.server.signature"] = "true"; } else { diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html b/themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html index 0a8e99680a..e5cd2d09b7 100755 --- a/themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html +++ b/themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html @@ -518,6 +518,25 @@ {{:: 'request-object-required.tooltip' | translate}} +
+ +
+
+ +
+ +
+
+ +
+ +
+ +
+
+
+ {{:: 'request-uris.tooltip' | translate}} +