Move AbstractGroupTest.java, GroupMappersTest.java, GroupTest.java to the new testsuite

Part of: #34494

Signed-off-by: Simon Vacek <simonvacky@email.cz>

# Conflicts:
#	test-framework/core/src/main/java/org/keycloak/testframework/realm/RealmConfigBuilder.java
#	test-framework/core/src/main/java/org/keycloak/testframework/realm/UserConfigBuilder.java

# Conflicts:
#	test-framework/core/src/main/java/org/keycloak/testframework/realm/ClientConfigBuilder.java
This commit is contained in:
Simon Vacek
2025-03-26 16:59:02 +01:00
committed by Stian Thorgersen
parent 9e1d519e2c
commit a8e33732cd
10 changed files with 989 additions and 915 deletions
@@ -1,6 +1,7 @@
package org.keycloak.testframework.realm;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.ProtocolMapperRepresentation;
import java.util.HashMap;
import java.util.LinkedList;
@@ -69,6 +70,11 @@ public class ClientConfigBuilder {
return this;
}
public ClientConfigBuilder rootUrl(String rootUrl) {
rep.setRootUrl(rootUrl);
return this;
}
public ClientConfigBuilder baseUrl(String baseUrl) {
rep.setBaseUrl(baseUrl);
return this;
@@ -128,6 +134,14 @@ public class ClientConfigBuilder {
return this;
}
public ClientConfigBuilder protocolMappers(List<ProtocolMapperRepresentation> mappers) {
if (rep.getProtocolMappers() == null) {
rep.setProtocolMappers(new LinkedList<>());
}
rep.getProtocolMappers().addAll(mappers);
return this;
}
public ClientRepresentation build() {
return rep;
}
@@ -1,8 +1,10 @@
package org.keycloak.testframework.realm;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;
class Collections {
@@ -28,4 +30,25 @@ class Collections {
return combine(l1, items.toList());
}
static <K, V> Map<K, List<V>> combine(Map<K, List<V>> m1, Map<K, List<V>> m2) {
if (m1 == null) {
m1 = new HashMap<>();
}
for (Map.Entry<K, List<V>> entry : m2.entrySet()) {
K k = entry.getKey();
List<V> v = entry.getValue();
m1.put(k, combine(m1.get(k), v));
}
return m1;
}
@SafeVarargs
static <K, V> Map<K, List<V>> combine(Map<K, List<V>> m1, K key, V... values) {
return combine(m1, Map.of(key, List.of(values)));
}
static <K, V> Map<K, List<V>> combine(Map<K, List<V>> m1, K key, Stream<V> values) {
return combine(m1, Map.of(key, values.toList()));
}
}
@@ -0,0 +1,78 @@
package org.keycloak.testframework.realm;
import org.keycloak.representations.idm.GroupRepresentation;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
public class GroupConfigBuilder {
private final GroupRepresentation rep;
private GroupConfigBuilder(GroupRepresentation rep) {
this.rep = rep;
}
public static GroupConfigBuilder create() {
GroupRepresentation rep = new GroupRepresentation();
return new GroupConfigBuilder(rep);
}
public static GroupConfigBuilder update(GroupRepresentation rep) {
return new GroupConfigBuilder(rep);
}
public GroupConfigBuilder name(String name) {
rep.setName(name);
return this;
}
public GroupConfigBuilder path(String path) {
rep.setPath(path);
return this;
}
public GroupConfigBuilder realmRoles(String... realmRoles) {
if (rep.getRealmRoles() == null) {
rep.setRealmRoles(new LinkedList<>());
}
rep.getRealmRoles().addAll(List.of(realmRoles));
return this;
}
public GroupConfigBuilder clientRole(String client, String... clientRoles) {
if (rep.getClientRoles() == null) {
rep.setClientRoles(new HashMap<>());
}
rep.getClientRoles().put(client, List.of(clientRoles));
return this;
}
public GroupConfigBuilder attribute(String name, String... values) {
rep.setAttributes(Collections.combine(rep.getAttributes(), name, values));
return this;
}
public GroupConfigBuilder setAttributes(Map<String, List<String>> attributes) {
rep.setAttributes(attributes);
return this;
}
//
// public GroupConfigBuilder singleAttribute(String name, String value) {
// rep.singleAttribute(name, value);
// return this;
// }
public GroupConfigBuilder subGroups(GroupRepresentation... subGroups) {
if (rep.getSubGroups() == null) {
rep.setSubGroups(new LinkedList<>());
}
rep.getSubGroups().addAll(List.of(subGroups));
return this;
}
public GroupRepresentation build() {
return rep;
}
}
@@ -1,6 +1,7 @@
package org.keycloak.testframework.realm;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.GroupRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.RolesRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
@@ -59,6 +60,15 @@ public class RealmConfigBuilder {
return UserConfigBuilder.update(user).enabled(true).username(username);
}
public GroupConfigBuilder addGroup(String name) {
if (rep.getGroups() == null) {
rep.setGroups(new LinkedList<>());
}
GroupRepresentation group = new GroupRepresentation();
rep.getGroups().add(group);
return GroupConfigBuilder.update(group).name(name);
}
public RealmConfigBuilder registrationEmailAsUsername(boolean registrationEmailAsUsername) {
rep.setRegistrationEmailAsUsername(registrationEmailAsUsername);
return this;
@@ -129,7 +139,22 @@ public class RealmConfigBuilder {
if (rep.getRoles() == null) {
rep.setRoles(new RolesRepresentation());
}
rep.getRoles().setRealm(Collections.combine(rep.getRoles().getRealm(), Arrays.stream(roleNames).map(Representations::toRole)));
rep.getRoles().setRealm(Collections.combine(
rep.getRoles().getRealm(),
Arrays.stream(roleNames).map(r -> Representations.toRole(r, false))
));
return this;
}
public RealmConfigBuilder clientRoles(String client, String... roleNames) {
if (rep.getRoles() == null) {
rep.setRoles(new RolesRepresentation());
}
rep.getRoles().setClient(Collections.combine(
rep.getRoles().getClient(),
client,
Arrays.stream(roleNames).map(r -> Representations.toRole(r, true))
));
return this;
}
@@ -138,6 +163,11 @@ public class RealmConfigBuilder {
return this;
}
public RealmConfigBuilder defaultGroups(String... defaultGroupsNames) {
rep.setDefaultGroups(Collections.combine(rep.getDefaultGroups(), defaultGroupsNames));
return this;
}
public RealmConfigBuilder internationalizationEnabled(boolean enabled) {
rep.setInternationalizationEnabled(enabled);
return this;
@@ -9,9 +9,10 @@ class Representations {
private Representations() {
}
static RoleRepresentation toRole(String roleName) {
static RoleRepresentation toRole(String roleName, boolean clientRole) {
RoleRepresentation role = new RoleRepresentation();
role.setName(roleName);
role.setClientRole(clientRole);
return role;
}
@@ -82,8 +82,8 @@ public class UserConfigBuilder {
return this;
}
public UserConfigBuilder attribute(String key, String value) {
rep.singleAttribute(key, value);
public UserConfigBuilder attribute(String name, String... value) {
rep.setAttributes(Collections.combine(rep.getAttributes(), name, value));
return this;
}
@@ -15,116 +15,68 @@
* limitations under the License.
*/
package org.keycloak.testsuite.admin.group;
package org.keycloak.tests.admin.group;
import jakarta.ws.rs.core.Response;
import org.junit.Rule;
import org.keycloak.OAuth2Constants;
import org.keycloak.RSATokenVerifier;
import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.common.util.PemUtils;
import org.keycloak.events.Details;
import org.keycloak.events.admin.OperationType;
import org.keycloak.events.admin.ResourceType;
import org.keycloak.jose.jws.JWSInput;
import org.keycloak.representations.AccessToken;
import org.keycloak.representations.RefreshToken;
import org.keycloak.representations.idm.GroupRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.testsuite.AbstractKeycloakTest;
import org.keycloak.testsuite.AssertEvents;
import org.keycloak.testsuite.admin.ApiUtil;
import org.keycloak.testsuite.util.AdminEventPaths;
import org.keycloak.testsuite.util.AssertAdminEvents;
import org.keycloak.testsuite.util.KeyUtils;
import org.keycloak.testframework.annotations.InjectAdminEvents;
import org.keycloak.testframework.annotations.KeycloakIntegrationTest;
import org.keycloak.testframework.events.AdminEventAssertion;
import org.keycloak.testframework.events.AdminEvents;
import org.keycloak.testframework.oauth.OAuthClient;
import org.keycloak.testframework.oauth.annotations.InjectOAuthClient;
import org.keycloak.testframework.realm.ManagedRealm;
import org.keycloak.tests.utils.admin.AdminEventPaths;
import org.keycloak.tests.utils.admin.ApiUtil;
import org.keycloak.testsuite.util.oauth.AccessTokenResponse;
import java.security.PublicKey;
import java.util.List;
import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
import static org.keycloak.testsuite.utils.io.IOUtil.loadRealm;
import static org.keycloak.testsuite.util.ServerURLs.getAuthServerContextRoot;
/**
* @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
*/
public abstract class AbstractGroupTest extends AbstractKeycloakTest {
@KeycloakIntegrationTest
public abstract class AbstractGroupTest {
protected String testRealmId;
@InjectAdminEvents
AdminEvents adminEvents;
@Rule
public AssertEvents events = new AssertEvents(this);
@InjectOAuthClient
OAuthClient oAuth;
@Rule
public AssertAdminEvents assertAdminEvents = new AssertAdminEvents(this);
@Override
public void beforeAbstractKeycloakTest() throws Exception {
super.beforeAbstractKeycloakTest();
this.testRealmId = adminClient.realm(TEST).toRepresentation().getId();
AccessToken login(String username, String clientId, String clientSecret) {
AccessTokenResponse tokenResponse = oAuth.client(clientId, clientSecret).doPasswordGrantRequest(username, "password");
return oAuth.parseToken(tokenResponse.getAccessToken(), AccessToken.class);
}
AccessToken login(String login, String clientId, String clientSecret, String userId) throws Exception {
AccessTokenResponse tokenResponse = oauth.client(clientId, clientSecret).doPasswordGrantRequest( login, "password");
String createGroup(ManagedRealm managedRealm, GroupRepresentation group) {
Response response = managedRealm.admin().groups().add(group);
String groupId = ApiUtil.getCreatedId(response);
managedRealm.cleanup().add(r -> r.groups().group(groupId).remove());
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.CREATE, AdminEventPaths.groupPath(groupId), group, ResourceType.GROUP);
String accessToken = tokenResponse.getAccessToken();
String refreshToken = tokenResponse.getRefreshToken();
PublicKey publicKey = PemUtils.decodePublicKey(KeyUtils.findActiveSigningKey(adminClient.realm("test")).getPublicKey());
AccessToken accessTokenRepresentation = RSATokenVerifier.verifyToken(accessToken, publicKey, getAuthServerContextRoot() + "/auth/realms/test");
JWSInput jws = new JWSInput(refreshToken);
RefreshToken refreshTokenRepresentation = jws.readJsonContent(RefreshToken.class);
events.expectLogin()
.client(clientId)
.user(userId)
.detail(Details.GRANT_TYPE, OAuth2Constants.PASSWORD)
.detail(Details.TOKEN_ID, accessTokenRepresentation.getId())
.detail(Details.REFRESH_TOKEN_ID, refreshTokenRepresentation.getId())
.detail(Details.USERNAME, login)
.removeDetail(Details.CODE_ID)
.removeDetail(Details.REDIRECT_URI)
.removeDetail(Details.CONSENT)
.assertEvent();
return accessTokenRepresentation;
// Set ID to the original rep
group.setId(groupId);
return groupId;
}
RealmRepresentation loadTestRealm(List<RealmRepresentation> testRealms) {
RealmRepresentation result = loadRealm("/testrealm.json");
testRealms.add(result);
return result;
}
GroupRepresentation createGroup(RealmResource realm, GroupRepresentation group) {
try (Response response = realm.groups().add(group)) {
String groupId = ApiUtil.getCreatedId(response);
getCleanup().addGroupId(groupId);
assertAdminEvents.assertEvent(testRealmId, OperationType.CREATE, AdminEventPaths.groupPath(groupId), group, ResourceType.GROUP);
// Set ID to the original rep
group.setId(groupId);
return group;
}
}
void addSubGroup(RealmResource realm, GroupRepresentation parent, GroupRepresentation child) {
Response response = realm.groups().add(child);
child.setId(ApiUtil.getCreatedId(response));
response = realm.groups().group(parent.getId()).subGroup(child);
void addSubGroup(ManagedRealm managedRealm, GroupRepresentation parent, GroupRepresentation child) {
Response response = managedRealm.admin().groups().add(child);
adminEvents.skip();
String childUuid = ApiUtil.getCreatedId(response);
child.setId(childUuid);
response = managedRealm.admin().groups().group(parent.getId()).subGroup(child);
adminEvents.skip();
response.close();
}
RoleRepresentation createRealmRole(RealmResource realm, RoleRepresentation role) {
realm.roles().create(role);
RoleRepresentation created = realm.roles().get(role.getName()).toRepresentation();
getCleanup().addRoleId(created.getId());
RoleRepresentation createRealmRole(ManagedRealm managedRealm, RoleRepresentation role) {
managedRealm.admin().roles().create(role);
RoleRepresentation created = managedRealm.admin().roles().get(role.getName()).toRepresentation();
String createdName = created.getName();
managedRealm.cleanup().add(r -> r.roles().deleteRole(createdName));
return created;
}
}
@@ -15,14 +15,14 @@
* limitations under the License.
*/
package org.keycloak.testsuite.admin.group;
package org.keycloak.tests.admin.group;
import jakarta.ws.rs.core.Response;
import java.util.*;
import org.hamcrest.MatcherAssert;
import org.hamcrest.Matchers;
import org.junit.Assert;
import org.junit.Test;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.keycloak.admin.client.resource.ClientResource;
import org.keycloak.admin.client.resource.ProtocolMappersResource;
import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.models.GroupProvider;
@@ -34,143 +34,200 @@ import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper;
import org.keycloak.protocol.oidc.mappers.UserAttributeMapper;
import org.keycloak.provider.ProviderConfigProperty;
import org.keycloak.representations.AccessToken;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.GroupRepresentation;
import org.keycloak.representations.idm.ProtocolMapperRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.testsuite.admin.ApiUtil;
import org.keycloak.testframework.annotations.InjectRealm;
import org.keycloak.testframework.annotations.KeycloakIntegrationTest;
import org.keycloak.testframework.realm.GroupConfigBuilder;
import org.keycloak.testframework.realm.ManagedRealm;
import org.keycloak.testframework.realm.RealmConfig;
import org.keycloak.testframework.realm.RealmConfigBuilder;
import org.keycloak.tests.utils.admin.ApiUtil;
import org.keycloak.testsuite.util.ProtocolMapperUtil;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
* @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
*/
@KeycloakIntegrationTest
public class GroupMappersTest extends AbstractGroupTest {
@Override
public void addTestRealms(List<RealmRepresentation> testRealms) {
RealmRepresentation testRealmRep = loadTestRealm(testRealms);
@InjectRealm(config = GroupMappersTestRealmConfig.class)
ManagedRealm managedRealm;
testRealmRep.setEventsEnabled(true);
private static final String CLIENT_ID = "my-app";
private static final String CLIENT_SECRET = "password";
private static final String CLIENT_ROLE = "customer-user";
private static final String TOP_GROUP = "topGroup";
private static final String TOP_ATTRIBUTE = "topAttribute";
private static final String LEVEL_2_ATTRIBUTE = "level2Attribute";
private static final String LEVEL_2_GROUP = "level2group";
private static final String TOP_GROUP_USER = "topGroupUser";
private static final String LEVEL_2_GROUP_USER = "level2GroupUser";
ClientRepresentation client = getClientByAlias(testRealmRep, "test-app");
Assert.assertNotNull("test-app client exists", client);
@Test
@SuppressWarnings("unchecked")
public void testGroupMappers() {
{
UserRepresentation user = ApiUtil.findUserByUsername(managedRealm.admin(), TOP_GROUP_USER);
client.setDirectAccessGrantsEnabled(true);
List<ProtocolMapperRepresentation> mappers = new LinkedList<>();
ProtocolMapperRepresentation mapper = new ProtocolMapperRepresentation();
mapper.setName("groups");
mapper.setProtocolMapper(GroupMembershipMapper.PROVIDER_ID);
mapper.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
Map<String, String> config = new HashMap<>();
config.put(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME, "groups.groups");
config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN, "true");
config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN, "true");
mapper.setConfig(config);
mappers.add(mapper);
mapper = new ProtocolMapperRepresentation();
mapper.setName("topAttribute");
mapper.setProtocolMapper(UserAttributeMapper.PROVIDER_ID);
mapper.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
config = new HashMap<>();
config.put(ProtocolMapperUtils.USER_ATTRIBUTE, "topAttribute");
config.put(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME, "topAttribute");
config.put(OIDCAttributeMapperHelper.JSON_TYPE, ProviderConfigProperty.STRING_TYPE);
config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN, "true");
config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN, "true");
mapper.setConfig(config);
mappers.add(mapper);
mapper = new ProtocolMapperRepresentation();
mapper.setName("level2Attribute");
mapper.setProtocolMapper(UserAttributeMapper.PROVIDER_ID);
mapper.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
config = new HashMap<>();
config.put(ProtocolMapperUtils.USER_ATTRIBUTE, "level2Attribute");
config.put(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME, "level2Attribute");
config.put(OIDCAttributeMapperHelper.JSON_TYPE, ProviderConfigProperty.STRING_TYPE);
config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN, "true");
config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN, "true");
mapper.setConfig(config);
mappers.add(mapper);
client.setProtocolMappers(mappers);
}
private ClientRepresentation getClientByAlias(RealmRepresentation testRealmRep, String alias) {
for (ClientRepresentation client: testRealmRep.getClients()) {
if (alias.equals(client.getClientId())) {
return client;
}
AccessToken token = login(user.getUsername(), CLIENT_ID, CLIENT_SECRET);
Assertions.assertTrue(token.getRealmAccess().getRoles().contains("user"));
Assertions.assertNotNull(token.getOtherClaims().get("groups"));
Map<String, Collection<String>> groups = (Map<String, Collection<String>>) token.getOtherClaims().get("groups");
MatcherAssert.assertThat(groups.get("groups"), Matchers.contains(TOP_GROUP));
Assertions.assertEquals("true", token.getOtherClaims().get(TOP_ATTRIBUTE));
}
{
UserRepresentation user = ApiUtil.findUserByUsername(managedRealm.admin(), LEVEL_2_GROUP_USER);
AccessToken token = login(user.getUsername(), CLIENT_ID, CLIENT_SECRET);
Assertions.assertTrue(token.getRealmAccess().getRoles().contains("user"));
Assertions.assertTrue(token.getRealmAccess().getRoles().contains("admin"));
Assertions.assertTrue(token.getResourceAccess(CLIENT_ID).getRoles().contains(CLIENT_ROLE));
Assertions.assertNotNull(token.getOtherClaims().get("groups"));
Map<String, Collection<String>> groups = (Map<String, Collection<String>>) token.getOtherClaims().get("groups");
MatcherAssert.assertThat(groups.get("groups"), Matchers.contains(LEVEL_2_GROUP));
Assertions.assertEquals("true", token.getOtherClaims().get(TOP_ATTRIBUTE));
Assertions.assertEquals("true", token.getOtherClaims().get(LEVEL_2_ATTRIBUTE));
}
return null;
}
@Test
@SuppressWarnings("unchecked")
public void testGroupMappers() throws Exception {
RealmResource realm = adminClient.realms().realm("test");
{
UserRepresentation user = realm.users().search("topGroupUser", -1, -1).get(0);
AccessToken token = login(user.getUsername(), "test-app", "password", user.getId());
Assert.assertTrue(token.getRealmAccess().getRoles().contains("user"));
Assert.assertNotNull(token.getOtherClaims().get("groups"));
Map<String, Collection<String>> groups = (Map<String, Collection<String>>) token.getOtherClaims().get("groups");
MatcherAssert.assertThat(groups.get("groups"), Matchers.contains("topGroup"));
Assert.assertEquals("true", token.getOtherClaims().get("topAttribute"));
}
{
UserRepresentation user = realm.users().search("level2GroupUser", -1, -1).get(0);
AccessToken token = login(user.getUsername(), "test-app", "password", user.getId());
Assert.assertTrue(token.getRealmAccess().getRoles().contains("user"));
Assert.assertTrue(token.getRealmAccess().getRoles().contains("admin"));
Assert.assertTrue(token.getResourceAccess("test-app").getRoles().contains("customer-user"));
Assert.assertNotNull(token.getOtherClaims().get("groups"));
Map<String, Collection<String>> groups = (Map<String, Collection<String>>) token.getOtherClaims().get("groups");
MatcherAssert.assertThat(groups.get("groups"), Matchers.contains("level2group"));
Assert.assertEquals("true", token.getOtherClaims().get("topAttribute"));
Assert.assertEquals("true", token.getOtherClaims().get("level2Attribute"));
}
}
@Test
public void testGroupMappersWithSlash() throws Exception {
RealmResource realm = adminClient.realms().realm("test");
GroupRepresentation topGroup = realm.getGroupByPath("/topGroup");
Assert.assertNotNull(topGroup);
public void testGroupMappersWithSlash() {
RealmResource realm = managedRealm.admin();
GroupRepresentation topGroup = realm.getGroupByPath("/" + TOP_GROUP);
Assertions.assertNotNull(topGroup);
GroupRepresentation childSlash = new GroupRepresentation();
childSlash.setName("child/slash");
try (Response response = realm.groups().group(topGroup.getId()).subGroup(childSlash)) {
Assert.assertEquals(Response.Status.CREATED.getStatusCode(), response.getStatus());
childSlash.setId(ApiUtil.getCreatedId(response));
}
List<UserRepresentation> users = realm.users().search("level2GroupUser", true);
Assert.assertEquals(1, users.size());
UserRepresentation user = users.iterator().next();
Response response = realm.groups().group(topGroup.getId()).subGroup(childSlash);
childSlash.setId(ApiUtil.getCreatedId(response));
UserRepresentation user = ApiUtil.findUserByUsername(managedRealm.admin(), LEVEL_2_GROUP_USER);
realm.users().get(user.getId()).joinGroup(childSlash.getId());
ProtocolMappersResource protocolMappers = ApiUtil.findClientResourceByClientId(realm, "test-app").getProtocolMappers();
ClientResource client = ApiUtil.findClientByClientId(realm, CLIENT_ID);
ProtocolMappersResource protocolMappers = client.getProtocolMappers();
ProtocolMapperRepresentation groupsMapper = ProtocolMapperUtil.getMapperByNameAndProtocol(
protocolMappers, OIDCLoginProtocol.LOGIN_PROTOCOL, "groups");
Assertions.assertNotNull(groupsMapper);
groupsMapper.getConfig().put("full.path", Boolean.TRUE.toString());
protocolMappers.update(groupsMapper.getId(), groupsMapper);
try {
AccessToken token = login(user.getUsername(), "test-app", "password", user.getId());
Assert.assertNotNull(token.getOtherClaims().get("groups"));
Map<String, Collection<String>> groups = (Map<String, Collection<String>>) token.getOtherClaims().get("groups");
MatcherAssert.assertThat(groups.get("groups"), Matchers.containsInAnyOrder(
KeycloakModelUtils.buildGroupPath(GroupProvider.DEFAULT_ESCAPE_SLASHES, "topGroup", "level2group"),
KeycloakModelUtils.buildGroupPath(GroupProvider.DEFAULT_ESCAPE_SLASHES, "topGroup", "child/slash")));
} finally {
realm.users().get(user.getId()).leaveGroup(childSlash.getId());
realm.groups().group(childSlash.getId()).remove();
groupsMapper.getConfig().remove("full.path");
protocolMappers.update(groupsMapper.getId(), groupsMapper);
groupsMapper.getConfig().remove("full.path");
managedRealm.cleanup().add(r -> {
r.users().get(user.getId()).leaveGroup(childSlash.getId());
r.groups().group(childSlash.getId()).remove();
r.clients().get(client.toRepresentation().getId())
.getProtocolMappers().update(groupsMapper.getId(), groupsMapper);
});
AccessToken token = login(user.getUsername(), CLIENT_ID, CLIENT_SECRET);
Assertions.assertNotNull(token.getOtherClaims().get("groups"));
Map<String, Collection<String>> groups = (Map<String, Collection<String>>) token.getOtherClaims().get("groups");
MatcherAssert.assertThat(groups.get("groups"), Matchers.containsInAnyOrder(
KeycloakModelUtils.buildGroupPath(GroupProvider.DEFAULT_ESCAPE_SLASHES, TOP_GROUP, LEVEL_2_GROUP),
KeycloakModelUtils.buildGroupPath(GroupProvider.DEFAULT_ESCAPE_SLASHES, TOP_GROUP, "child/slash")));
}
private static class GroupMappersTestRealmConfig implements RealmConfig {
private List<ProtocolMapperRepresentation> createMappers() {
List<ProtocolMapperRepresentation> mappers = new LinkedList<>();
ProtocolMapperRepresentation mapper = new ProtocolMapperRepresentation();
mapper.setName("groups");
mapper.setProtocolMapper(GroupMembershipMapper.PROVIDER_ID);
mapper.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
Map<String, String> config = new HashMap<>();
config.put(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME, "groups.groups");
config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN, "true");
config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN, "true");
mapper.setConfig(config);
mappers.add(mapper);
mapper = new ProtocolMapperRepresentation();
mapper.setName(TOP_ATTRIBUTE);
mapper.setProtocolMapper(UserAttributeMapper.PROVIDER_ID);
mapper.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
config = new HashMap<>();
config.put(ProtocolMapperUtils.USER_ATTRIBUTE, TOP_ATTRIBUTE);
config.put(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME, TOP_ATTRIBUTE);
config.put(OIDCAttributeMapperHelper.JSON_TYPE, ProviderConfigProperty.STRING_TYPE);
config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN, "true");
config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN, "true");
mapper.setConfig(config);
mappers.add(mapper);
mapper = new ProtocolMapperRepresentation();
mapper.setName(LEVEL_2_ATTRIBUTE);
mapper.setProtocolMapper(UserAttributeMapper.PROVIDER_ID);
mapper.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
config = new HashMap<>();
config.put(ProtocolMapperUtils.USER_ATTRIBUTE, LEVEL_2_ATTRIBUTE);
config.put(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME, LEVEL_2_ATTRIBUTE);
config.put(OIDCAttributeMapperHelper.JSON_TYPE, ProviderConfigProperty.STRING_TYPE);
config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN, "true");
config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN, "true");
mapper.setConfig(config);
mappers.add(mapper);
return mappers;
}
@Override
public RealmConfigBuilder configure(RealmConfigBuilder realm) {
List<ProtocolMapperRepresentation> mappers = createMappers();
realm.addClient(CLIENT_ID)
.enabled(true)
.secret(CLIENT_SECRET)
.directAccessGrants()
.protocolMappers(mappers);
realm.eventsEnabled(true)
.clientRoles(CLIENT_ID, CLIENT_ROLE);
GroupRepresentation subGroup = GroupConfigBuilder.create()
.name(LEVEL_2_GROUP)
.realmRoles("admin")
.clientRole(CLIENT_ID, CLIENT_ROLE)
.attribute(LEVEL_2_ATTRIBUTE, "true")
.build();
GroupRepresentation subGroup2 = GroupConfigBuilder.create()
.name("level2group2")
.realmRoles("admin")
.clientRole(CLIENT_ID, CLIENT_ROLE)
.attribute(LEVEL_2_ATTRIBUTE, "true")
.build();
realm.addGroup(TOP_GROUP)
.attribute(TOP_ATTRIBUTE, "true")
.realmRoles("user")
.subGroups(subGroup, subGroup2);
realm.addUser(TOP_GROUP_USER)
.name("John", "Doe")
.enabled(true)
.email("top@redhat.com")
.password("password")
.groups(TOP_GROUP);
realm.addUser(LEVEL_2_GROUP_USER)
.name("Jane", "Doe")
.enabled(true)
.email("level2@redhat.com")
.password("password")
.groups("topGroup/level2group");
return realm;
}
}
}
File diff suppressed because it is too large Load Diff