[KEYCLOAK-12511] - Mapper not visible in client's mapper list
This commit is contained in:
parent
fea7b4e031
commit
03bbf77b35
12 changed files with 147 additions and 21 deletions
|
@ -295,7 +295,7 @@ public class AuthorizationTokenService {
|
|||
AuthenticationManager.setClientScopesInSession(authSession);
|
||||
clientSessionCtx = TokenManager.attachAuthenticationSession(keycloakSession, userSessionModel, authSession);
|
||||
} else {
|
||||
clientSessionCtx = DefaultClientSessionContext.fromClientSessionScopeParameter(clientSession);
|
||||
clientSessionCtx = DefaultClientSessionContext.fromClientSessionScopeParameter(clientSession, keycloakSession);
|
||||
}
|
||||
|
||||
TokenManager tokenManager = request.getTokenManager();
|
||||
|
|
|
@ -124,7 +124,7 @@ public class KeycloakIdentity implements Identity {
|
|||
ClientModel client = realm.getClientByClientId(token.getIssuedFor());
|
||||
AuthenticatedClientSessionModel clientSessionModel = userSession.getAuthenticatedClientSessions().get(client.getId());
|
||||
|
||||
ClientSessionContext clientSessionCtx = DefaultClientSessionContext.fromClientSessionScopeParameter(clientSessionModel);
|
||||
ClientSessionContext clientSessionCtx = DefaultClientSessionContext.fromClientSessionScopeParameter(clientSessionModel, keycloakSession);
|
||||
this.accessToken = new TokenManager().createClientAccessToken(keycloakSession, realm, client, userSession.getUser(), userSession, clientSessionCtx);
|
||||
}
|
||||
|
||||
|
|
|
@ -148,4 +148,7 @@ public class ProtocolMapperUtils {
|
|||
return priority;
|
||||
}
|
||||
|
||||
public static boolean isEnabled(KeycloakSession session, ProtocolMapperModel mapper) {
|
||||
return session.getKeycloakSessionFactory().getProviderFactory(ProtocolMapper.class, mapper.getProtocolMapper()) != null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -181,7 +181,7 @@ public class TokenManager {
|
|||
MigrationUtils.migrateOldOfflineToken(session, realm, client, user);
|
||||
}
|
||||
|
||||
ClientSessionContext clientSessionCtx = DefaultClientSessionContext.fromClientSessionAndScopeParameter(clientSession, oldTokenScope);
|
||||
ClientSessionContext clientSessionCtx = DefaultClientSessionContext.fromClientSessionAndScopeParameter(clientSession, oldTokenScope, session);
|
||||
|
||||
// Check user didn't revoke granted consent
|
||||
if (!verifyConsentStillAvailable(session, user, client, clientSessionCtx.getClientScopes())) {
|
||||
|
@ -441,7 +441,7 @@ public class TokenManager {
|
|||
// Remove authentication session now
|
||||
new AuthenticationSessionManager(session).removeAuthenticationSession(userSession.getRealm(), authSession, true);
|
||||
|
||||
ClientSessionContext clientSessionCtx = DefaultClientSessionContext.fromClientSessionAndClientScopeIds(clientSession, clientScopeIds);
|
||||
ClientSessionContext clientSessionCtx = DefaultClientSessionContext.fromClientSessionAndClientScopeIds(clientSession, clientScopeIds, session);
|
||||
return clientSessionCtx;
|
||||
}
|
||||
|
||||
|
|
|
@ -388,7 +388,7 @@ public class TokenEndpoint {
|
|||
throw new CorsErrorResponseException(cors, OAuthErrorException.INVALID_SCOPE, "Client no longer has requested consent from user", Response.Status.BAD_REQUEST);
|
||||
}
|
||||
|
||||
ClientSessionContext clientSessionCtx = DefaultClientSessionContext.fromClientSessionAndClientScopes(clientSession, clientScopes);
|
||||
ClientSessionContext clientSessionCtx = DefaultClientSessionContext.fromClientSessionAndClientScopes(clientSession, clientScopes, session);
|
||||
|
||||
// Set nonce as an attribute in the ClientSessionContext. Will be used for the token generation
|
||||
clientSessionCtx.setAttribute(OIDCLoginProtocol.NONCE_PARAM, codeData.getNonce());
|
||||
|
|
|
@ -194,7 +194,7 @@ public class UserInfoEndpoint {
|
|||
AuthenticatedClientSessionModel clientSession = userSession.getAuthenticatedClientSessionByClient(clientModel.getId());
|
||||
|
||||
// Retrieve by latest scope parameter
|
||||
ClientSessionContext clientSessionCtx = DefaultClientSessionContext.fromClientSessionScopeParameter(clientSession);
|
||||
ClientSessionContext clientSessionCtx = DefaultClientSessionContext.fromClientSessionScopeParameter(clientSession, session);
|
||||
|
||||
AccessToken userInfo = new AccessToken();
|
||||
tokenManager.transformUserInfoAccessToken(session, userInfo, userSession, clientSessionCtx);
|
||||
|
|
|
@ -273,7 +273,7 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
|
|||
RoleModel manageAccountRole = accountService.getRole(AccountRoles.MANAGE_ACCOUNT);
|
||||
|
||||
// Ensure user has role and client has "role scope" for this role
|
||||
ClientSessionContext ctx = DefaultClientSessionContext.fromClientSessionScopeParameter(clientSession);
|
||||
ClientSessionContext ctx = DefaultClientSessionContext.fromClientSessionScopeParameter(clientSession, session);
|
||||
Set<RoleModel> userAccountRoles = ctx.getRoles();
|
||||
|
||||
if (!userAccountRoles.contains(manageAccountRole)) {
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
package org.keycloak.services.resources.admin;
|
||||
|
||||
import static org.keycloak.protocol.ProtocolMapperUtils.isEnabled;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
@ -124,7 +126,7 @@ public class ClientScopeEvaluateResource {
|
|||
for (ClientScopeModel mapperContainer : clientScopes) {
|
||||
Set<ProtocolMapperModel> currentMappers = mapperContainer.getProtocolMappers();
|
||||
for (ProtocolMapperModel current : currentMappers) {
|
||||
if (current.getProtocol().equals(client.getProtocol())) {
|
||||
if (isEnabled(session, current) && current.getProtocol().equals(client.getProtocol())) {
|
||||
ProtocolMapperEvaluationRepresentation rep = new ProtocolMapperEvaluationRepresentation();
|
||||
rep.setMapperId(current.getId());
|
||||
rep.setMapperName(current.getName());
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
*/
|
||||
package org.keycloak.services.resources.admin;
|
||||
|
||||
import static org.keycloak.protocol.ProtocolMapperUtils.isEnabled;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.jboss.resteasy.annotations.cache.NoCache;
|
||||
import javax.ws.rs.NotFoundException;
|
||||
|
@ -102,7 +104,7 @@ public class ProtocolMappersResource {
|
|||
|
||||
List<ProtocolMapperRepresentation> mappers = new LinkedList<ProtocolMapperRepresentation>();
|
||||
for (ProtocolMapperModel mapper : client.getProtocolMappers()) {
|
||||
if (mapper.getProtocol().equals(protocol)) mappers.add(ModelToRepresentation.toRepresentation(mapper));
|
||||
if (isEnabled(session, mapper) && mapper.getProtocol().equals(protocol)) mappers.add(ModelToRepresentation.toRepresentation(mapper));
|
||||
}
|
||||
return mappers;
|
||||
}
|
||||
|
@ -166,7 +168,9 @@ public class ProtocolMappersResource {
|
|||
|
||||
List<ProtocolMapperRepresentation> mappers = new LinkedList<ProtocolMapperRepresentation>();
|
||||
for (ProtocolMapperModel mapper : client.getProtocolMappers()) {
|
||||
mappers.add(ModelToRepresentation.toRepresentation(mapper));
|
||||
if (isEnabled(session, mapper)) {
|
||||
mappers.add(ModelToRepresentation.toRepresentation(mapper));
|
||||
}
|
||||
}
|
||||
return mappers;
|
||||
}
|
||||
|
|
|
@ -28,11 +28,13 @@ import org.keycloak.models.AuthenticatedClientSessionModel;
|
|||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.ClientScopeModel;
|
||||
import org.keycloak.models.ClientSessionContext;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ProtocolMapperModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.models.utils.RoleUtils;
|
||||
import org.keycloak.protocol.ProtocolMapperUtils;
|
||||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||
import org.keycloak.protocol.oidc.TokenManager;
|
||||
import org.keycloak.util.TokenUtil;
|
||||
|
@ -48,6 +50,7 @@ public class DefaultClientSessionContext implements ClientSessionContext {
|
|||
|
||||
private final AuthenticatedClientSessionModel clientSession;
|
||||
private final Set<String> clientScopeIds;
|
||||
private final KeycloakSession session;
|
||||
|
||||
private Set<ClientScopeModel> clientScopes;
|
||||
|
||||
|
@ -60,38 +63,39 @@ public class DefaultClientSessionContext implements ClientSessionContext {
|
|||
|
||||
private Map<String, Object> attributes = new HashMap<>();
|
||||
|
||||
private DefaultClientSessionContext(AuthenticatedClientSessionModel clientSession, Set<String> clientScopeIds) {
|
||||
private DefaultClientSessionContext(AuthenticatedClientSessionModel clientSession, Set<String> clientScopeIds, KeycloakSession session) {
|
||||
this.clientSession = clientSession;
|
||||
this.clientScopeIds = clientScopeIds;
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Useful if we want to "re-compute" client scopes based on the scope parameter
|
||||
*/
|
||||
public static DefaultClientSessionContext fromClientSessionScopeParameter(AuthenticatedClientSessionModel clientSession) {
|
||||
return fromClientSessionAndScopeParameter(clientSession, clientSession.getNote(OAuth2Constants.SCOPE));
|
||||
public static DefaultClientSessionContext fromClientSessionScopeParameter(AuthenticatedClientSessionModel clientSession, KeycloakSession session) {
|
||||
return fromClientSessionAndScopeParameter(clientSession, clientSession.getNote(OAuth2Constants.SCOPE), session);
|
||||
}
|
||||
|
||||
|
||||
public static DefaultClientSessionContext fromClientSessionAndScopeParameter(AuthenticatedClientSessionModel clientSession, String scopeParam) {
|
||||
public static DefaultClientSessionContext fromClientSessionAndScopeParameter(AuthenticatedClientSessionModel clientSession, String scopeParam, KeycloakSession session) {
|
||||
Set<ClientScopeModel> requestedClientScopes = TokenManager.getRequestedClientScopes(scopeParam, clientSession.getClient());
|
||||
return fromClientSessionAndClientScopes(clientSession, requestedClientScopes);
|
||||
return fromClientSessionAndClientScopes(clientSession, requestedClientScopes, session);
|
||||
}
|
||||
|
||||
|
||||
public static DefaultClientSessionContext fromClientSessionAndClientScopeIds(AuthenticatedClientSessionModel clientSession, Set<String> clientScopeIds) {
|
||||
return new DefaultClientSessionContext(clientSession, clientScopeIds);
|
||||
public static DefaultClientSessionContext fromClientSessionAndClientScopeIds(AuthenticatedClientSessionModel clientSession, Set<String> clientScopeIds, KeycloakSession session) {
|
||||
return new DefaultClientSessionContext(clientSession, clientScopeIds, session);
|
||||
}
|
||||
|
||||
|
||||
public static DefaultClientSessionContext fromClientSessionAndClientScopes(AuthenticatedClientSessionModel clientSession, Set<ClientScopeModel> clientScopes) {
|
||||
public static DefaultClientSessionContext fromClientSessionAndClientScopes(AuthenticatedClientSessionModel clientSession, Set<ClientScopeModel> clientScopes, KeycloakSession session) {
|
||||
Set<String> clientScopeIds = new HashSet<>();
|
||||
for (ClientScopeModel clientScope : clientScopes) {
|
||||
clientScopeIds.add(clientScope.getId());
|
||||
}
|
||||
|
||||
return new DefaultClientSessionContext(clientSession, clientScopeIds);
|
||||
return new DefaultClientSessionContext(clientSession, clientScopeIds, session);
|
||||
}
|
||||
|
||||
|
||||
|
@ -261,7 +265,7 @@ public class DefaultClientSessionContext implements ClientSessionContext {
|
|||
for (ClientScopeModel clientScope : clientScopes) {
|
||||
Set<ProtocolMapperModel> currentMappers = clientScope.getProtocolMappers();
|
||||
for (ProtocolMapperModel currentMapper : currentMappers) {
|
||||
if (protocol.equals(currentMapper.getProtocol())) {
|
||||
if (protocol.equals(currentMapper.getProtocol()) && ProtocolMapperUtils.isEnabled(session, currentMapper)) {
|
||||
protocolMappers.add(currentMapper);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ package org.keycloak.testsuite.script;
|
|||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.keycloak.common.Profile.Feature.SCRIPTS;
|
||||
import static org.keycloak.common.Profile.Feature.UPLOAD_SCRIPTS;
|
||||
import static org.keycloak.testsuite.admin.ApiUtil.findClientResourceByClientId;
|
||||
import static org.keycloak.testsuite.arquillian.DeploymentTargetModifier.AUTH_SERVER_CURRENT;
|
||||
import static org.keycloak.testsuite.util.ProtocolMapperUtil.createScriptMapper;
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.keycloak.testsuite.script;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.keycloak.common.Profile.Feature.SCRIPTS;
|
||||
import static org.keycloak.testsuite.admin.ApiUtil.findClientResourceByClientId;
|
||||
import static org.keycloak.testsuite.arquillian.DeploymentTargetModifier.AUTH_SERVER_CURRENT;
|
||||
import static org.keycloak.testsuite.util.ProtocolMapperUtil.createScriptMapper;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.jboss.arquillian.container.test.api.Deployer;
|
||||
import org.jboss.arquillian.container.test.api.Deployment;
|
||||
import org.jboss.arquillian.container.test.api.TargetsContainer;
|
||||
import org.jboss.arquillian.test.api.ArquillianResource;
|
||||
import org.jboss.shrinkwrap.api.ShrinkWrap;
|
||||
import org.jboss.shrinkwrap.api.asset.StringAsset;
|
||||
import org.jboss.shrinkwrap.api.spec.JavaArchive;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.admin.client.resource.ClientResource;
|
||||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||
import org.keycloak.protocol.oidc.mappers.ScriptBasedOIDCProtocolMapper;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.representations.idm.ProtocolMapperRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.representations.provider.ScriptProviderDescriptor;
|
||||
import org.keycloak.testsuite.AbstractTestRealmKeycloakTest;
|
||||
import org.keycloak.testsuite.arquillian.annotation.EnableFeature;
|
||||
import org.keycloak.testsuite.util.ContainerAssume;
|
||||
import org.keycloak.testsuite.util.OAuthClient;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public class UndeployedScriptMapperNotAvailableTest extends AbstractTestRealmKeycloakTest {
|
||||
|
||||
private static final String SCRIPT_DEPLOYMENT_NAME = "scripts.jar";
|
||||
|
||||
@Deployment(name = SCRIPT_DEPLOYMENT_NAME, managed = false, testable = false)
|
||||
@TargetsContainer(AUTH_SERVER_CURRENT)
|
||||
public static JavaArchive deploy() throws IOException {
|
||||
ScriptProviderDescriptor representation = new ScriptProviderDescriptor();
|
||||
|
||||
representation.addMapper("My Mapper", "mapper-a.js");
|
||||
|
||||
return ShrinkWrap.create(JavaArchive.class, SCRIPT_DEPLOYMENT_NAME)
|
||||
.addAsManifestResource(new StringAsset(JsonSerialization.writeValueAsPrettyString(representation)),
|
||||
"keycloak-scripts.json")
|
||||
.addAsResource("scripts/mapper-example.js", "mapper-a.js");
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void verifyEnvironment() {
|
||||
ContainerAssume.assumeNotAuthServerUndertow();
|
||||
}
|
||||
|
||||
@ArquillianResource
|
||||
private Deployer deployer;
|
||||
|
||||
@Before
|
||||
public void configureFlows() {
|
||||
deployer.deploy(SCRIPT_DEPLOYMENT_NAME);
|
||||
}
|
||||
|
||||
@After
|
||||
public void onAfter() {
|
||||
deployer.undeploy(SCRIPT_DEPLOYMENT_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureTestRealm(RealmRepresentation testRealm) {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnableFeature(SCRIPTS)
|
||||
public void testMapperNotRecognizedWhenDisabled() throws Exception {
|
||||
ClientResource app = findClientResourceByClientId(adminClient.realm("test"), "test-app");
|
||||
|
||||
{
|
||||
ProtocolMapperRepresentation mapper = createScriptMapper("test-script-mapper1", "computed-via-script",
|
||||
"computed-via-script", "String", true, true, "'hello_' + user.username", false);
|
||||
|
||||
mapper.setProtocolMapper("script-mapper-a.js");
|
||||
|
||||
app.getProtocolMappers().createMapper(mapper).close();
|
||||
}
|
||||
|
||||
deployer.undeploy(SCRIPT_DEPLOYMENT_NAME);
|
||||
assertTrue(app.getProtocolMappers().getMappers().isEmpty());
|
||||
assertTrue(app.getProtocolMappers().getMappersPerProtocol(app.toRepresentation().getProtocol()).isEmpty());
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue