From d2b45373d3eda82b63d54a94cbac2229f0db90fd Mon Sep 17 00:00:00 2001 From: Lukas Hanusovsky Date: Thu, 5 Jun 2025 14:59:41 +0200 Subject: [PATCH] Move PartialImportTest.java to the new testsuite Part of: #34494 Signed-off-by: Lukas Hanusovsky --- .../realm/RealmConfigBuilder.java | 5 + tests/base/pom.xml | 5 + .../AbstractPartialImportTest.java | 348 +++++++ .../PartialImportClientTest.java | 184 ++++ .../partialimport/PartialImportGroupTest.java | 50 + .../PartialImportProvidersTest.java | 97 ++ .../partialimport/PartialImportRealmTest.java | 72 ++ .../partialimport/PartialImportRolesTest.java | 100 ++ .../partialimport/PartialImportUserTest.java | 191 ++++ .../sample-authz-partial-import.json | 58 ++ tests/custom-scripts/pom.xml | 33 + .../resources/META-INF/keycloak-scripts.json | 13 + .../main/resources/scripts/default-policy.js | 1 + tests/pom.xml | 3 +- .../partialimport/PartialImportTest.java | 984 ------------------ 15 files changed, 1159 insertions(+), 985 deletions(-) create mode 100644 tests/base/src/test/java/org/keycloak/tests/admin/partialimport/AbstractPartialImportTest.java create mode 100644 tests/base/src/test/java/org/keycloak/tests/admin/partialimport/PartialImportClientTest.java create mode 100644 tests/base/src/test/java/org/keycloak/tests/admin/partialimport/PartialImportGroupTest.java create mode 100644 tests/base/src/test/java/org/keycloak/tests/admin/partialimport/PartialImportProvidersTest.java create mode 100644 tests/base/src/test/java/org/keycloak/tests/admin/partialimport/PartialImportRealmTest.java create mode 100644 tests/base/src/test/java/org/keycloak/tests/admin/partialimport/PartialImportRolesTest.java create mode 100644 tests/base/src/test/java/org/keycloak/tests/admin/partialimport/PartialImportUserTest.java create mode 100644 tests/base/src/test/resources/org/keycloak/tests/admin/partialimport/sample-authz-partial-import.json create mode 100755 tests/custom-scripts/pom.xml create mode 100644 tests/custom-scripts/src/main/resources/META-INF/keycloak-scripts.json create mode 100644 tests/custom-scripts/src/main/resources/scripts/default-policy.js delete mode 100644 testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/partialimport/PartialImportTest.java diff --git a/test-framework/core/src/main/java/org/keycloak/testframework/realm/RealmConfigBuilder.java b/test-framework/core/src/main/java/org/keycloak/testframework/realm/RealmConfigBuilder.java index cd3306b99bb..32989e3d2e2 100644 --- a/test-framework/core/src/main/java/org/keycloak/testframework/realm/RealmConfigBuilder.java +++ b/test-framework/core/src/main/java/org/keycloak/testframework/realm/RealmConfigBuilder.java @@ -210,6 +210,11 @@ public class RealmConfigBuilder { return this; } + public RealmConfigBuilder duplicateEmailsAllowed(boolean duplicateEmailsAllowed) { + rep.setDuplicateEmailsAllowed(duplicateEmailsAllowed); + return this; + } + /** * Best practice is to use other convenience methods when configuring a realm, but while the framework is under * active development there may not be a way to perform all updates required. In these cases this method allows diff --git a/tests/base/pom.xml b/tests/base/pom.xml index c6c5145aa3f..8a88c467391 100755 --- a/tests/base/pom.xml +++ b/tests/base/pom.xml @@ -105,6 +105,11 @@ keycloak-tests-custom-providers ${project.version} + + org.keycloak.tests + keycloak-tests-custom-scripts + ${project.version} + org.junit.platform junit-platform-suite diff --git a/tests/base/src/test/java/org/keycloak/tests/admin/partialimport/AbstractPartialImportTest.java b/tests/base/src/test/java/org/keycloak/tests/admin/partialimport/AbstractPartialImportTest.java new file mode 100644 index 00000000000..322eaa407ed --- /dev/null +++ b/tests/base/src/test/java/org/keycloak/tests/admin/partialimport/AbstractPartialImportTest.java @@ -0,0 +1,348 @@ +package org.keycloak.tests.admin.partialimport; + +import jakarta.ws.rs.core.Response; +import org.junit.jupiter.api.BeforeEach; +import org.keycloak.admin.client.resource.ClientResource; +import org.keycloak.common.constants.ServiceAccountConstants; +import org.keycloak.models.UserModel; +import org.keycloak.partialimport.PartialImportResults; +import org.keycloak.representations.idm.ClientRepresentation; +import org.keycloak.representations.idm.GroupRepresentation; +import org.keycloak.representations.idm.IdentityProviderMapperRepresentation; +import org.keycloak.representations.idm.IdentityProviderRepresentation; +import org.keycloak.representations.idm.PartialImportRepresentation; +import org.keycloak.representations.idm.RoleRepresentation; +import org.keycloak.representations.idm.RolesRepresentation; +import org.keycloak.representations.idm.UserRepresentation; +import org.keycloak.representations.idm.authorization.ResourceServerRepresentation; +import org.keycloak.testframework.annotations.InjectAdminEvents; +import org.keycloak.testframework.annotations.InjectClient; +import org.keycloak.testframework.annotations.InjectRealm; +import org.keycloak.testframework.events.AdminEvents; +import org.keycloak.testframework.injection.LifeCycle; +import org.keycloak.testframework.realm.ClientConfig; +import org.keycloak.testframework.realm.ClientConfigBuilder; +import org.keycloak.testframework.realm.ManagedClient; +import org.keycloak.testframework.realm.ManagedRealm; +import org.keycloak.testframework.realm.RealmConfig; +import org.keycloak.testframework.realm.RealmConfigBuilder; +import org.keycloak.testframework.realm.UserConfigBuilder; +import org.keycloak.testframework.server.KeycloakServerConfig; +import org.keycloak.testframework.server.KeycloakServerConfigBuilder; +import org.keycloak.tests.utils.admin.ApiUtil; +import org.keycloak.util.JsonSerialization; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +public class AbstractPartialImportTest { + + @InjectRealm(lifecycle = LifeCycle.METHOD, config = PartialImportRealmConfig.class) + ManagedRealm managedRealm; + + @InjectRealm(ref = "master", attachTo = "master") + ManagedRealm masterRealm; + + @InjectClient(ref = "clientRolesClient", config = PartialImportRolesClientConfig.class) + ManagedClient rolesClient; + + @InjectClient(ref = "clientServiceAccount", config = PartialImportServiceClientConfig.class) + ManagedClient serviceClient; + + @InjectAdminEvents + AdminEvents adminEvents; + + private static final String CLIENT_ROLES_CLIENT = "clientRolesClient"; + protected static final String CLIENT_SERVICE_ACCOUNT = "clientServiceAccount"; + protected static final String USER_PREFIX = "user"; + private static final String GROUP_PREFIX = "group"; + protected static final String CLIENT_PREFIX = "client"; + protected static final String REALM_ROLE_PREFIX = "realmRole"; + protected static final String CLIENT_ROLE_PREFIX = "clientRole"; + protected static final String[] IDP_ALIASES = {"twitter", "github", "facebook", "google", "linkedin-openid-connect", "microsoft", "stackoverflow"}; + protected static final int NUM_ENTITIES = IDP_ALIASES.length; + private static final ResourceServerRepresentation resourceServerSampleSettings; + + protected PartialImportRepresentation piRep; + + static { + try { + resourceServerSampleSettings = JsonSerialization.readValue( + AbstractPartialImportTest.class.getResourceAsStream("sample-authz-partial-import.json"), + ResourceServerRepresentation.class); + } catch (IOException e) { + throw new IllegalStateException("Cannot load sample resource server configuration", e); + } + } + + @BeforeEach + public void init() { + piRep = new PartialImportRepresentation(); + } + + protected void setFail() { + piRep.setIfResourceExists(PartialImportRepresentation.Policy.FAIL.toString()); + } + + protected void setSkip() { + piRep.setIfResourceExists(PartialImportRepresentation.Policy.SKIP.toString()); + } + + protected void setOverwrite() { + piRep.setIfResourceExists(PartialImportRepresentation.Policy.OVERWRITE.toString()); + } + + protected PartialImportResults doImport() { + + try (Response response = managedRealm.admin().partialImport(piRep)) { + return response.readEntity(PartialImportResults.class); + } + } + + protected void addUsers() { + List users = new ArrayList<>(); + + for (int i = 0; i < NUM_ENTITIES; i++) { + UserRepresentation user = UserConfigBuilder.create().username(USER_PREFIX + i).email(USER_PREFIX + i + "@foo.com").name("foo", "bar").build(); + users.add(user); + } + + piRep.setUsers(users); + } + + protected void addUsersWithIds() { + List users = new ArrayList<>(); + + for (int i = 0; i < NUM_ENTITIES; i++) { + UserRepresentation user = UserConfigBuilder.create().id(UUID.randomUUID().toString()).username(USER_PREFIX + i).email(USER_PREFIX + i + "@foo.com").name("foo", "bar").build(); + users.add(user); + } + + piRep.setUsers(users); + } + + protected void addUsersWithTermsAndConditions() { + List users = new ArrayList<>(); + List requiredActions = new ArrayList<>(); + requiredActions.add(UserModel.RequiredAction.TERMS_AND_CONDITIONS.name()); + + for (int i = 0; i < NUM_ENTITIES; i++) { + UserRepresentation user = UserConfigBuilder.create().username(USER_PREFIX + i).email(USER_PREFIX + i + "@foo.com").name("foo", "bar").build(); + user.setRequiredActions(requiredActions); + users.add(user); + } + + piRep.setUsers(users); + } + + protected void addGroups() { + List groups = new ArrayList<>(); + + for (int i=0; i < NUM_ENTITIES; i++) { + GroupRepresentation group = new GroupRepresentation(); + group.setName(GROUP_PREFIX + i); + group.setPath("/" + GROUP_PREFIX + i); + groups.add(group); + } + + piRep.setGroups(groups); + } + + protected void addClients(boolean withServiceAccounts) { + List clients = new ArrayList<>(); + List serviceAccounts = new ArrayList<>(); + + for (int i = 0; i < NUM_ENTITIES; i++) { + ClientRepresentation client = new ClientRepresentation(); + client.setClientId(CLIENT_PREFIX + i); + client.setName(CLIENT_PREFIX + i); + clients.add(client); + if (withServiceAccounts) { + client.setServiceAccountsEnabled(true); + client.setBearerOnly(false); + client.setPublicClient(false); + client.setAuthorizationSettings(resourceServerSampleSettings); + client.setAuthorizationServicesEnabled(true); + // create the user service account + UserRepresentation serviceAccount = new UserRepresentation(); + serviceAccount.setUsername(ServiceAccountConstants.SERVICE_ACCOUNT_USER_PREFIX + client.getClientId()); + serviceAccount.setEnabled(true); + serviceAccount.setEmail(serviceAccount.getUsername() + "@placeholder.org"); + serviceAccount.setServiceAccountClientId(client.getClientId()); + serviceAccounts.add(serviceAccount); + } + } + + if (withServiceAccounts) { + if (piRep.getUsers() == null) { + piRep.setUsers(new ArrayList<>()); + } + piRep.getUsers().addAll(serviceAccounts); + } + piRep.setClients(clients); + } + + protected void addProviders() { + addProviders(false); + } + + private void addProviders(boolean withMappers) { + List providers = new ArrayList<>(); + List mappers = new ArrayList<>(); + + for (String alias : IDP_ALIASES) { + IdentityProviderRepresentation idpRep = new IdentityProviderRepresentation(); + idpRep.setAlias(alias); + idpRep.setProviderId(alias); + idpRep.setEnabled(true); + idpRep.setAuthenticateByDefault(false); + idpRep.setFirstBrokerLoginFlowAlias("first broker login"); + + Map config = new HashMap<>(); + config.put("clientSecret", "secret"); + config.put("clientId", alias); + idpRep.setConfig(config); + providers.add(idpRep); + + if(withMappers) { + Map mapConfig = new HashMap<>(); + mapConfig.put("external.role", "IDP.TEST_ROLE"); + mapConfig.put("syncMode", "FORCE"); + mapConfig.put("role", "TEST_ROLE"); + + IdentityProviderMapperRepresentation idpMapRep = new IdentityProviderMapperRepresentation(); + idpMapRep.setName(alias+"_mapper"); + idpMapRep.setIdentityProviderAlias(alias); + idpMapRep.setIdentityProviderMapper("keycloak-oidc-role-to-role-idp-mapper"); + idpMapRep.setConfig(mapConfig); + + mappers.add(idpMapRep); + } + } + + piRep.setIdentityProviders(providers); + if (withMappers) { + piRep.setIdentityProviderMappers(mappers); + } + } + + protected void addProviderMappers() { + addProviders(true); + } + + private List makeRoles(String prefix) { + List roles = new ArrayList<>(); + + for (int i = 0; i < NUM_ENTITIES; i++) { + RoleRepresentation role = new RoleRepresentation(); + role.setName(prefix + i); + roles.add(role); + } + + return roles; + } + + protected void addRealmRoles() { + RolesRepresentation roles = piRep.getRoles(); + if (roles == null) roles = new RolesRepresentation(); + roles.setRealm(makeRoles(REALM_ROLE_PREFIX)); + piRep.setRoles(roles); + } + + protected void addClientRoles() { + RolesRepresentation roles = piRep.getRoles(); + if (roles == null) roles = new RolesRepresentation(); + Map> clientRolesMap = new HashMap<>(); + clientRolesMap.put(CLIENT_ROLES_CLIENT, makeRoles(CLIENT_ROLE_PREFIX)); + roles.setClient(clientRolesMap); + piRep.setRoles(roles); + } + + protected void testFail() { + setFail(); + PartialImportResults results = doImport(); + assertNull(results.getErrorMessage()); + results = doImport(); // second time should fail + assertNotNull(results.getErrorMessage()); + } + + protected void testSkip() { + testSkip(NUM_ENTITIES); + } + + protected void testSkip(int numberEntities) { + setSkip(); + PartialImportResults results = doImport(); + assertEquals(numberEntities, results.getAdded()); + + results = doImport(); + assertEquals(numberEntities, results.getSkipped()); + } + + protected void testOverwrite() { + testOverwrite(NUM_ENTITIES); + } + + protected void testOverwrite(int numberEntities) { + setOverwrite(); + PartialImportResults results = doImport(); + assertEquals(numberEntities, results.getAdded()); + + results = doImport(); + assertEquals(numberEntities, results.getOverwritten()); + } + + private static class PartialImportRealmConfig implements RealmConfig { + + @Override + public RealmConfigBuilder configure(RealmConfigBuilder builder) { + builder.duplicateEmailsAllowed(false); + + return builder; + } + } + + private static class PartialImportRolesClientConfig implements ClientConfig { + + @Override + public ClientConfigBuilder configure(ClientConfigBuilder builder) { + builder.clientId(CLIENT_ROLES_CLIENT); + builder.name(CLIENT_ROLES_CLIENT); + builder.protocol("openid-connect"); + + return builder; + } + } + + private static class PartialImportServiceClientConfig implements ClientConfig { + + @Override + public ClientConfigBuilder configure(ClientConfigBuilder builder) { + builder.clientId(CLIENT_SERVICE_ACCOUNT); + builder.name(CLIENT_SERVICE_ACCOUNT); + builder.secret("secret"); + builder.protocol("openid-connect"); + builder.rootUrl("http://localhost/foo"); + builder.publicClient(false); + builder.serviceAccountsEnabled(true); + + return builder; + } + } + + public static class PartialImportServerConfig implements KeycloakServerConfig { + + @Override + public KeycloakServerConfigBuilder configure(KeycloakServerConfigBuilder builder) { + return builder.dependency("org.keycloak.tests", "keycloak-tests-custom-scripts"); + } + } +} diff --git a/tests/base/src/test/java/org/keycloak/tests/admin/partialimport/PartialImportClientTest.java b/tests/base/src/test/java/org/keycloak/tests/admin/partialimport/PartialImportClientTest.java new file mode 100644 index 00000000000..7e7425bd7ce --- /dev/null +++ b/tests/base/src/test/java/org/keycloak/tests/admin/partialimport/PartialImportClientTest.java @@ -0,0 +1,184 @@ +package org.keycloak.tests.admin.partialimport; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.keycloak.admin.client.resource.AuthorizationResource; +import org.keycloak.admin.client.resource.ClientResource; +import org.keycloak.admin.client.resource.UserResource; +import org.keycloak.common.constants.ServiceAccountConstants; +import org.keycloak.partialimport.PartialImportResult; +import org.keycloak.partialimport.PartialImportResults; +import org.keycloak.partialimport.ResourceType; +import org.keycloak.representations.idm.ClientRepresentation; +import org.keycloak.representations.idm.PartialImportRepresentation; +import org.keycloak.representations.idm.RoleRepresentation; +import org.keycloak.representations.idm.RolesRepresentation; +import org.keycloak.representations.idm.UserRepresentation; +import org.keycloak.representations.idm.authorization.ResourceServerRepresentation; +import org.keycloak.testframework.annotations.KeycloakIntegrationTest; +import org.keycloak.tests.utils.Assert; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@KeycloakIntegrationTest(config = AbstractPartialImportTest.PartialImportServerConfig.class) +public class PartialImportClientTest extends AbstractPartialImportTest { + + @Test + public void testAddClients() { + setFail(); + addClients(false); + + PartialImportResults results = doImport(); + assertEquals(NUM_ENTITIES, results.getAdded()); + + for (PartialImportResult result : results.getResults()) { + String id = result.getId(); + ClientResource clientRsc = managedRealm.admin().clients().get(id); + ClientRepresentation client = clientRsc.toRepresentation(); + assertTrue(client.getName().startsWith(CLIENT_PREFIX)); + } + } + + @Test + public void testAddClientsWithServiceAccountsAndAuthorization() { + setFail(); + addClients(true); + + PartialImportResults results = doImport(); + assertEquals(NUM_ENTITIES * 2, results.getAdded()); + + for (PartialImportResult result : results.getResults()) { + if (result.getResourceType().equals(ResourceType.CLIENT)) { + String id = result.getId(); + ClientResource clientRsc = managedRealm.admin().clients().get(id); + ClientRepresentation client = clientRsc.toRepresentation(); + assertTrue(client.getName().startsWith(CLIENT_PREFIX)); + Assertions.assertTrue(client.isServiceAccountsEnabled()); + Assertions.assertTrue(client.getAuthorizationServicesEnabled()); + AuthorizationResource authRsc = clientRsc.authorization(); + ResourceServerRepresentation authRep = authRsc.exportSettings(); + Assertions.assertNotNull(authRep); + Assertions.assertEquals(2, authRep.getResources().size()); + Assertions.assertEquals(3, authRep.getPolicies().size()); + } else { + UserResource userRsc = managedRealm.admin().users().get(result.getId()); + Assert.assertTrue(userRsc.toRepresentation().getUsername().startsWith( + ServiceAccountConstants.SERVICE_ACCOUNT_USER_PREFIX + CLIENT_PREFIX)); + } + } + } + + @Test + public void testAddClientsFail() { + addClients(false); + testFail(); + } + + @Test + public void testAddClientsSkip() { + addClients(false); + testSkip(); + } + + @Test + public void testAddClientsSkipWithServiceAccountsAndAuthorization() { + addClients(true); + setSkip(); + PartialImportResults results = doImport(); + assertEquals(NUM_ENTITIES * 2, results.getAdded()); + + results = doImport(); + assertEquals(NUM_ENTITIES * 2, results.getSkipped()); + } + + @Test + public void testAddClientsOverwrite() { + addClients(false); + testOverwrite(); + } + + @Test + public void testAddClientsOverwriteWithServiceAccountsAndAuthorization() { + addClients(true); + setOverwrite(); + PartialImportResults results = doImport(); + assertEquals(NUM_ENTITIES * 2, results.getAdded()); + + results = doImport(); + assertEquals(NUM_ENTITIES * 2, results.getOverwritten()); + } + + @Test + public void testAddClientsOverwriteServiceAccountsWithNoServiceAccounts() { + addClients(true); + setOverwrite(); + PartialImportResults results = doImport(); + assertEquals(NUM_ENTITIES * 2, results.getAdded()); + // check the service accounts are there + for (int i = 0; i < NUM_ENTITIES; i++) { + List l = managedRealm.admin().users().search(ServiceAccountConstants.SERVICE_ACCOUNT_USER_PREFIX + CLIENT_PREFIX + i); + Assertions.assertEquals(1, l.size()); + } + // re-import without service accounts enabled + piRep = new PartialImportRepresentation(); + addClients(false); + setOverwrite(); + results = doImport(); + assertEquals(NUM_ENTITIES, results.getOverwritten()); + // check the service accounts have been removed + for (int i = 0; i < NUM_ENTITIES; i++) { + List l = managedRealm.admin().users().search(ServiceAccountConstants.SERVICE_ACCOUNT_USER_PREFIX + CLIENT_PREFIX + i); + Assertions.assertEquals(0, l.size()); + } + } + + //KEYCLOAK-3042 + @Test + public void testOverwriteExistingClientWithRoles() { + setOverwrite(); + + ClientRepresentation client = masterRealm.admin().clients().findByClientId("broker").get(0); + List clientRoles = masterRealm.admin().clients().get(client.getId()).roles().list(); + + Map> clients = new HashMap<>(); + clients.put(client.getClientId(), clientRoles); + + RolesRepresentation roles = new RolesRepresentation(); + roles.setClient(clients); + + piRep.setClients(List.of(client)); + piRep.setRoles(roles); + + doImport(); + } + + // KEYCLOAK-6058 + @Test + public void testOverwriteExistingInternalClient() { + setOverwrite(); + ClientRepresentation client = masterRealm.admin().clients().findByClientId("security-admin-console").get(0); + ClientRepresentation client2 = masterRealm.admin().clients().findByClientId("master-realm").get(0); + piRep.setClients(Arrays.asList(client, client2)); + + PartialImportResults result = doImport(); + Assertions.assertEquals(0, result.getOverwritten()); + } + + @Test + public void testOverwriteExistingClientWithServiceAccount() { + setOverwrite(); + piRep.setClients(Collections.singletonList(serviceClient.admin().toRepresentation())); + + Assertions.assertEquals(1, doImport().getOverwritten()); + + ClientRepresentation client = managedRealm.admin().clients().findByClientId(CLIENT_SERVICE_ACCOUNT).get(0); + Assertions.assertDoesNotThrow(() -> managedRealm.admin().clients().get(client.getId()).getServiceAccountUser()); + } +} diff --git a/tests/base/src/test/java/org/keycloak/tests/admin/partialimport/PartialImportGroupTest.java b/tests/base/src/test/java/org/keycloak/tests/admin/partialimport/PartialImportGroupTest.java new file mode 100644 index 00000000000..38aaa09dfb5 --- /dev/null +++ b/tests/base/src/test/java/org/keycloak/tests/admin/partialimport/PartialImportGroupTest.java @@ -0,0 +1,50 @@ +/* + * Copyright 2016 Red Hat Inc. and/or its affiliates and other contributors + * as indicated by the @author tags. All rights reserved. + * + * 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.tests.admin.partialimport; + +import org.junit.jupiter.api.Test; +import org.keycloak.testframework.annotations.KeycloakIntegrationTest; + +/** + * Tests for the partial import endpoint in admin client. Also tests the + * server side functionality of each resource along with "fail, skip, overwrite" + * functions. + * + * @author Stan Silvert ssilvert@redhat.com (C) 2016 Red Hat Inc. + */ +@KeycloakIntegrationTest +public class PartialImportGroupTest extends AbstractPartialImportTest { + + @Test + public void testAddGroupsFail() { + addGroups(); + testFail(); + } + + + @Test + public void testAddGroupsSkip() { + addGroups(); + testSkip(); + } + + @Test + public void testAddGroupsOverwrite() { + addGroups(); + testOverwrite(); + } +} diff --git a/tests/base/src/test/java/org/keycloak/tests/admin/partialimport/PartialImportProvidersTest.java b/tests/base/src/test/java/org/keycloak/tests/admin/partialimport/PartialImportProvidersTest.java new file mode 100644 index 00000000000..1581eb62946 --- /dev/null +++ b/tests/base/src/test/java/org/keycloak/tests/admin/partialimport/PartialImportProvidersTest.java @@ -0,0 +1,97 @@ +package org.keycloak.tests.admin.partialimport; + +import org.junit.jupiter.api.Test; +import org.keycloak.admin.client.resource.IdentityProviderResource; +import org.keycloak.partialimport.PartialImportResult; +import org.keycloak.partialimport.PartialImportResults; +import org.keycloak.partialimport.ResourceType; +import org.keycloak.representations.idm.IdentityProviderMapperRepresentation; +import org.keycloak.representations.idm.IdentityProviderRepresentation; +import org.keycloak.testframework.annotations.KeycloakIntegrationTest; + +import java.util.Arrays; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@KeycloakIntegrationTest(config = AbstractPartialImportTest.PartialImportServerConfig.class) +public class PartialImportProvidersTest extends AbstractPartialImportTest { + + @Test + public void testAddProviders() { + setFail(); + addProviders(); + + PartialImportResults results = doImport(); + assertEquals(IDP_ALIASES.length, results.getAdded()); + + for (PartialImportResult result : results.getResults()) { + String id = result.getId(); + IdentityProviderResource idpRsc = managedRealm.admin().identityProviders().get(id); + IdentityProviderRepresentation idp = idpRsc.toRepresentation(); + Map config = idp.getConfig(); + assertTrue(Arrays.asList(IDP_ALIASES).contains(config.get("clientId"))); + } + } + + @Test + public void testAddProviderMappers() { + setFail(); + addProviderMappers(); + + PartialImportResults results = doImport(); + assertEquals(IDP_ALIASES.length*2, results.getAdded()); + + for (PartialImportResult result : results.getResults()) { + if (ResourceType.IDP.equals(result.getResourceType())) { + String id = result.getId(); + IdentityProviderResource idpRsc = managedRealm.admin().identityProviders().get(id); + IdentityProviderMapperRepresentation idpMap = idpRsc.getMappers().get(0); + String alias = idpMap.getIdentityProviderAlias(); + assertTrue(Arrays.asList(IDP_ALIASES).contains(alias)); + assertEquals(alias + "_mapper", idpMap.getName()); + assertEquals("keycloak-oidc-role-to-role-idp-mapper", idpMap.getIdentityProviderMapper()); + assertEquals("IDP.TEST_ROLE", idpMap.getConfig().get("external.role")); + assertEquals("FORCE", idpMap.getConfig().get("syncMode")); + assertEquals("TEST_ROLE", idpMap.getConfig().get("role")); + } + } + } + + @Test + public void testAddProvidersFail() { + addProviders(); + testFail(); + } + + @Test + public void testAddProviderMappersFail() { + addProviderMappers(); + testFail(); + } + + @Test + public void testAddProvidersSkip() { + addProviders(); + testSkip(); + } + + @Test + public void testAddProviderMappersSkip() { + addProviderMappers(); + testSkip(NUM_ENTITIES*2); + } + + @Test + public void testAddProvidersOverwrite() { + addProviders(); + testOverwrite(); + } + + @Test + public void testAddProviderMappersOverwrite() { + addProviderMappers(); + testOverwrite(NUM_ENTITIES*2); + } +} diff --git a/tests/base/src/test/java/org/keycloak/tests/admin/partialimport/PartialImportRealmTest.java b/tests/base/src/test/java/org/keycloak/tests/admin/partialimport/PartialImportRealmTest.java new file mode 100644 index 00000000000..1a6c9e1dc0c --- /dev/null +++ b/tests/base/src/test/java/org/keycloak/tests/admin/partialimport/PartialImportRealmTest.java @@ -0,0 +1,72 @@ +package org.keycloak.tests.admin.partialimport; + +import org.junit.jupiter.api.Test; +import org.keycloak.partialimport.PartialImportResults; +import org.keycloak.testframework.annotations.KeycloakIntegrationTest; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +@KeycloakIntegrationTest(config = AbstractPartialImportTest.PartialImportServerConfig.class) +public class PartialImportRealmTest extends AbstractPartialImportTest { + + private static final int NUM_RESOURCE_TYPES = 6; + + @Test + public void testEverythingFail() { + setFail(); + importEverything(false); + PartialImportResults results = doImport(); // second import will fail because not allowed to skip or overwrite + assertNotNull(results.getErrorMessage()); + } + + @Test + public void testEverythingSkip() { + setSkip(); + importEverything(false); + PartialImportResults results = doImport(); + assertEquals(NUM_ENTITIES * NUM_RESOURCE_TYPES, results.getSkipped()); + } + + @Test + public void testEverythingSkipWithServiceAccounts() { + setSkip(); + importEverything(true); + PartialImportResults results = doImport(); + assertEquals(NUM_ENTITIES * (NUM_RESOURCE_TYPES + 1), results.getSkipped()); + } + + @Test + public void testEverythingOverwrite() { + setOverwrite(); + importEverything(false); + PartialImportResults results = doImport(); + assertEquals(NUM_ENTITIES * NUM_RESOURCE_TYPES, results.getOverwritten()); + } + + @Test + public void testEverythingOverwriteWithServiceAccounts() { + setOverwrite(); + importEverything(true); + PartialImportResults results = doImport(); + assertEquals(NUM_ENTITIES * (NUM_RESOURCE_TYPES + 1), results.getOverwritten()); + } + + private void importEverything(boolean withServiceAccounts) { + addUsers(); + addGroups(); + addClients(withServiceAccounts); + addProviders(); + addRealmRoles(); + addClientRoles(); + + PartialImportResults results = doImport(); + assertNull(results.getErrorMessage()); + if (withServiceAccounts) { + assertEquals(NUM_ENTITIES * (NUM_RESOURCE_TYPES + 1), results.getAdded()); + } else { + assertEquals(NUM_ENTITIES * NUM_RESOURCE_TYPES, results.getAdded()); + } + } +} diff --git a/tests/base/src/test/java/org/keycloak/tests/admin/partialimport/PartialImportRolesTest.java b/tests/base/src/test/java/org/keycloak/tests/admin/partialimport/PartialImportRolesTest.java new file mode 100644 index 00000000000..b372d569ba4 --- /dev/null +++ b/tests/base/src/test/java/org/keycloak/tests/admin/partialimport/PartialImportRolesTest.java @@ -0,0 +1,100 @@ +package org.keycloak.tests.admin.partialimport; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.keycloak.admin.client.resource.RoleResource; +import org.keycloak.partialimport.PartialImportResult; +import org.keycloak.partialimport.PartialImportResults; +import org.keycloak.representations.idm.RoleRepresentation; +import org.keycloak.representations.idm.RolesRepresentation; +import org.keycloak.testframework.annotations.KeycloakIntegrationTest; + +import java.util.Collections; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@KeycloakIntegrationTest(config = AbstractPartialImportTest.PartialImportServerConfig.class) +public class PartialImportRolesTest extends AbstractPartialImportTest { + + @Test + public void testAddRealmRoles() { + setFail(); + addRealmRoles(); + + PartialImportResults results = doImport(); + assertEquals(NUM_ENTITIES, results.getAdded()); + + for (PartialImportResult result : results.getResults()) { + String name = result.getResourceName(); + RoleResource roleRsc = managedRealm.admin().roles().get(name); + RoleRepresentation role = roleRsc.toRepresentation(); + assertTrue(role.getName().startsWith(REALM_ROLE_PREFIX)); + } + } + + @Test + public void testAddClientRoles() { + setFail(); + addClientRoles(); + + PartialImportResults results = doImport(); + assertEquals(NUM_ENTITIES, results.getAdded()); + + List clientRoles = rolesClient.admin().roles().list(); + assertEquals(NUM_ENTITIES, clientRoles.size()); + + for (RoleRepresentation roleRep : clientRoles) { + assertTrue(roleRep.getName().startsWith(CLIENT_ROLE_PREFIX)); + } + } + + @Test + public void testAddRealmRolesFail() { + addRealmRoles(); + testFail(); + } + + @Test + public void testAddClientRolesFail() { + addClientRoles(); + testFail(); + } + + @Test + public void testAddRealmRolesSkip() { + addRealmRoles(); + testSkip(); + } + + @Test + public void testAddClientRolesSkip() { + addClientRoles(); + testSkip(); + } + + @Test + public void testAddRealmRolesOverwrite() { + addRealmRoles(); + testOverwrite(); + } + + @Test + public void testAddClientRolesOverwrite() { + addClientRoles(); + testOverwrite(); + } + + @Test + public void testOverwriteDefaultRole() { + setOverwrite(); + + RolesRepresentation roles = new RolesRepresentation(); + RoleRepresentation oldDefaultRole = managedRealm.admin().toRepresentation().getDefaultRole(); + roles.setRealm(Collections.singletonList(oldDefaultRole)); + piRep.setRoles(roles); + + Assertions.assertEquals(1, doImport().getOverwritten(), "default role should have been overwritten"); + } +} diff --git a/tests/base/src/test/java/org/keycloak/tests/admin/partialimport/PartialImportUserTest.java b/tests/base/src/test/java/org/keycloak/tests/admin/partialimport/PartialImportUserTest.java new file mode 100644 index 00000000000..32d8fe879c9 --- /dev/null +++ b/tests/base/src/test/java/org/keycloak/tests/admin/partialimport/PartialImportUserTest.java @@ -0,0 +1,191 @@ +package org.keycloak.tests.admin.partialimport; + +import jakarta.ws.rs.core.Response; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.keycloak.admin.client.resource.UserResource; +import org.keycloak.authentication.requiredactions.TermsAndConditions; +import org.keycloak.events.admin.OperationType; +import org.keycloak.partialimport.PartialImportResult; +import org.keycloak.partialimport.PartialImportResults; +import org.keycloak.representations.idm.AdminEventRepresentation; +import org.keycloak.representations.idm.RealmRepresentation; +import org.keycloak.representations.idm.UserRepresentation; +import org.keycloak.testframework.annotations.KeycloakIntegrationTest; +import org.keycloak.testframework.realm.UserConfigBuilder; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import static org.hamcrest.CoreMatchers.hasItem; +import static org.hamcrest.CoreMatchers.startsWith; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.equalTo; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@KeycloakIntegrationTest(config = AbstractPartialImportTest.PartialImportServerConfig.class) +public class PartialImportUserTest extends AbstractPartialImportTest { + + @Test + public void testAddUsers() { + adminEvents.clear(); + + setFail(); + addUsers(); + + PartialImportResults results = doImport(); + assertEquals(NUM_ENTITIES, results.getAdded()); + + // Need to do this way as admin events from partial import are unsorted + Set userIds = new HashSet<>(); + for (int i=0 ; i userRepIds = new HashSet<>(); + for (UserRepresentation userRep : piRep.getUsers()) { + userRepIds.add(userRep.getId()); + } + + PartialImportResults results = doImport(); + assertEquals(NUM_ENTITIES, results.getAdded()); + + // Need to do this way as admin events from partial import are unsorted + Set userIds = new HashSet<>(); + for (int i=0 ; i userIds = new HashSet<>(); + for (int i=0 ; i + + + + + keycloak-tests-parent + org.keycloak.tests + 999.0.0-SNAPSHOT + ../pom.xml + + 4.0.0 + + keycloak-tests-custom-scripts + Keycloak Testsuite Custom Scripts + jar + Keycloak Testsuite Custom Scripts + diff --git a/tests/custom-scripts/src/main/resources/META-INF/keycloak-scripts.json b/tests/custom-scripts/src/main/resources/META-INF/keycloak-scripts.json new file mode 100644 index 00000000000..ba0290779f6 --- /dev/null +++ b/tests/custom-scripts/src/main/resources/META-INF/keycloak-scripts.json @@ -0,0 +1,13 @@ +{ + "authenticators": [ + ], + "mappers": [ + ], + "policies": [ + { + "name": "Default Policy", + "fileName": "scripts/default-policy.js", + "description": "A policy that grants access only for users within this realm" + } + ] +} \ No newline at end of file diff --git a/tests/custom-scripts/src/main/resources/scripts/default-policy.js b/tests/custom-scripts/src/main/resources/scripts/default-policy.js new file mode 100644 index 00000000000..2f8b6c929b9 --- /dev/null +++ b/tests/custom-scripts/src/main/resources/scripts/default-policy.js @@ -0,0 +1 @@ +$evaluation.grant(); \ No newline at end of file diff --git a/tests/pom.xml b/tests/pom.xml index f25559d8b51..a1c22ec171b 100755 --- a/tests/pom.xml +++ b/tests/pom.xml @@ -37,6 +37,7 @@ utils utils-shared custom-providers + custom-scripts clustering @@ -49,4 +50,4 @@ - + \ No newline at end of file diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/partialimport/PartialImportTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/partialimport/PartialImportTest.java deleted file mode 100644 index b1c6503d25d..00000000000 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/partialimport/PartialImportTest.java +++ /dev/null @@ -1,984 +0,0 @@ -/* - * Copyright 2016 Red Hat Inc. and/or its affiliates and other contributors - * as indicated by the @author tags. All rights reserved. - * - * 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.admin.partialimport; - -import java.io.IOException; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.keycloak.admin.client.resource.ClientResource; -import org.keycloak.admin.client.resource.IdentityProviderResource; -import org.keycloak.admin.client.resource.RoleResource; -import org.keycloak.admin.client.resource.UserResource; -import org.keycloak.authentication.requiredactions.TermsAndConditions; -import org.keycloak.events.admin.OperationType; -import org.keycloak.models.UserModel; -import org.keycloak.partialimport.PartialImportResult; -import org.keycloak.partialimport.PartialImportResults; -import org.keycloak.representations.idm.AdminEventRepresentation; -import org.keycloak.representations.idm.ClientRepresentation; -import org.keycloak.representations.idm.GroupRepresentation; -import org.keycloak.representations.idm.IdentityProviderMapperRepresentation; -import org.keycloak.representations.idm.IdentityProviderRepresentation; -import org.keycloak.representations.idm.PartialImportRepresentation; -import org.keycloak.representations.idm.PartialImportRepresentation.Policy; -import org.keycloak.representations.idm.RealmRepresentation; -import org.keycloak.representations.idm.RoleRepresentation; -import org.keycloak.representations.idm.RolesRepresentation; -import org.keycloak.representations.idm.UserRepresentation; -import org.keycloak.testsuite.AbstractAuthTest; -import org.keycloak.testsuite.Assert; -import org.keycloak.testsuite.ProfileAssume; -import org.keycloak.testsuite.admin.ApiUtil; -import org.keycloak.testsuite.util.AssertAdminEvents; -import org.keycloak.testsuite.util.RealmBuilder; - -import jakarta.ws.rs.core.Response; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; - -import static org.hamcrest.CoreMatchers.hasItem; -import static org.hamcrest.CoreMatchers.startsWith; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.equalTo; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import org.keycloak.admin.client.resource.AuthorizationResource; -import org.keycloak.common.constants.ServiceAccountConstants; -import org.keycloak.partialimport.ResourceType; -import org.keycloak.representations.idm.authorization.ResourceServerRepresentation; - -import static org.keycloak.common.Profile.Feature.AUTHORIZATION; -import static org.keycloak.testsuite.auth.page.AuthRealm.MASTER; -import org.keycloak.util.JsonSerialization; - -/** - * Tests for the partial import endpoint in admin client. Also tests the - * server side functionality of each resource along with "fail, skip, overwrite" - * functions. - * - * @author Stan Silvert ssilvert@redhat.com (C) 2016 Red Hat Inc. - */ -public class PartialImportTest extends AbstractAuthTest { - - @Rule - public AssertAdminEvents assertAdminEvents = new AssertAdminEvents(this); - - private static final int NUM_RESOURCE_TYPES = 6; - private static final String CLIENT_ROLES_CLIENT = "clientRolesClient"; - private static final String CLIENT_SERVICE_ACCOUNT = "clientServiceAccount"; - private static final String USER_PREFIX = "user"; - private static final String GROUP_PREFIX = "group"; - private static final String CLIENT_PREFIX = "client"; - private static final String REALM_ROLE_PREFIX = "realmRole"; - private static final String CLIENT_ROLE_PREFIX = "clientRole"; - private static final String[] IDP_ALIASES = {"twitter", "github", "facebook", "google", "linkedin-openid-connect", "microsoft", "stackoverflow"}; - private static final int NUM_ENTITIES = IDP_ALIASES.length; - private static final ResourceServerRepresentation resourceServerSampleSettings; - - private PartialImportRepresentation piRep; - private String realmId; - - static { - try { - resourceServerSampleSettings = JsonSerialization.readValue( - PartialImportTest.class.getResourceAsStream("/import/sample-authz-partial-import.json"), - ResourceServerRepresentation.class); - } catch (IOException e) { - throw new IllegalStateException("Cannot load sample resource server configuration", e); - } - } - - @Before - public void initAdminEvents() { - RealmRepresentation realmRep = RealmBuilder.edit(testRealmResource().toRepresentation()).testEventListener().build(); - realmId = realmRep.getId(); - realmRep.setDuplicateEmailsAllowed(false); - adminClient.realm(realmRep.getRealm()).update(realmRep); - - piRep = new PartialImportRepresentation(); - } - - @After - public void tearDownAdminEvents() { - RealmRepresentation realmRep = RealmBuilder.edit(testRealmResource().toRepresentation()).removeTestEventListener().build(); - adminClient.realm(realmRep.getRealm()).update(realmRep); - } - - @Before - public void createClientForClientRoles() { - ClientRepresentation client = new ClientRepresentation(); - client.setClientId(CLIENT_ROLES_CLIENT); - client.setName(CLIENT_ROLES_CLIENT); - client.setProtocol("openid-connect"); - try (Response resp = testRealmResource().clients().create(client)) { - - // for some reason, findAll() will later fail unless readEntity is called here - resp.readEntity(String.class); - //testRealmResource().clients().findAll(); - } - } - - @Before - public void createClientWithServiceAccount() { - ClientRepresentation client = new ClientRepresentation(); - client.setClientId(CLIENT_SERVICE_ACCOUNT); - client.setName(CLIENT_SERVICE_ACCOUNT); - client.setRootUrl("http://localhost/foo"); - client.setProtocol("openid-connect"); - client.setPublicClient(false); - client.setSecret("secret"); - client.setServiceAccountsEnabled(true); - try (Response resp = testRealmResource().clients().create(client)) { - String id = ApiUtil.getCreatedId(resp); - UserRepresentation serviceAccountUser = testRealmResource().clients().get(id).getServiceAccountUser(); - assertNotNull(serviceAccountUser); - } - } - - @Before - public void removeUsers() { - List toRemove = testRealmResource().users().search(USER_PREFIX, 0, NUM_ENTITIES); - for (UserRepresentation user : toRemove) { - testRealmResource().users().get(user.getId()).remove(); - } - } - - @Before - public void removeGroups() { - List toRemove = testRealmResource().groups().groups(); - for (GroupRepresentation group: toRemove) { - testRealmResource().groups().group(group.getId()).remove(); - } - } - - @Before - public void removeClients() { - List toRemove = testRealmResource().clients().findAll(); - for (ClientRepresentation client : toRemove) { - if (client.getName() != null && client.getName().startsWith(CLIENT_PREFIX)) { - testRealmResource().clients().get(client.getId()).remove(); - } - } - } - - @Before - public void removeProviders() { - List toRemove = testRealmResource().identityProviders().findAll(); - for (IdentityProviderRepresentation idp : toRemove) { - testRealmResource().identityProviders().get(idp.getInternalId()).remove(); - } - } - - @Before - public void removeRealmRoles() { - List toRemove = testRealmResource().roles().list(); - for (RoleRepresentation role : toRemove) { - if (role.getName().startsWith(REALM_ROLE_PREFIX)) { - testRealmResource().roles().get(role.getName()).remove(); - } - } - } - - @Before - public void removeClientRoles() { - List toRemove = clientRolesClient().roles().list(); - for (RoleRepresentation role : toRemove) { - if (role.getName().startsWith(CLIENT_ROLE_PREFIX)) { - testRealmResource().clients().get(CLIENT_ROLES_CLIENT).roles().get(role.getName()).remove(); - } - } - } - - private ClientResource clientRolesClient() { - return ApiUtil.findClientResourceByName(testRealmResource(), CLIENT_ROLES_CLIENT); - } - - private void setFail() { - piRep.setIfResourceExists(Policy.FAIL.toString()); - } - - private void setSkip() { - piRep.setIfResourceExists(Policy.SKIP.toString()); - } - - private void setOverwrite() { - piRep.setIfResourceExists(Policy.OVERWRITE.toString()); - } - - private PartialImportResults doImport() { - try (Response response = testRealmResource().partialImport(piRep)) { - return response.readEntity(PartialImportResults.class); - } - } - - private void addUsers() { - List users = new ArrayList<>(); - - for (int i = 0; i < NUM_ENTITIES; i++) { - UserRepresentation user = createUserRepresentation(USER_PREFIX + i, USER_PREFIX + i + "@foo.com", "foo", "bar", true); - users.add(user); - } - - piRep.setUsers(users); - } - - private void addUsersWithIds() { - List users = new ArrayList<>(); - - for (int i = 0; i < NUM_ENTITIES; i++) { - UserRepresentation user = createUserRepresentation(UUID.randomUUID().toString(), USER_PREFIX + i, USER_PREFIX + i + "@foo.com", "foo", "bar", null, true); - users.add(user); - } - - piRep.setUsers(users); - } - - private void addUsersWithTermsAndConditions() { - List users = new ArrayList<>(); - List requiredActions = new ArrayList<>(); - requiredActions.add(UserModel.RequiredAction.TERMS_AND_CONDITIONS.name()); - - for (int i = 0; i < NUM_ENTITIES; i++) { - UserRepresentation user = createUserRepresentation(USER_PREFIX + i, USER_PREFIX + i + "@foo.com", "foo", "bar", true); - user.setRequiredActions(requiredActions); - users.add(user); - } - - piRep.setUsers(users); - } - - private void addGroups() { - List groups = new ArrayList<>(); - - for (int i=0; i < NUM_ENTITIES; i++) { - GroupRepresentation group = new GroupRepresentation(); - group.setName(GROUP_PREFIX + i); - group.setPath("/" + GROUP_PREFIX + i); - groups.add(group); - } - - piRep.setGroups(groups); - } - - private void addClients(boolean withServiceAccounts) { - List clients = new ArrayList<>(); - List serviceAccounts = new ArrayList<>(); - - for (int i = 0; i < NUM_ENTITIES; i++) { - ClientRepresentation client = new ClientRepresentation(); - client.setClientId(CLIENT_PREFIX + i); - client.setName(CLIENT_PREFIX + i); - clients.add(client); - if (withServiceAccounts) { - client.setServiceAccountsEnabled(true); - client.setBearerOnly(false); - client.setPublicClient(false); - client.setAuthorizationSettings(resourceServerSampleSettings); - client.setAuthorizationServicesEnabled(true); - // create the user service account - UserRepresentation serviceAccount = new UserRepresentation(); - serviceAccount.setUsername(ServiceAccountConstants.SERVICE_ACCOUNT_USER_PREFIX + client.getClientId()); - serviceAccount.setEnabled(true); - serviceAccount.setEmail(serviceAccount.getUsername() + "@placeholder.org"); - serviceAccount.setServiceAccountClientId(client.getClientId()); - serviceAccounts.add(serviceAccount); - } - } - - if (withServiceAccounts) { - if (piRep.getUsers() == null) { - piRep.setUsers(new ArrayList<>()); - } - piRep.getUsers().addAll(serviceAccounts); - } - piRep.setClients(clients); - } - - private void addProviders() { - addProviders(false); - } - - private void addProviders(boolean withMappers) { - List providers = new ArrayList<>(); - List mappers = new ArrayList<>(); - - for (String alias : IDP_ALIASES) { - IdentityProviderRepresentation idpRep = new IdentityProviderRepresentation(); - idpRep.setAlias(alias); - idpRep.setProviderId(alias); - idpRep.setEnabled(true); - idpRep.setAuthenticateByDefault(false); - idpRep.setFirstBrokerLoginFlowAlias("first broker login"); - - Map config = new HashMap<>(); - config.put("clientSecret", "secret"); - config.put("clientId", alias); - idpRep.setConfig(config); - providers.add(idpRep); - - if(withMappers) { - Map mapConfig = new HashMap<>(); - mapConfig.put("external.role", "IDP.TEST_ROLE"); - mapConfig.put("syncMode", "FORCE"); - mapConfig.put("role", "TEST_ROLE"); - - IdentityProviderMapperRepresentation idpMapRep = new IdentityProviderMapperRepresentation(); - idpMapRep.setName(alias+"_mapper"); - idpMapRep.setIdentityProviderAlias(alias); - idpMapRep.setIdentityProviderMapper("keycloak-oidc-role-to-role-idp-mapper"); - idpMapRep.setConfig(mapConfig); - - mappers.add(idpMapRep); - } - } - - piRep.setIdentityProviders(providers); - if (withMappers) { - piRep.setIdentityProviderMappers(mappers); - } - } - - private void addProviderMappers() { - addProviders(true); - } - - private List makeRoles(String prefix) { - List roles = new ArrayList<>(); - - for (int i = 0; i < NUM_ENTITIES; i++) { - RoleRepresentation role = new RoleRepresentation(); - role.setName(prefix + i); - roles.add(role); - } - - return roles; - } - - private void addRealmRoles() { - RolesRepresentation roles = piRep.getRoles(); - if (roles == null) roles = new RolesRepresentation(); - roles.setRealm(makeRoles(REALM_ROLE_PREFIX)); - piRep.setRoles(roles); - } - - private void addClientRoles() { - RolesRepresentation roles = piRep.getRoles(); - if (roles == null) roles = new RolesRepresentation(); - Map> clientRolesMap = new HashMap<>(); - clientRolesMap.put(CLIENT_ROLES_CLIENT, makeRoles(CLIENT_ROLE_PREFIX)); - roles.setClient(clientRolesMap); - piRep.setRoles(roles); - } - - @Test - public void testAddUsers() { - assertAdminEvents.clear(); - - setFail(); - addUsers(); - - PartialImportResults results = doImport(); - assertEquals(NUM_ENTITIES, results.getAdded()); - - // Need to do this way as admin events from partial import are unsorted - Set userIds = new HashSet<>(); - for (int i=0 ; i userRepIds = new HashSet<>(); - for (UserRepresentation userRep : piRep.getUsers()) { - userRepIds.add(userRep.getId()); - } - - PartialImportResults results = doImport(); - assertEquals(NUM_ENTITIES, results.getAdded()); - - // Need to do this way as admin events from partial import are unsorted - Set userIds = new HashSet<>(); - for (int i=0 ; i userIds = new HashSet<>(); - for (int i=0 ; i config = idp.getConfig(); - assertTrue(Arrays.asList(IDP_ALIASES).contains(config.get("clientId"))); - } - } - - @Test - public void testAddProviderMappers() { - setFail(); - addProviderMappers(); - - PartialImportResults results = doImport(); - assertEquals(IDP_ALIASES.length*2, results.getAdded()); - - for (PartialImportResult result : results.getResults()) { - if (ResourceType.IDP.equals(result.getResourceType())) { - String id = result.getId(); - IdentityProviderResource idpRsc = testRealmResource().identityProviders().get(id); - IdentityProviderMapperRepresentation idpMap = idpRsc.getMappers().get(0); - String alias = idpMap.getIdentityProviderAlias(); - assertTrue(Arrays.asList(IDP_ALIASES).contains(alias)); - assertEquals(alias + "_mapper", idpMap.getName()); - assertEquals("keycloak-oidc-role-to-role-idp-mapper", idpMap.getIdentityProviderMapper()); - assertEquals("IDP.TEST_ROLE", idpMap.getConfig().get("external.role")); - assertEquals("FORCE", idpMap.getConfig().get("syncMode")); - assertEquals("TEST_ROLE", idpMap.getConfig().get("role")); - } - } - } - - @Test - public void testAddRealmRoles() { - setFail(); - addRealmRoles(); - - PartialImportResults results = doImport(); - assertEquals(NUM_ENTITIES, results.getAdded()); - - for (PartialImportResult result : results.getResults()) { - String name = result.getResourceName(); - RoleResource roleRsc = testRealmResource().roles().get(name); - RoleRepresentation role = roleRsc.toRepresentation(); - assertTrue(role.getName().startsWith(REALM_ROLE_PREFIX)); - } - } - - @Test - public void testAddClientRoles() { - setFail(); - addClientRoles(); - - PartialImportResults results = doImport(); - assertEquals(NUM_ENTITIES, results.getAdded()); - - List clientRoles = clientRolesClient().roles().list(); - assertEquals(NUM_ENTITIES, clientRoles.size()); - - for (RoleRepresentation roleRep : clientRoles) { - assertTrue(roleRep.getName().startsWith(CLIENT_ROLE_PREFIX)); - } - } - - private void testFail() { - setFail(); - PartialImportResults results = doImport(); - assertNull(results.getErrorMessage()); - results = doImport(); // second time should fail - assertNotNull(results.getErrorMessage()); - } - - @Test - public void testAddUsersFail() { - addUsers(); - testFail(); - } - - @Test - public void testAddGroupsFail() { - addGroups(); - testFail(); - } - - @Test - public void testAddClientsFail() { - addClients(false); - testFail(); - } - - @Test - public void testAddProvidersFail() { - addProviders(); - testFail(); - } - - @Test - public void testAddProviderMappersFail() { - addProviderMappers(); - testFail(); - } - - @Test - public void testAddRealmRolesFail() { - addRealmRoles(); - testFail(); - } - - @Test - public void testAddClientRolesFail() { - addClientRoles(); - testFail(); - } - - private void testSkip() { - testSkip(NUM_ENTITIES); - } - - private void testSkip(int numberEntities) { - setSkip(); - PartialImportResults results = doImport(); - assertEquals(numberEntities, results.getAdded()); - - results = doImport(); - assertEquals(numberEntities, results.getSkipped()); - } - - @Test - public void testAddUsersSkip() { - addUsers(); - testSkip(); - } - - @Test - public void testAddGroupsSkip() { - addGroups(); - testSkip(); - } - - @Test - public void testAddClientsSkip() { - addClients(false); - testSkip(); - } - - @Test - public void testAddClientsSkipWithServiceAccountsAndAuthorization() { - addClients(true); - setSkip(); - PartialImportResults results = doImport(); - assertEquals(NUM_ENTITIES * 2, results.getAdded()); - - results = doImport(); - assertEquals(NUM_ENTITIES * 2, results.getSkipped()); - } - - @Test - public void testAddProvidersSkip() { - addProviders(); - testSkip(); - } - - @Test - public void testAddProviderMappersSkip() { - addProviderMappers(); - testSkip(NUM_ENTITIES*2); - } - - @Test - public void testAddRealmRolesSkip() { - addRealmRoles(); - testSkip(); - } - - @Test - public void testAddClientRolesSkip() { - addClientRoles(); - testSkip(); - } - - private void testOverwrite() { - testOverwrite(NUM_ENTITIES); - } - - private void testOverwrite(int numberEntities) { - setOverwrite(); - PartialImportResults results = doImport(); - assertEquals(numberEntities, results.getAdded()); - - results = doImport(); - assertEquals(numberEntities, results.getOverwritten()); - } - - @Test - public void testAddUsersOverwrite() { - addUsers(); - testOverwrite(); - } - - @Test - public void testAddGroupsOverwrite() { - addGroups(); - testOverwrite(); - } - - @Test - public void testAddClientsOverwrite() { - addClients(false); - testOverwrite(); - } - - @Test - public void testAddClientsOverwriteWithServiceAccountsAndAuthorization() { - addClients(true); - setOverwrite(); - PartialImportResults results = doImport(); - assertEquals(NUM_ENTITIES * 2, results.getAdded()); - - results = doImport(); - assertEquals(NUM_ENTITIES * 2, results.getOverwritten()); - } - - @Test - public void testAddClientsOverwriteServiceAccountsWithNoServiceAccounts() { - addClients(true); - setOverwrite(); - PartialImportResults results = doImport(); - assertEquals(NUM_ENTITIES * 2, results.getAdded()); - // check the service accounts are there - for (int i = 0; i < NUM_ENTITIES; i++) { - List l = testRealmResource().users().search(ServiceAccountConstants.SERVICE_ACCOUNT_USER_PREFIX + CLIENT_PREFIX + i); - Assert.assertEquals(1, l.size()); - } - // re-import without service accounts enabled - piRep = new PartialImportRepresentation(); - addClients(false); - setOverwrite(); - results = doImport(); - assertEquals(NUM_ENTITIES, results.getOverwritten()); - // check the service accounts have been removed - for (int i = 0; i < NUM_ENTITIES; i++) { - List l = testRealmResource().users().search(ServiceAccountConstants.SERVICE_ACCOUNT_USER_PREFIX + CLIENT_PREFIX + i); - Assert.assertEquals(0, l.size()); - } - } - - @Test - public void testAddProvidersOverwrite() { - addProviders(); - testOverwrite(); - } - - @Test - public void testAddProviderMappersOverwrite() { - addProviderMappers(); - testOverwrite(NUM_ENTITIES*2); - } - - @Test - public void testAddRealmRolesOverwrite() { - addRealmRoles(); - testOverwrite(); - } - - @Test - public void testAddClientRolesOverwrite() { - addClientRoles(); - testOverwrite(); - } - - private void importEverything(boolean withServiceAccounts) { - addUsers(); - addGroups(); - addClients(withServiceAccounts); - addProviders(); - addRealmRoles(); - addClientRoles(); - - PartialImportResults results = doImport(); - assertNull(results.getErrorMessage()); - if (withServiceAccounts) { - assertEquals(NUM_ENTITIES * (NUM_RESOURCE_TYPES + 1), results.getAdded()); - } else { - assertEquals(NUM_ENTITIES * NUM_RESOURCE_TYPES, results.getAdded()); - } - } - - @Test - public void testEverythingFail() { - setFail(); - importEverything(false); - PartialImportResults results = doImport(); // second import will fail because not allowed to skip or overwrite - assertNotNull(results.getErrorMessage()); - } - - @Test - public void testEverythingSkip() { - setSkip(); - importEverything(false); - PartialImportResults results = doImport(); - assertEquals(NUM_ENTITIES * NUM_RESOURCE_TYPES, results.getSkipped()); - } - - @Test - public void testEverythingSkipWithServiceAccounts() { - setSkip(); - importEverything(true); - PartialImportResults results = doImport(); - assertEquals(NUM_ENTITIES * (NUM_RESOURCE_TYPES + 1), results.getSkipped()); - } - - @Test - public void testEverythingOverwrite() { - setOverwrite(); - importEverything(false); - PartialImportResults results = doImport(); - assertEquals(NUM_ENTITIES * NUM_RESOURCE_TYPES, results.getOverwritten()); - } - - @Test - public void testEverythingOverwriteWithServiceAccounts() { - setOverwrite(); - importEverything(true); - PartialImportResults results = doImport(); - assertEquals(NUM_ENTITIES * (NUM_RESOURCE_TYPES + 1), results.getOverwritten()); - } - - //KEYCLOAK-3042 - @Test - public void testOverwriteExistingClientWithRoles() { - setOverwrite(); - - ClientRepresentation client = adminClient.realm(MASTER).clients().findByClientId("broker").get(0); - List clientRoles = adminClient.realm(MASTER).clients().get(client.getId()).roles().list(); - - Map> clients = new HashMap<>(); - clients.put(client.getClientId(), clientRoles); - - RolesRepresentation roles = new RolesRepresentation(); - roles.setClient(clients); - - piRep.setClients(List.of(client)); - piRep.setRoles(roles); - - doImport(); - } - - // KEYCLOAK-6058 - @Test - public void testOverwriteExistingInternalClient() { - setOverwrite(); - ClientRepresentation client = adminClient.realm(MASTER).clients().findByClientId("security-admin-console").get(0); - ClientRepresentation client2 = adminClient.realm(MASTER).clients().findByClientId("master-realm").get(0); - piRep.setClients(Arrays.asList(client, client2)); - - PartialImportResults result = doImport(); - Assert.assertEquals(0, result.getOverwritten()); - } - - @Test - public void testOverwriteExistingClientWithServiceAccount() { - setOverwrite(); - piRep.setClients(Collections.singletonList(testRealmResource().clients().findByClientId(CLIENT_SERVICE_ACCOUNT).get(0))); - - Assert.assertEquals(1, doImport().getOverwritten()); - - ClientRepresentation client = testRealmResource().clients().findByClientId(CLIENT_SERVICE_ACCOUNT).get(0); - testRealmResource().clients().get(client.getId()).getServiceAccountUser(); - } - - @Test - public void testOverwriteDefaultRole() { - setOverwrite(); - - RolesRepresentation roles = new RolesRepresentation(); - RoleRepresentation oldDefaultRole = testRealmResource().toRepresentation().getDefaultRole(); - roles.setRealm(Collections.singletonList(oldDefaultRole)); - piRep.setRoles(roles); - - Assert.assertEquals("default role should have been overwritten", 1, doImport().getOverwritten()); - // The following check is not valid anymore since file store does have the same ID - // Assert.assertNotEquals("when overwriting, the ID of the role changes", - // testRealmResource().toRepresentation().getDefaultRole().getId(), oldDefaultRole.getId()); - } - -}