KEYCLOAK-13306 Model fixes for check realm when lookup by ID

(cherry picked from commit e40a62de31f6f5d326234314a9e285010665f707)
This commit is contained in:
mposolda 2020-03-18 09:31:31 +01:00 committed by Hynek Mlnařík
parent 821405e175
commit b29810c923
4 changed files with 627 additions and 32 deletions

View file

@ -250,14 +250,17 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
}
protected UserSessionAdapter getUserSession(RealmModel realm, String id, boolean offline) {
UserSessionEntity entity = getUserSessionEntity(id, offline);
UserSessionEntity entity = getUserSessionEntity(realm, id, offline);
return wrap(realm, entity, offline);
}
private UserSessionEntity getUserSessionEntity(String id, boolean offline) {
private UserSessionEntity getUserSessionEntity(RealmModel realm, String id, boolean offline) {
InfinispanChangelogBasedTransaction<String, UserSessionEntity> tx = getTransaction(offline);
SessionEntityWrapper<UserSessionEntity> entityWrapper = tx.get(id);
return entityWrapper==null ? null : entityWrapper.getEntity();
if (entityWrapper==null) return null;
UserSessionEntity entity = entityWrapper.getEntity();
if (!entity.getRealmId().equals(realm.getId())) return null;
return entity;
}
@ -455,7 +458,7 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
@Override
public void removeUserSession(RealmModel realm, UserSessionModel session) {
UserSessionEntity entity = getUserSessionEntity(session, false);
UserSessionEntity entity = getUserSessionEntity(realm, session, false);
if (entity != null) {
removeUserSession(entity, false);
}
@ -801,11 +804,12 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
return entity != null ? new UserLoginFailureAdapter(this, key, entity) : null;
}
UserSessionEntity getUserSessionEntity(UserSessionModel userSession, boolean offline) {
UserSessionEntity getUserSessionEntity(RealmModel realm, UserSessionModel userSession, boolean offline) {
if (userSession instanceof UserSessionAdapter) {
if (!userSession.getRealm().equals(realm)) return null;
return ((UserSessionAdapter) userSession).getEntity();
} else {
return getUserSessionEntity(userSession.getId(), offline);
return getUserSessionEntity(realm, userSession.getId(), offline);
}
}
@ -829,7 +833,7 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
@Override
public void removeOfflineUserSession(RealmModel realm, UserSessionModel userSession) {
UserSessionEntity userSessionEntity = getUserSessionEntity(userSession, true);
UserSessionEntity userSessionEntity = getUserSessionEntity(realm, userSession, true);
if (userSessionEntity != null) {
removeUserSession(userSessionEntity, true);
}

View file

@ -364,6 +364,10 @@ public class JpaRealmProvider implements RealmProvider {
container.removeDefaultRoles(role.getName());
}
RoleEntity roleEntity = em.getReference(RoleEntity.class, role.getId());
if (roleEntity == null || !roleEntity.getRealmId().equals(realm.getId())) {
// Throw model exception to ensure transaction rollback and revert previous operations (removing default roles) as well
throw new ModelException("Role not found or trying to remove role from incorrect realm");
}
String compositeRoleTable = JpaUtils.getTableNameForNativeQuery("COMPOSITE_ROLE", em);
em.createNativeQuery("delete from " + compositeRoleTable + " where CHILD_ROLE = :role").setParameter("role", roleEntity).executeUpdate();
realm.getClients().forEach(c -> c.deleteScopeMapping(role));
@ -786,21 +790,19 @@ public class JpaRealmProvider implements RealmProvider {
@Override
public ClientInitialAccessModel getClientInitialAccessModel(RealmModel realm, String id) {
ClientInitialAccessEntity entity = em.find(ClientInitialAccessEntity.class, id);
if (entity == null) {
return null;
} else {
if (entity == null) return null;
if (!entity.getRealm().getId().equals(realm.getId())) return null;
return entityToModel(entity);
}
}
@Override
public void removeClientInitialAccessModel(RealmModel realm, String id) {
ClientInitialAccessEntity entity = em.find(ClientInitialAccessEntity.class, id, LockModeType.PESSIMISTIC_WRITE);
if (entity != null) {
if (entity == null) return;
if (!entity.getRealm().getId().equals(realm.getId())) return;
em.remove(entity);
em.flush();
}
}
@Override
public List<ClientInitialAccessModel> listClientInitialAccess(RealmModel realm) {

View file

@ -1651,7 +1651,7 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
@Override
public AuthenticationFlowModel getAuthenticationFlowById(String id) {
AuthenticationFlowEntity entity = em.find(AuthenticationFlowEntity.class, id);
AuthenticationFlowEntity entity = getAuthenticationFlowEntity(id, false);
if (entity == null) return null;
return entityToModel(entity);
}
@ -1661,15 +1661,15 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
if (KeycloakModelUtils.isFlowUsed(this, model)) {
throw new ModelException("Cannot remove authentication flow, it is currently in use");
}
AuthenticationFlowEntity entity = em.find(AuthenticationFlowEntity.class, model.getId(), LockModeType.PESSIMISTIC_WRITE);
AuthenticationFlowEntity entity = getAuthenticationFlowEntity(model.getId(), true);
if (entity == null) return;
em.remove(entity);
em.flush();
}
@Override
public void updateAuthenticationFlow(AuthenticationFlowModel model) {
AuthenticationFlowEntity entity = em.find(AuthenticationFlowEntity.class, model.getId());
AuthenticationFlowEntity entity = getAuthenticationFlowEntity(model.getId(), false);
if (entity == null) return;
entity.setAlias(model.getAlias());
entity.setDescription(model.getDescription());
@ -1679,6 +1679,15 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
}
private AuthenticationFlowEntity getAuthenticationFlowEntity(String id, boolean readForRemove) {
AuthenticationFlowEntity entity = readForRemove
? em.find(AuthenticationFlowEntity.class, id, LockModeType.PESSIMISTIC_WRITE)
: em.find(AuthenticationFlowEntity.class, id);
if (entity == null) return null;
if (!entity.getRealm().equals(getEntity())) return null;
return entity;
}
@Override
public AuthenticationFlowModel addAuthenticationFlow(AuthenticationFlowModel model) {
AuthenticationFlowEntity entity = new AuthenticationFlowEntity();
@ -1723,7 +1732,7 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
@Override
public AuthenticationExecutionModel getAuthenticationExecutionById(String id) {
AuthenticationExecutionEntity entity = em.find(AuthenticationExecutionEntity.class, id);
AuthenticationExecutionEntity entity = getAuthenticationExecution(id, false);
if (entity == null) return null;
return entityToModel(entity);
}
@ -1761,7 +1770,7 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
@Override
public void updateAuthenticatorExecution(AuthenticationExecutionModel model) {
AuthenticationExecutionEntity entity = em.find(AuthenticationExecutionEntity.class, model.getId());
AuthenticationExecutionEntity entity = getAuthenticationExecution(model.getId(), false);
if (entity == null) return;
entity.setAutheticatorFlow(model.isAuthenticatorFlow());
entity.setAuthenticator(model.getAuthenticator());
@ -1778,13 +1787,22 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
@Override
public void removeAuthenticatorExecution(AuthenticationExecutionModel model) {
AuthenticationExecutionEntity entity = em.find(AuthenticationExecutionEntity.class, model.getId(), LockModeType.PESSIMISTIC_WRITE);
AuthenticationExecutionEntity entity = getAuthenticationExecution(model.getId(), true);
if (entity == null) return;
em.remove(entity);
em.flush();
}
private AuthenticationExecutionEntity getAuthenticationExecution(String id, boolean readForRemove) {
AuthenticationExecutionEntity entity = readForRemove
? em.find(AuthenticationExecutionEntity.class, id, LockModeType.PESSIMISTIC_WRITE)
: em.find(AuthenticationExecutionEntity.class, id);
if (entity == null) return null;
if (!entity.getRealm().equals(getEntity())) return null;
return entity;
}
@Override
public AuthenticatorConfigModel addAuthenticatorConfig(AuthenticatorConfigModel model) {
AuthenticatorConfigEntity auth = new AuthenticatorConfigEntity();
@ -1801,7 +1819,7 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
@Override
public void removeAuthenticatorConfig(AuthenticatorConfigModel model) {
AuthenticatorConfigEntity entity = em.find(AuthenticatorConfigEntity.class, model.getId(), LockModeType.PESSIMISTIC_WRITE);
AuthenticatorConfigEntity entity = getAuthenticatorConfigEntity(model.getId(), true);
if (entity == null) return;
em.remove(entity);
em.flush();
@ -1810,7 +1828,7 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
@Override
public AuthenticatorConfigModel getAuthenticatorConfigById(String id) {
AuthenticatorConfigEntity entity = em.find(AuthenticatorConfigEntity.class, id);
AuthenticatorConfigEntity entity = getAuthenticatorConfigEntity(id, false);
if (entity == null) return null;
return entityToModel(entity);
}
@ -1827,7 +1845,7 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
@Override
public void updateAuthenticatorConfig(AuthenticatorConfigModel model) {
AuthenticatorConfigEntity entity = em.find(AuthenticatorConfigEntity.class, model.getId());
AuthenticatorConfigEntity entity = getAuthenticatorConfigEntity(model.getId(), false);
if (entity == null) return;
entity.setAlias(model.getAlias());
if (entity.getConfig() == null) {
@ -1842,6 +1860,15 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
}
private AuthenticatorConfigEntity getAuthenticatorConfigEntity(String id, boolean readForRemove) {
AuthenticatorConfigEntity entity = readForRemove
? em.find(AuthenticatorConfigEntity.class, id, LockModeType.PESSIMISTIC_WRITE)
: em.find(AuthenticatorConfigEntity.class, id);
if (entity == null) return null;
if (!entity.getRealm().equals(getEntity())) return null;
return entity;
}
@Override
public List<AuthenticatorConfigModel> getAuthenticatorConfigs() {
Collection<AuthenticatorConfigEntity> entities = realm.getAuthenticatorConfigs();
@ -1875,7 +1902,7 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
@Override
public void removeRequiredActionProvider(RequiredActionProviderModel model) {
RequiredActionProviderEntity entity = em.find(RequiredActionProviderEntity.class, model.getId(), LockModeType.PESSIMISTIC_WRITE);
RequiredActionProviderEntity entity = getRequiredProviderEntity(model.getId(), true);
if (entity == null) return;
em.remove(entity);
em.flush();
@ -1884,7 +1911,7 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
@Override
public RequiredActionProviderModel getRequiredActionProviderById(String id) {
RequiredActionProviderEntity entity = em.find(RequiredActionProviderEntity.class, id);
RequiredActionProviderEntity entity = getRequiredProviderEntity(id, false);
if (entity == null) return null;
return entityToModel(entity);
}
@ -1906,7 +1933,7 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
@Override
public void updateRequiredActionProvider(RequiredActionProviderModel model) {
RequiredActionProviderEntity entity = em.find(RequiredActionProviderEntity.class, model.getId());
RequiredActionProviderEntity entity = getRequiredProviderEntity(model.getId(), false);
if (entity == null) return;
entity.setAlias(model.getAlias());
entity.setProviderId(model.getProviderId());
@ -1938,6 +1965,15 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
return Collections.unmodifiableList(actions);
}
private RequiredActionProviderEntity getRequiredProviderEntity(String id, boolean readForRemove) {
RequiredActionProviderEntity entity = readForRemove
? em.find(RequiredActionProviderEntity.class, id, LockModeType.PESSIMISTIC_WRITE)
: em.find(RequiredActionProviderEntity.class, id);
if (entity == null) return null;
if (!entity.getRealm().equals(getEntity())) return null;
return entity;
}
@Override
public RequiredActionProviderModel getRequiredActionProviderByAlias(String alias) {
for (RequiredActionProviderModel action : getRequiredActionProviders()) {
@ -2178,7 +2214,7 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
public void updateComponent(ComponentModel component) {
ComponentUtil.getComponentFactory(session, component).validateConfiguration(session, this, component);
ComponentEntity c = em.find(ComponentEntity.class, component.getId());
ComponentEntity c = getComponentEntity(component.getId());
if (c == null) return;
ComponentModel old = entityToModel(c);
c.setName(component.getName());
@ -2194,7 +2230,7 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
@Override
public void removeComponent(ComponentModel component) {
ComponentEntity c = em.find(ComponentEntity.class, component.getId());
ComponentEntity c = getComponentEntity(component.getId());
if (c == null) return;
session.users().preRemove(this, component);
ComponentUtil.notifyPreRemove(session, this, component);
@ -2260,8 +2296,14 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
@Override
public ComponentModel getComponent(String id) {
ComponentEntity c = getComponentEntity(id);
return c==null ? null : entityToModel(c);
}
private ComponentEntity getComponentEntity(String id) {
ComponentEntity c = em.find(ComponentEntity.class, id);
if (c == null) return null;
return entityToModel(c);
if (!c.getRealm().equals(getEntity())) return null;
return c;
}
}

View file

@ -0,0 +1,547 @@
/*
* Copyright 2019 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.model;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiFunction;
import org.junit.Assert;
import org.junit.Test;
import org.keycloak.component.ComponentModel;
import org.keycloak.models.AuthenticationExecutionModel;
import org.keycloak.models.AuthenticationFlowModel;
import org.keycloak.models.AuthenticatorConfigModel;
import org.keycloak.models.ClientInitialAccessModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelException;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RealmProvider;
import org.keycloak.models.RequiredActionProviderModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.models.utils.DefaultAuthenticationFlows;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.testsuite.AbstractKeycloakTest;
import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude;
import org.keycloak.testsuite.arquillian.annotation.ModelTest;
import org.keycloak.testsuite.util.RealmBuilder;
import org.keycloak.testsuite.util.UserBuilder;
import static org.keycloak.testsuite.admin.AbstractAdminTest.loadJson;
/**
* Test for the CRUD scenarios when the operation is called on the object, which is owned by different realm
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@AuthServerContainerExclude(AuthServerContainerExclude.AuthServer.REMOTE)
public class OwnerReplacementTest extends AbstractKeycloakTest {
@Override
public void addTestRealms(List<RealmRepresentation> testRealms) {
log.debug("Adding test realm for import from testrealm.json");
RealmRepresentation testRealm = loadJson(getClass().getResourceAsStream("/testrealm.json"), RealmRepresentation.class);
testRealms.add(testRealm);
UserRepresentation user = UserBuilder.create()
.username("foo@user")
.email("foo@user.com")
.password("password")
.build();
RealmRepresentation realm2 = RealmBuilder.create()
.name("foo")
.user(user)
.build();
realm2.setId("foo");
testRealms.add(realm2);
}
@Test
@ModelTest
public void componentsTest(KeycloakSession session1) {
doTest(session1,
// Get ID of some component from realm1
((session, realm1) -> {
List<ComponentModel> components = realm1.getComponents();
return components.get(0).getId();
}),
// Test lookup realm1 component in realm2 should not work
((session, realm2, realm1ComponentId) -> {
ComponentModel component = realm2.getComponent(realm1ComponentId);
Assert.assertNull(component);
}),
// Try to update some component in realm1 through the realm2
((session, realm1, realm2, realm1ComponentId) -> {
ComponentModel component = realm1.getComponent(realm1ComponentId);
component.put("key1", "Val1");
realm2.updateComponent(component);
}),
// Test update from above was not successful
((session, realm1, realm1ComponentId) -> {
ComponentModel component = realm1.getComponent(realm1ComponentId);
Assert.assertNull(component.get("key1"));
}),
// Try remove component from realm1 in the context of realm2
((session, realm1, realm2, realm1ComponentId) -> {
ComponentModel component = realm1.getComponent(realm1ComponentId);
realm2.removeComponent(component);
}),
// Test remove from above was not successful
((session, realm1, realm1ComponentId) -> {
ComponentModel component = realm1.getComponent(realm1ComponentId);
Assert.assertNotNull(component);
})
);
}
@Test
@ModelTest
public void requiredActionProvidersTest(KeycloakSession session1) {
doTest(session1,
// Get ID of some object from realm1
((session, realm1) -> {
List<RequiredActionProviderModel> reqActions = realm1.getRequiredActionProviders();
return reqActions.get(0).getId();
}),
// Test lookup realm1 object in realm2 should not work
((session, realm2, realm1ReqActionId) -> {
RequiredActionProviderModel reqAction = realm2.getRequiredActionProviderById(realm1ReqActionId);
Assert.assertNull(reqAction);
}),
// Try to update some object in realm1 through the realm2
((session, realm1, realm2, realm1ReqActionId) -> {
RequiredActionProviderModel reqAction = realm1.getRequiredActionProviderById(realm1ReqActionId);
reqAction.getConfig().put("key1", "Val1");
realm2.updateRequiredActionProvider(reqAction);
}),
// Test update from above was not successful
((session, realm1, realm1ReqActionId) -> {
RequiredActionProviderModel reqAction = realm1.getRequiredActionProviderById(realm1ReqActionId);
Assert.assertNull(reqAction.getConfig().get("key1"));
}),
// Try remove object from realm1 in the context of realm2
((session, realm1, realm2, realm1ReqActionId) -> {
RequiredActionProviderModel reqAction = realm1.getRequiredActionProviderById(realm1ReqActionId);
realm2.removeRequiredActionProvider(reqAction);
}),
// Test remove from above was not successful
((session, realm1, realm1ReqActionId) -> {
RequiredActionProviderModel reqAction = realm1.getRequiredActionProviderById(realm1ReqActionId);
Assert.assertNotNull(reqAction);
})
);
}
@Test
@ModelTest
public void authenticationFlowsTest(KeycloakSession session1) {
doTest(session1,
// Get ID of some object from realm1
((session, realm1) -> {
AuthenticationFlowModel flow = realm1.getFlowByAlias(DefaultAuthenticationFlows.BROWSER_FLOW);
return flow.getId();
}),
// Test lookup realm1 object in realm2 should not work
((session, realm2, realm1FlowId) -> {
AuthenticationFlowModel flow = realm2.getAuthenticationFlowById(realm1FlowId);
Assert.assertNull(flow);
}),
// Try to update some object in realm1 through the realm2
((session, realm1, realm2, realm1FlowId) -> {
AuthenticationFlowModel flow = realm1.getAuthenticationFlowById(realm1FlowId);
flow.setDescription("foo");
realm2.updateAuthenticationFlow(flow);
}),
// Test update from above was not successful
((session, realm1, realm1FlowId) -> {
AuthenticationFlowModel flow = realm1.getAuthenticationFlowById(realm1FlowId);
Assert.assertNotEquals("foo", flow.getDescription());
}),
// Try remove object from realm1 in the context of realm2
((session, realm1, realm2, realm1FlowId) -> {
AuthenticationFlowModel flow = realm1.getAuthenticationFlowById(realm1FlowId);
realm2.removeAuthenticationFlow(flow);
}),
// Test remove from above was not successful
((session, realm1, realm1FlowId) -> {
AuthenticationFlowModel flow = realm1.getAuthenticationFlowById(realm1FlowId);
Assert.assertNotNull(flow);
})
);
}
@Test
@ModelTest
public void authenticationExecutionsTest(KeycloakSession session1) {
doTest(session1,
// Get ID of some object from realm1
((session, realm1) -> {
AuthenticationFlowModel flow = realm1.getFlowByAlias(DefaultAuthenticationFlows.BROWSER_FLOW);
List<AuthenticationExecutionModel> executions = realm1.getAuthenticationExecutions(flow.getId());
return executions.get(0).getId();
}),
// Test lookup realm1 object in realm2 should not work
((session, realm2, realm1ExecutionId) -> {
AuthenticationExecutionModel execution = realm2.getAuthenticationExecutionById(realm1ExecutionId);
Assert.assertNull(execution);
}),
// Try to update some object in realm1 through the realm2
((session, realm1, realm2, realm1ExecutionId) -> {
AuthenticationExecutionModel execution = realm1.getAuthenticationExecutionById(realm1ExecutionId);
execution.setPriority(1234);
realm2.updateAuthenticatorExecution(execution);
}),
// Test update from above was not successful
((session, realm1, realm1ExecutionId) -> {
AuthenticationExecutionModel execution = realm1.getAuthenticationExecutionById(realm1ExecutionId);
Assert.assertNotEquals(1234, execution.getPriority());
}),
// Try remove object from realm1 in the context of realm2
((session, realm1, realm2, realm1ExecutionId) -> {
AuthenticationExecutionModel execution = realm1.getAuthenticationExecutionById(realm1ExecutionId);
realm2.removeAuthenticatorExecution(execution);
}),
// Test remove from above was not successful
((session,realm1, realm1ExecutionId) -> {
AuthenticationExecutionModel execution = realm1.getAuthenticationExecutionById(realm1ExecutionId);
Assert.assertNotNull(execution);
})
);
}
@Test
@ModelTest
public void authenticationConfigsTest(KeycloakSession session1) {
doTest(session1,
// Get ID of some object from realm1
((session, realm1) -> {
List<AuthenticatorConfigModel> configs = realm1.getAuthenticatorConfigs();
return configs.get(0).getId();
}),
// Test lookup realm1 object in realm2 should not work
((session, realm2, realm1AuthConfigId) -> {
AuthenticatorConfigModel config = realm2.getAuthenticatorConfigById(realm1AuthConfigId);
Assert.assertNull(config);
}),
// Try to update some object in realm1 through the realm2
((session, realm1, realm2, realm1AuthConfigId) -> {
AuthenticatorConfigModel config = realm1.getAuthenticatorConfigById(realm1AuthConfigId);
config.getConfig().put("key1", "val1");
realm2.updateAuthenticatorConfig(config);
}),
// Test update from above was not successful
((session, realm1, realm1AuthConfigId) -> {
AuthenticatorConfigModel config = realm1.getAuthenticatorConfigById(realm1AuthConfigId);
Assert.assertNull(config.getConfig().get("key1"));
}),
// Try remove object from realm1 in the context of realm2
((session, realm1, realm2, realm1AuthConfigId) -> {
AuthenticatorConfigModel config = realm1.getAuthenticatorConfigById(realm1AuthConfigId);
realm2.removeAuthenticatorConfig(config);
}),
// Test remove from above was not successful
((session, realm1, realm1AuthConfigId) -> {
AuthenticatorConfigModel config = realm1.getAuthenticatorConfigById(realm1AuthConfigId);
Assert.assertNotNull(config);
})
);
}
@Test
@ModelTest
public void clientInitialAccessTest(KeycloakSession session1) {
doTest(session1,
// Get ID of some object from realm1
((session, realm1) -> {
ClientInitialAccessModel clientInitialAccess = session.getProvider(RealmProvider.class).createClientInitialAccessModel(realm1, 10, 20);
return clientInitialAccess.getId();
}),
// Test lookup realm1 object in realm2 should not work
((session, realm2, realm1ClientInitialAccessId) -> {
ClientInitialAccessModel clientInitialAccess = session.getProvider(RealmProvider.class).getClientInitialAccessModel(realm2, realm1ClientInitialAccessId);
Assert.assertNull(clientInitialAccess);
}),
// Try to update some object in realm1 through the realm2
((session, realm1, realm2, realm1ClientInitialAccessId) -> {
// No-op, update not supported for clientInitialAccessModel
}),
// Test update from above was not successful
((session, realm1, realm1ClientInitialAccessId) -> {
// No-op, update not supported for clientInitialAccessModel
}),
// Try remove object from realm1 in the context of realm2
((session, realm1, realm2, realm1ClientInitialAccessId) -> {
session.getProvider(RealmProvider.class).removeClientInitialAccessModel(realm2, realm1ClientInitialAccessId);
}),
// Test remove from above was not successful
((session, realm1, realm1ClientInitialAccessId) -> {
ClientInitialAccessModel clientInitialAccess = session.getProvider(RealmProvider.class).getClientInitialAccessModel(realm1, realm1ClientInitialAccessId);
Assert.assertNotNull(clientInitialAccess);
})
);
}
@Test
@ModelTest
public void rolesTest(KeycloakSession session1) {
doTest(session1,
// Get ID of some object from realm1
((session, realm1) -> {
RoleModel role = session.getProvider(RealmProvider.class).addRealmRole(realm1, "foo");
realm1.addDefaultRole("foo");
return role.getId();
}),
// Test lookup realm1 object in realm2 should not work
((session, realm2, realm1RoleId) -> {
RoleModel role = session.getProvider(RealmProvider.class).getRoleById(realm1RoleId, realm2);
Assert.assertNull(role);
}),
// Try to update some object in realm1 through the realm2
((session, realm1, realm2, realm1RoleId) -> {
// No-op, update done directly by calling operations on RoleModel. No explicit updateRole method on the RealmModel
}),
// Test update from above was not successful
((session, realm1, realm1RoleId) -> {
// No-op, update done directly by calling operations on RoleModel. No explicit updateRole method on the RealmModel
}),
// Try remove object from realm1 in the context of realm2
((session, realm1, realm2, realm1RoleId) -> {
RoleModel role = session.getProvider(RealmProvider.class).getRoleById(realm1RoleId, realm1);
session.getProvider(RealmProvider.class).removeRole(realm2, role);
}),
// Test remove from above was not successful
((session, realm1, realm1RoleId) -> {
RoleModel role = session.getProvider(RealmProvider.class).getRoleById(realm1RoleId, realm1);
Assert.assertNotNull(role);
Assert.assertTrue(realm1.getDefaultRoles().contains("foo"));
})
);
}
@Test
@ModelTest
public void userSessionsTest(KeycloakSession session1) {
doTest(session1,
// Get ID of some object from realm1
((session, realm1) -> {
UserModel user = session.users().getUserByUsername("test-user@localhost", realm1);
UserSessionModel userSession = session.sessions().createUserSession(realm1, user, user.getUsername(), "1.2.3.4", "bar", false, null, null);
return userSession.getId();
}),
// Test lookup realm1 object in realm2 should not work
((session, realm2, realm1SessionId) -> {
UserSessionModel userSession = session.sessions().getUserSession(realm2, realm1SessionId);
Assert.assertNull(userSession);
}),
// Try to update some object in realm1 through the realm2
((session, realm1, realm2, realm1SessionId) -> {
// No-op, update done directly by calling operations on UserSessionModel. No explicit update method
}),
// Test update from above was not successful
((session, realm1, realm1SessionId) -> {
// No-op, update done directly by calling operations on UserSessionModel. No explicit update method.
}),
// Try remove object from realm1 in the context of realm2
((session, realm1, realm2, realm1SessionId) -> {
UserSessionModel userSession = session.sessions().getUserSession(realm1, realm1SessionId);
session.sessions().removeUserSession(realm2, userSession);
}),
// Test remove from above was not successful
((session, realm1, realm1SessionId) -> {
UserSessionModel userSession = session.sessions().getUserSession(realm1, realm1SessionId);
Assert.assertNotNull(userSession);
})
);
}
private void doTest(KeycloakSession session1,
BiFunction<KeycloakSession, RealmModel, String> realm1ObjectIdProducer,
TriConsumer<KeycloakSession, RealmModel, String> testLookupRealm1ObjectInRealm2,
TetraConsumer<KeycloakSession, RealmModel, RealmModel, String> updaterRealm1ObjectInRealm2,
TriConsumer<KeycloakSession, RealmModel, String> testUpdateFailed,
TetraConsumer<KeycloakSession, RealmModel, RealmModel, String> removeRealm1ObjectInRealm2,
TriConsumer<KeycloakSession, RealmModel, String> testRemoveFailed
) {
// Transaction 1 - Lookup object of realm1
AtomicReference<String> realm1ObjectId = new AtomicReference<>();
KeycloakModelUtils.runJobInTransaction(session1.getKeycloakSessionFactory(), (KeycloakSession session) -> {
RealmModel realm1 = session.getProvider(RealmProvider.class).getRealm("test");
realm1ObjectId.set(realm1ObjectIdProducer.apply(session, realm1));
});
// Transaction 2
KeycloakModelUtils.runJobInTransaction(session1.getKeycloakSessionFactory(), (KeycloakSession session) -> {
RealmModel realm1 = session.getProvider(RealmProvider.class).getRealm("test");
RealmModel realm2 = session.getProvider(RealmProvider.class).getRealm("foo");
testLookupRealm1ObjectInRealm2.accept(session, realm2, realm1ObjectId.get());
updaterRealm1ObjectInRealm2.accept(session, realm1, realm2, realm1ObjectId.get());
});
// Transaction 3
KeycloakModelUtils.runJobInTransaction(session1.getKeycloakSessionFactory(), (KeycloakSession session) -> {
RealmModel realm1 = session.getProvider(RealmProvider.class).getRealm("test");
testUpdateFailed.accept(session, realm1, realm1ObjectId.get());
});
// Transaction 4
try {
KeycloakModelUtils.runJobInTransaction(session1.getKeycloakSessionFactory(), (KeycloakSession session) -> {
RealmModel realm1 = session.getProvider(RealmProvider.class).getRealm("test");
RealmModel realm2 = session.getProvider(RealmProvider.class).getRealm("foo");
removeRealm1ObjectInRealm2.accept(session, realm1, realm2, realm1ObjectId.get());
});
} catch (ModelException e) {
// This is fine. Attempt to remove on incorrect object can throw an exception in some cases, which will enforce transaction rollback
}
// Transaction 5
KeycloakModelUtils.runJobInTransaction(session1.getKeycloakSessionFactory(), (KeycloakSession session) -> {
RealmModel realm1 = session.getProvider(RealmProvider.class).getRealm("test");
testRemoveFailed.accept(session, realm1, realm1ObjectId.get());
});
}
@FunctionalInterface
public interface TriConsumer<T, U, V> {
void accept(T var1, U var2, V var3);
}
@FunctionalInterface
public interface TetraConsumer<T, U, V, W> {
void accept(T var1, U var2, V var3, W var4);
}
}