keycloak-uncached
Changes
integration/admin-client/src/main/java/org/keycloak/admin/client/resource/RealmResource.java 11(+9 -2)
Details
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/RealmResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/RealmResource.java
old mode 100755
new mode 100644
index 498b3ac..25d521c
--- a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/RealmResource.java
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/RealmResource.java
@@ -18,17 +18,19 @@
package org.keycloak.admin.client.resource;
import org.jboss.resteasy.annotations.cache.NoCache;
+import org.keycloak.representations.idm.AdminEventRepresentation;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.EventRepresentation;
import org.keycloak.representations.idm.GroupRepresentation;
+import org.keycloak.representations.idm.PartialImportRepresentation;
+import org.keycloak.representations.idm.RealmEventsConfigRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
import java.util.List;
import java.util.Map;
-import org.keycloak.representations.idm.AdminEventRepresentation;
-import org.keycloak.representations.idm.RealmEventsConfigRepresentation;
/**
* @author rodrigo.sasaki@icarros.com.br
@@ -142,6 +144,11 @@ public interface RealmResource {
@Path("clients-initial-access")
ClientInitialAccessResource clientInitialAccess();
+ @Path("partialImport")
+ @POST
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response partialImport(PartialImportRepresentation rep);
@Path("authentication")
@Consumes(MediaType.APPLICATION_JSON)
AuthenticationManagementResource flows();
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/UsersResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/UsersResource.java
index 915731c..d341e35 100755
--- a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/UsersResource.java
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/UsersResource.java
@@ -37,9 +37,9 @@ public interface UsersResource {
List<UserRepresentation> search(@QueryParam("username") String username,
@QueryParam("firstName") String firstName,
@QueryParam("lastName") String lastName,
- @QueryParam("email") String email,
- @QueryParam("first") Integer firstResult,
- @QueryParam("max") Integer maxResults);
+ @QueryParam("email") String email,
+ @QueryParam("first") Integer firstResult,
+ @QueryParam("max") Integer maxResults);
@GET
@Produces(MediaType.APPLICATION_JSON)
diff --git a/services/src/main/java/org/keycloak/partialimport/PartialImportResult.java b/services/src/main/java/org/keycloak/partialimport/PartialImportResult.java
index fdf3f69..f512848 100644
--- a/services/src/main/java/org/keycloak/partialimport/PartialImportResult.java
+++ b/services/src/main/java/org/keycloak/partialimport/PartialImportResult.java
@@ -26,11 +26,13 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
*/
public class PartialImportResult {
- private final Action action;
- private final ResourceType resourceType;
- private final String resourceName;
- private final String id;
- private final Object representation;
+ private Action action;
+ private ResourceType resourceType;
+ private String resourceName;
+ private String id;
+ private Object representation;
+
+ private PartialImportResult() {};
private PartialImportResult(Action action, ResourceType resourceType, String resourceName, String id, Object representation) {
this.action = action;
@@ -56,18 +58,34 @@ public class PartialImportResult {
return action;
}
+ public void setAction(Action action) {
+ this.action = action;
+ }
+
public ResourceType getResourceType() {
return resourceType;
}
+ public void setResourceType(ResourceType resourceType) {
+ this.resourceType = resourceType;
+ }
+
public String getResourceName() {
return resourceName;
}
+ public void setResourceName(String resourceName) {
+ this.resourceName = resourceName;
+ }
+
public String getId() {
return id;
}
+ public void setId(String id) {
+ this.id = id;
+ }
+
@JsonIgnore
public Object getRepresentation() {
return representation;
diff --git a/services/src/main/java/org/keycloak/partialimport/PartialImportResults.java b/services/src/main/java/org/keycloak/partialimport/PartialImportResults.java
index 52288f3..fbab8c1 100644
--- a/services/src/main/java/org/keycloak/partialimport/PartialImportResults.java
+++ b/services/src/main/java/org/keycloak/partialimport/PartialImportResults.java
@@ -28,6 +28,14 @@ import java.util.Set;
*/
public class PartialImportResults {
+ // these fields used only for marsalling from JSON with admin client
+ // they are never directly set
+ private int overwritten;
+ private int added;
+ private int skipped;
+
+ private String errorMessage;
+
private final Set<PartialImportResult> importResults = new HashSet<>();
public void addResult(PartialImportResult result) {
@@ -68,4 +76,13 @@ public class PartialImportResults {
public Set<PartialImportResult> getResults() {
return importResults;
}
+
+ public String getErrorMessage() {
+ return errorMessage;
+ }
+
+ public void setErrorMessage(String errorMessage) {
+ this.errorMessage = errorMessage;
+ }
+
}
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
new file mode 100644
index 0000000..0440f7b
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/partialimport/PartialImportTest.java
@@ -0,0 +1,464 @@
+/*
+ * 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.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.ws.rs.ProcessingException;
+import javax.ws.rs.core.Response;
+import org.junit.Before;
+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.partialimport.PartialImportResult;
+import org.keycloak.partialimport.PartialImportResults;
+import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.representations.idm.IdentityProviderRepresentation;
+import org.keycloak.representations.idm.PartialImportRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.testsuite.AbstractAuthTest;
+
+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.representations.idm.PartialImportRepresentation.Policy;
+import org.keycloak.representations.idm.RoleRepresentation;
+import org.keycloak.representations.idm.RolesRepresentation;
+import org.keycloak.testsuite.admin.ApiUtil;
+
+/**
+ * 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 {
+
+ private static final int NUM_RESOURCE_TYPES = 5;
+ private static final String CLIENT_ROLES_CLIENT = "clientRolesClient";
+ private static final String USER_PREFIX = "user";
+ 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", "microsoft", "stackoverflow"};
+ private static final int NUM_ENTITIES = IDP_ALIASES.length;
+
+ private PartialImportRepresentation piRep;
+
+ @Before
+ public void init() {
+ piRep = new PartialImportRepresentation();
+ }
+
+ @Before
+ public void createClientForClientRoles() {
+ ClientRepresentation client = new ClientRepresentation();
+ client.setClientId(CLIENT_ROLES_CLIENT);
+ client.setName(CLIENT_ROLES_CLIENT);
+ client.setRootUrl("foo");
+ client.setProtocol("openid-connect");
+ 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 removeUsers() {
+ List<UserRepresentation> toRemove = testRealmResource().users().search(USER_PREFIX, 0, NUM_ENTITIES);
+ for (UserRepresentation user : toRemove) {
+ testRealmResource().users().get(user.getId()).remove();
+ }
+ }
+
+ @Before
+ public void removeClients() {
+ List<ClientRepresentation> toRemove = testRealmResource().clients().findAll();
+ for (ClientRepresentation client : toRemove) {
+ if (client.getName().startsWith(CLIENT_PREFIX)) {
+ testRealmResource().clients().get(client.getId()).remove();
+ }
+ }
+ }
+
+ @Before
+ public void removeProviders() {
+ List<IdentityProviderRepresentation> toRemove = testRealmResource().identityProviders().findAll();
+ for (IdentityProviderRepresentation idp : toRemove) {
+ testRealmResource().identityProviders().get(idp.getInternalId()).remove();
+ }
+ }
+
+ @Before
+ public void removeRealmRoles() {
+ List<RoleRepresentation> 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<RoleRepresentation> 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() {
+ Response response = testRealmResource().partialImport(piRep);
+ return response.readEntity(PartialImportResults.class);
+ }
+
+ private void addUsers() {
+ List<UserRepresentation> 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 addClients() {
+ List<ClientRepresentation> clients = new ArrayList<>();
+
+ for (int i = 0; i < NUM_ENTITIES; i++) {
+ ClientRepresentation client = new ClientRepresentation();
+ client.setClientId(CLIENT_PREFIX + i);
+ client.setName(CLIENT_PREFIX + i);
+ client.setRootUrl("foo");
+ clients.add(client);
+ }
+
+ piRep.setClients(clients);
+ }
+
+ private void addProviders() {
+ List<IdentityProviderRepresentation> providers = 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<String, String> config = new HashMap<>();
+ config.put("clientSecret", "secret");
+ config.put("clientId", alias);
+ idpRep.setConfig(config);
+ providers.add(idpRep);
+ }
+
+ piRep.setIdentityProviders(providers);
+ }
+
+ private List<RoleRepresentation> makeRoles(String prefix) {
+ List<RoleRepresentation> 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<String, List<RoleRepresentation>> clientRolesMap = new HashMap<>();
+ clientRolesMap.put(CLIENT_ROLES_CLIENT, makeRoles(CLIENT_ROLE_PREFIX));
+ roles.setClient(clientRolesMap);
+ piRep.setRoles(roles);
+ }
+
+ @Test
+ public void testAddUsers() {
+ setFail();
+ addUsers();
+
+ PartialImportResults results = doImport();
+ assertEquals(NUM_ENTITIES, results.getAdded());
+
+ for (PartialImportResult result : results.getResults()) {
+ String id = result.getId();
+ UserResource userRsc = testRealmResource().users().get(id);
+ UserRepresentation user = userRsc.toRepresentation();
+ assertTrue(user.getUsername().startsWith(USER_PREFIX));
+ }
+ }
+
+ @Test
+ public void testAddClients() {
+ setFail();
+ addClients();
+
+ PartialImportResults results = doImport();
+ assertEquals(NUM_ENTITIES, results.getAdded());
+
+ for (PartialImportResult result : results.getResults()) {
+ String id = result.getId();
+ ClientResource clientRsc = testRealmResource().clients().get(id);
+ ClientRepresentation client = clientRsc.toRepresentation();
+ assertTrue(client.getName().startsWith(CLIENT_PREFIX));
+ }
+ }
+
+ @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 = testRealmResource().identityProviders().get(id);
+ IdentityProviderRepresentation idp = idpRsc.toRepresentation();
+ Map<String, String> config = idp.getConfig();
+ assertTrue(Arrays.asList(IDP_ALIASES).contains(config.get("clientId")));
+ }
+ }
+
+ @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<RoleRepresentation> 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 testAddClientsFail() {
+ addClients();
+ testFail();
+ }
+
+ @Test
+ public void testAddProvidersFail() {
+ addProviders();
+ testFail();
+ }
+
+ @Test
+ public void testAddRealmRolesFail() {
+ addRealmRoles();
+ testFail();
+ }
+
+ @Test
+ public void testAddClientRolesFail() {
+ addClientRoles();
+ testFail();
+ }
+
+ private void testSkip() {
+ setSkip();
+ PartialImportResults results = doImport();
+ assertEquals(NUM_ENTITIES, results.getAdded());
+
+ results = doImport();
+ assertEquals(NUM_ENTITIES, results.getSkipped());
+ }
+
+ @Test
+ public void testAddUsersSkip() {
+ addUsers();
+ testSkip();
+ }
+
+ @Test
+ public void testAddClientsSkip() {
+ addClients();
+ testSkip();
+ }
+
+ @Test
+ public void testAddProvidersSkip() {
+ addProviders();
+ testSkip();
+ }
+
+ @Test
+ public void testAddRealmRolesSkip() {
+ addRealmRoles();
+ testSkip();
+ }
+
+ @Test
+ public void testAddClientRolesSkip() {
+ addClientRoles();
+ testSkip();
+ }
+
+ private void testOverwrite() {
+ setOverwrite();
+ PartialImportResults results = doImport();
+ assertEquals(NUM_ENTITIES, results.getAdded());
+
+ results = doImport();
+ assertEquals(NUM_ENTITIES, results.getOverwritten());
+ }
+
+ @Test
+ public void testAddUsersOverwrite() {
+ addUsers();
+ testOverwrite();
+ }
+
+ @Test
+ public void testAddClientsOverwrite() {
+ addClients();
+ testOverwrite();
+ }
+
+ @Test
+ public void testAddProvidersOverwrite() {
+ addProviders();
+ testOverwrite();
+ }
+
+ @Test
+ public void testAddRealmRolesOverwrite() {
+ addRealmRoles();
+ testOverwrite();
+ }
+
+ @Test
+ public void testAddClientRolesOverwrite() {
+ addClientRoles();
+ testOverwrite();
+ }
+
+
+ private void importEverything() {
+ addUsers();
+ addClients();
+ addProviders();
+ addRealmRoles();
+ addClientRoles();
+
+ PartialImportResults results = doImport();
+ assertNull(results.getErrorMessage());
+ assertEquals(NUM_ENTITIES * NUM_RESOURCE_TYPES, results.getAdded());
+ }
+
+ @Test
+ public void testEverythingFail() {
+ setFail();
+ importEverything();
+ PartialImportResults results = doImport(); // second import will fail because not allowed to skip or overwrite
+ assertNotNull(results.getErrorMessage());
+ }
+
+ @Test
+ public void testEverythingSkip() {
+ setSkip();
+ importEverything();
+ PartialImportResults results = doImport();
+ assertEquals(NUM_ENTITIES * NUM_RESOURCE_TYPES, results.getSkipped());
+ }
+
+ @Test
+ public void testEverythingOverwrite() {
+ setOverwrite();
+ importEverything();
+ PartialImportResults results = doImport();
+ assertEquals(NUM_ENTITIES * NUM_RESOURCE_TYPES, results.getOverwritten());
+ }
+
+}