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());
- }
-
-}