KEYCLOAK-14019 Improvements for request_uri parameter
(cherry picked from commit da38b36297a5bd9890f7df031696b516268d6cff)
This commit is contained in:
parent
acfea8ecd2
commit
eac3329d22
15 changed files with 214 additions and 4 deletions
|
@ -109,6 +109,9 @@ public class OIDCConfigurationRepresentation {
|
||||||
@JsonProperty("request_uri_parameter_supported")
|
@JsonProperty("request_uri_parameter_supported")
|
||||||
private Boolean requestUriParameterSupported;
|
private Boolean requestUriParameterSupported;
|
||||||
|
|
||||||
|
@JsonProperty("require_request_uri_registration")
|
||||||
|
private Boolean requireRequestUriRegistration;
|
||||||
|
|
||||||
// KEYCLOAK-7451 OAuth Authorization Server Metadata for Proof Key for Code Exchange
|
// KEYCLOAK-7451 OAuth Authorization Server Metadata for Proof Key for Code Exchange
|
||||||
@JsonProperty("code_challenge_methods_supported")
|
@JsonProperty("code_challenge_methods_supported")
|
||||||
private List<String> codeChallengeMethodsSupported;
|
private List<String> codeChallengeMethodsSupported;
|
||||||
|
@ -343,6 +346,14 @@ public class OIDCConfigurationRepresentation {
|
||||||
this.requestUriParameterSupported = requestUriParameterSupported;
|
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
|
// KEYCLOAK-7451 OAuth Authorization Server Metadata for Proof Key for Code Exchange
|
||||||
public List<String> getCodeChallengeMethodsSupported() {
|
public List<String> getCodeChallengeMethodsSupported() {
|
||||||
return codeChallengeMethodsSupported;
|
return codeChallengeMethodsSupported;
|
||||||
|
|
|
@ -20,9 +20,13 @@ package org.keycloak.protocol.oidc;
|
||||||
import org.keycloak.authentication.authenticators.client.X509ClientAuthenticator;
|
import org.keycloak.authentication.authenticators.client.X509ClientAuthenticator;
|
||||||
import org.keycloak.jose.jws.Algorithm;
|
import org.keycloak.jose.jws.Algorithm;
|
||||||
import org.keycloak.models.ClientModel;
|
import org.keycloak.models.ClientModel;
|
||||||
|
import org.keycloak.models.Constants;
|
||||||
import org.keycloak.representations.idm.ClientRepresentation;
|
import org.keycloak.representations.idm.ClientRepresentation;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
@ -79,6 +83,14 @@ public class OIDCAdvancedConfigWrapper {
|
||||||
setAttribute(OIDCConfigAttributes.REQUEST_OBJECT_REQUIRED, requestObjectRequired);
|
setAttribute(OIDCConfigAttributes.REQUEST_OBJECT_REQUIRED, requestObjectRequired);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<String> getRequestUris() {
|
||||||
|
return getAttributeMultivalued(OIDCConfigAttributes.REQUEST_URIS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRequestUris(List<String> requestUris) {
|
||||||
|
setAttributeMultivalued(OIDCConfigAttributes.REQUEST_URIS, requestUris);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isUseJwksUrl() {
|
public boolean isUseJwksUrl() {
|
||||||
String useJwksUrl = getAttribute(OIDCConfigAttributes.USE_JWKS_URL);
|
String useJwksUrl = getAttribute(OIDCConfigAttributes.USE_JWKS_URL);
|
||||||
return Boolean.parseBoolean(useJwksUrl);
|
return Boolean.parseBoolean(useJwksUrl);
|
||||||
|
@ -244,4 +256,20 @@ public class OIDCAdvancedConfigWrapper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<String> 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<String> attrValues) {
|
||||||
|
if (attrValues == null || attrValues.size() == 0) {
|
||||||
|
// Remove attribute
|
||||||
|
setAttribute(attrKey, null);
|
||||||
|
} else {
|
||||||
|
String attrValueFull = String.join(Constants.CFG_DELIMITER, attrValues);
|
||||||
|
setAttribute(attrKey, attrValueFull);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 = "request only";
|
||||||
public static final String REQUEST_OBJECT_REQUIRED_REQUEST_URI = "request_uri 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 JWKS_URL = "jwks.url";
|
||||||
|
|
||||||
public static final String USE_JWKS_URL = "use.jwks.url";
|
public static final String USE_JWKS_URL = "use.jwks.url";
|
||||||
|
|
|
@ -133,6 +133,7 @@ public class OIDCWellKnownProvider implements WellKnownProvider {
|
||||||
|
|
||||||
config.setRequestParameterSupported(true);
|
config.setRequestParameterSupported(true);
|
||||||
config.setRequestUriParameterSupported(true);
|
config.setRequestUriParameterSupported(true);
|
||||||
|
config.setRequireRequestUriRegistration(true);
|
||||||
|
|
||||||
// KEYCLOAK-7451 OAuth Authorization Server Metadata for Proof Key for Code Exchange
|
// KEYCLOAK-7451 OAuth Authorization Server Metadata for Proof Key for Code Exchange
|
||||||
config.setCodeChallengeMethodsSupported(DEFAULT_CODE_CHALLENGE_METHODS_SUPPORTED);
|
config.setCodeChallengeMethodsSupported(DEFAULT_CODE_CHALLENGE_METHODS_SUPPORTED);
|
||||||
|
|
|
@ -26,6 +26,7 @@ import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper;
|
import org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper;
|
||||||
import org.keycloak.protocol.oidc.OIDCConfigAttributes;
|
import org.keycloak.protocol.oidc.OIDCConfigAttributes;
|
||||||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||||
|
import org.keycloak.protocol.oidc.utils.RedirectUtils;
|
||||||
import org.keycloak.services.ErrorPageException;
|
import org.keycloak.services.ErrorPageException;
|
||||||
import org.keycloak.services.ServicesLogger;
|
import org.keycloak.services.ServicesLogger;
|
||||||
import org.keycloak.services.messages.Messages;
|
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.MultivaluedMap;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -75,7 +77,14 @@ public class AuthorizationEndpointRequestParserProcessor {
|
||||||
if (requestParam != null) {
|
if (requestParam != null) {
|
||||||
new AuthzEndpointRequestObjectParser(session, requestParam, client).parseRequest(request);
|
new AuthzEndpointRequestObjectParser(session, requestParam, client).parseRequest(request);
|
||||||
} else if (requestUriParam != null) {
|
} else if (requestUriParam != null) {
|
||||||
try (InputStream is = session.getProvider(HttpClientProvider.class).get(requestUriParam)) {
|
// Validate "requestUriParam" with allowed requestUris
|
||||||
|
List<String> 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);
|
String retrievedRequest = StreamUtil.readString(is);
|
||||||
new AuthzEndpointRequestObjectParser(session, retrievedRequest, client).parseRequest(request);
|
new AuthzEndpointRequestObjectParser(session, retrievedRequest, client).parseRequest(request);
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,7 +78,7 @@ public class RedirectUtils {
|
||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String verifyRedirectUri(KeycloakSession session, String rootUrl, String redirectUri, Set<String> validRedirects, boolean requireRedirectUri) {
|
public static String verifyRedirectUri(KeycloakSession session, String rootUrl, String redirectUri, Set<String> validRedirects, boolean requireRedirectUri) {
|
||||||
KeycloakUriInfo uriInfo = session.getContext().getUri();
|
KeycloakUriInfo uriInfo = session.getContext().getUri();
|
||||||
RealmModel realm = session.getContext().getRealm();
|
RealmModel realm = session.getContext().getRealm();
|
||||||
|
|
||||||
|
|
|
@ -142,6 +142,10 @@ public class DescriptionConverter {
|
||||||
configWrapper.setIdTokenEncryptedResponseEnc(clientOIDC.getIdTokenEncryptedResponseEnc());
|
configWrapper.setIdTokenEncryptedResponseEnc(clientOIDC.getIdTokenEncryptedResponseEnc());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (clientOIDC.getRequestUris() != null) {
|
||||||
|
configWrapper.setRequestUris(clientOIDC.getRequestUris());
|
||||||
|
}
|
||||||
|
|
||||||
configWrapper.setTokenEndpointAuthSigningAlg(clientOIDC.getTokenEndpointAuthSigningAlg());
|
configWrapper.setTokenEndpointAuthSigningAlg(clientOIDC.getTokenEndpointAuthSigningAlg());
|
||||||
|
|
||||||
configWrapper.setBackchannelLogoutUrl(clientOIDC.getBackchannelLogoutUri());
|
configWrapper.setBackchannelLogoutUrl(clientOIDC.getBackchannelLogoutUri());
|
||||||
|
@ -253,6 +257,9 @@ public class DescriptionConverter {
|
||||||
if (config.getIdTokenEncryptedResponseEnc() != null) {
|
if (config.getIdTokenEncryptedResponseEnc() != null) {
|
||||||
response.setIdTokenEncryptedResponseEnc(config.getIdTokenEncryptedResponseEnc());
|
response.setIdTokenEncryptedResponseEnc(config.getIdTokenEncryptedResponseEnc());
|
||||||
}
|
}
|
||||||
|
if (config.getRequestUris() != null) {
|
||||||
|
response.setRequestUris(config.getRequestUris());
|
||||||
|
}
|
||||||
if (config.getTokenEndpointAuthSigningAlg() != null) {
|
if (config.getTokenEndpointAuthSigningAlg() != null) {
|
||||||
response.setTokenEndpointAuthSigningAlg(config.getTokenEndpointAuthSigningAlg());
|
response.setTokenEndpointAuthSigningAlg(config.getTokenEndpointAuthSigningAlg());
|
||||||
}
|
}
|
||||||
|
|
|
@ -721,6 +721,7 @@ public class ClientPolicyBasicsTest extends AbstractKeycloakTest {
|
||||||
String clientSecret = "secret";
|
String clientSecret = "secret";
|
||||||
String cid = createClientByAdmin(clientId, (ClientRepresentation clientRep) -> {
|
String cid = createClientByAdmin(clientId, (ClientRepresentation clientRep) -> {
|
||||||
clientRep.setSecret(clientSecret);
|
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());
|
adminClient.realm(REALM_NAME).clients().get(cid).roles().create(RoleBuilder.create().name("sample-client-role").build());
|
||||||
|
|
||||||
|
|
|
@ -531,4 +531,21 @@ public class OIDCClientRegistrationTest extends AbstractClientRegistrationTest {
|
||||||
assertTrue(realmDefaultClientScopes.equals(new HashSet<>(registeredDefaultClientScopes)));
|
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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ import org.keycloak.admin.client.resource.UserResource;
|
||||||
import org.keycloak.authentication.authenticators.client.JWTClientAuthenticator;
|
import org.keycloak.authentication.authenticators.client.JWTClientAuthenticator;
|
||||||
import org.keycloak.common.Profile;
|
import org.keycloak.common.Profile;
|
||||||
import org.keycloak.common.util.Time;
|
import org.keycloak.common.util.Time;
|
||||||
|
import org.keycloak.common.util.UriUtils;
|
||||||
import org.keycloak.events.Details;
|
import org.keycloak.events.Details;
|
||||||
import org.keycloak.events.EventType;
|
import org.keycloak.events.EventType;
|
||||||
import org.keycloak.jose.jws.Algorithm;
|
import org.keycloak.jose.jws.Algorithm;
|
||||||
|
@ -121,7 +122,10 @@ public class OIDCAdvancedRequestParamsTest extends AbstractTestRealmKeycloakTest
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void clientConfiguration() {
|
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
|
* 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
|
* 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());
|
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
|
@Test
|
||||||
public void requestUriParamSigned() throws Exception {
|
public void requestUriParamSigned() throws Exception {
|
||||||
oauth.stateParamHardcoded("mystate3");
|
oauth.stateParamHardcoded("mystate3");
|
||||||
|
|
|
@ -152,6 +152,7 @@ public class OIDCWellKnownProviderTest extends AbstractKeycloakTest {
|
||||||
// Request and Request_Uri
|
// Request and Request_Uri
|
||||||
Assert.assertTrue(oidcConfig.getRequestParameterSupported());
|
Assert.assertTrue(oidcConfig.getRequestParameterSupported());
|
||||||
Assert.assertTrue(oidcConfig.getRequestUriParameterSupported());
|
Assert.assertTrue(oidcConfig.getRequestUriParameterSupported());
|
||||||
|
Assert.assertTrue(oidcConfig.getRequireRequestUriRegistration());
|
||||||
|
|
||||||
// KEYCLOAK-7451 OAuth Authorization Server Metadata for Proof Key for Code Exchange
|
// KEYCLOAK-7451 OAuth Authorization Server Metadata for Proof Key for Code Exchange
|
||||||
// PKCE support
|
// PKCE support
|
||||||
|
|
|
@ -2,11 +2,14 @@ package org.keycloak.testsuite.util;
|
||||||
|
|
||||||
import org.keycloak.admin.client.resource.ClientResource;
|
import org.keycloak.admin.client.resource.ClientResource;
|
||||||
import org.keycloak.admin.client.resource.RealmResource;
|
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.ClientRepresentation;
|
||||||
import org.keycloak.representations.idm.ProtocolMapperRepresentation;
|
import org.keycloak.representations.idm.ProtocolMapperRepresentation;
|
||||||
import org.keycloak.representations.idm.RoleRepresentation;
|
import org.keycloak.representations.idm.RoleRepresentation;
|
||||||
import org.keycloak.representations.idm.UserRepresentation;
|
import org.keycloak.representations.idm.UserRepresentation;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
|
@ -68,10 +71,11 @@ public class ClientManager {
|
||||||
clientResource.update(app);
|
clientResource.update(app);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void directAccessGrant(Boolean enable) {
|
public ClientManagerBuilder directAccessGrant(Boolean enable) {
|
||||||
ClientRepresentation app = clientResource.toRepresentation();
|
ClientRepresentation app = clientResource.toRepresentation();
|
||||||
app.setDirectAccessGrantsEnabled(enable);
|
app.setDirectAccessGrantsEnabled(enable);
|
||||||
clientResource.update(app);
|
clientResource.update(app);
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClientManagerBuilder standardFlow(Boolean enable) {
|
public ClientManagerBuilder standardFlow(Boolean enable) {
|
||||||
|
@ -158,6 +162,13 @@ public class ClientManager {
|
||||||
clientResource.update(app);
|
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() {
|
public UserRepresentation getServiceAccountUser() {
|
||||||
return clientResource.getServiceAccountUser();
|
return clientResource.getServiceAccountUser();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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-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=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-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=Fine Grain SAML Endpoint Configuration
|
||||||
fine-saml-endpoint-conf.tooltip=Expand this section to configure exact URLs for Assertion Consumer and Single Logout Service.
|
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
|
assertion-consumer-post-binding-url=Assertion Consumer Service POST Binding URL
|
||||||
|
|
|
@ -1319,6 +1319,13 @@ module.controller('ClientDetailCtrl', function($scope, realm, client, flows, $ro
|
||||||
$scope.backchannelLogoutRevokeOfflineSessions = false;
|
$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) {
|
if (!$scope.create) {
|
||||||
|
@ -1456,6 +1463,9 @@ module.controller('ClientDetailCtrl', function($scope, realm, client, flows, $ro
|
||||||
if ($scope.newWebOrigin && $scope.newWebOrigin.length > 0) {
|
if ($scope.newWebOrigin && $scope.newWebOrigin.length > 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if ($scope.newRequestUri && $scope.newRequestUri.length > 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1543,6 +1553,10 @@ module.controller('ClientDetailCtrl', function($scope, realm, client, flows, $ro
|
||||||
$scope.changed = isChanged();
|
$scope.changed = isChanged();
|
||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
|
$scope.$watch('newRequestUri', function() {
|
||||||
|
$scope.changed = isChanged();
|
||||||
|
}, true);
|
||||||
|
|
||||||
$scope.deleteWebOrigin = function(index) {
|
$scope.deleteWebOrigin = function(index) {
|
||||||
$scope.clientEdit.webOrigins.splice(index, 1);
|
$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.clientEdit.webOrigins.push($scope.newWebOrigin);
|
||||||
$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.deleteRedirectUri = function(index) {
|
||||||
$scope.clientEdit.redirectUris.splice(index, 1);
|
$scope.clientEdit.redirectUris.splice(index, 1);
|
||||||
}
|
}
|
||||||
|
@ -1568,6 +1589,16 @@ module.controller('ClientDetailCtrl', function($scope, realm, client, flows, $ro
|
||||||
$scope.addWebOrigin();
|
$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) {
|
if ($scope.samlServerSignature == true) {
|
||||||
$scope.clientEdit.attributes["saml.server.signature"] = "true";
|
$scope.clientEdit.attributes["saml.server.signature"] = "true";
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -518,6 +518,25 @@
|
||||||
</div>
|
</div>
|
||||||
<kc-tooltip>{{:: 'request-object-required.tooltip' | translate}}</kc-tooltip>
|
<kc-tooltip>{{:: 'request-object-required.tooltip' | translate}}</kc-tooltip>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group clearfix block" data-ng-show="protocol == 'openid-connect'">
|
||||||
|
<label class="col-md-2 control-label" for="newRequestUri">{{:: 'request-uris' | translate}}</label>
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<div class="input-group" ng-repeat="(i, requestUri) in clientEdit.requestUris track by $index">
|
||||||
|
<input class="form-control" ng-model="clientEdit.requestUris[i]">
|
||||||
|
<div class="input-group-btn">
|
||||||
|
<button class="btn btn-default" type="button" data-ng-click="deleteRequestUri($index)"><span class="fa fa-minus"></span></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="input-group">
|
||||||
|
<input class="form-control" ng-model="newRequestUri" id="newRequestUri">
|
||||||
|
<div class="input-group-btn">
|
||||||
|
<button class="btn btn-default" type="button" data-ng-click="newRequestUri.length > 0 && addRequestUri()"><span class="fa fa-plus"></span></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<kc-tooltip>{{:: 'request-uris.tooltip' | translate}}</kc-tooltip>
|
||||||
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<fieldset data-ng-show="protocol == 'openid-connect'">
|
<fieldset data-ng-show="protocol == 'openid-connect'">
|
||||||
|
|
Loading…
Reference in a new issue