KEYCLOAK-3980

This commit is contained in:
Bill Burke 2016-11-28 12:20:40 -05:00
parent cb4f856ab6
commit 1dacddb7e3
11 changed files with 95 additions and 246 deletions

View file

@ -20,7 +20,7 @@ package org.keycloak.representations.idm;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class UserFederationSyncResultRepresentation {
public class SynchronizationResultRepresentation {
private boolean ignored;
@ -31,6 +31,9 @@ public class UserFederationSyncResultRepresentation {
private String status;
public SynchronizationResultRepresentation() {
}
public boolean isIgnored() {
return ignored;
}

View file

@ -208,6 +208,10 @@ public interface RealmResource {
@Path("components")
ComponentsResource components();
@Path("user-storage")
UserStorageProviderResource userStorage();
@Path("keys")
KeyResource keys();

View file

@ -1,103 +0,0 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.admin.client.resource;
import org.keycloak.representations.idm.UserFederationMapperRepresentation;
import org.keycloak.representations.idm.UserFederationMapperTypeRepresentation;
import org.keycloak.representations.idm.UserFederationProviderRepresentation;
import org.keycloak.representations.idm.UserFederationSyncResultRepresentation;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.List;
import java.util.Map;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public interface UserFederationProviderResource {
@PUT
@Consumes(MediaType.APPLICATION_JSON)
void update(UserFederationProviderRepresentation rep);
@GET
@Produces(MediaType.APPLICATION_JSON)
UserFederationProviderRepresentation toRepresentation();
@DELETE
void remove();
@POST
@Path("sync")
@Produces(MediaType.APPLICATION_JSON)
UserFederationSyncResultRepresentation syncUsers(@QueryParam("action") String action);
@GET
@Path("mapper-types")
@Produces(MediaType.APPLICATION_JSON)
Map<String, UserFederationMapperTypeRepresentation> getMapperTypes();
@GET
@Path("mappers")
@Produces(MediaType.APPLICATION_JSON)
List<UserFederationMapperRepresentation> getMappers();
@POST
@Path("mappers")
@Consumes(MediaType.APPLICATION_JSON)
Response addMapper(UserFederationMapperRepresentation mapper);
@GET
@Path("mappers/{id}")
@Produces(MediaType.APPLICATION_JSON)
UserFederationMapperRepresentation getMapperById(@PathParam("id") String id);
@PUT
@Path("mappers/{id}")
@Consumes(MediaType.APPLICATION_JSON)
void updateMapper(@PathParam("id") String id, UserFederationMapperRepresentation rep);
@DELETE
@Path("mappers/{id}")
void removeMapper(@PathParam("id") String id);
@POST
@Path("mappers/{id}/sync")
@Produces(MediaType.APPLICATION_JSON)
UserFederationSyncResultRepresentation syncMapperData(@PathParam("id") String mapperId, @QueryParam("direction") String direction);
}

View file

@ -1,65 +0,0 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.admin.client.resource;
import org.keycloak.representations.idm.UserFederationProviderFactoryRepresentation;
import org.keycloak.representations.idm.UserFederationProviderRepresentation;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.List;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public interface UserFederationProvidersResource {
@GET
@Path("providers")
@Produces(MediaType.APPLICATION_JSON)
List<UserFederationProviderFactoryRepresentation> getProviderFactories();
@GET
@Path("providers/{id}")
@Produces(MediaType.APPLICATION_JSON)
UserFederationProviderFactoryRepresentation getProviderFactory(@PathParam("id") String id);
@POST
@Path("instances")
@Consumes(MediaType.APPLICATION_JSON)
Response create(UserFederationProviderRepresentation rep);
@GET
@Path("instances")
@Produces(MediaType.APPLICATION_JSON)
List<UserFederationProviderRepresentation> getProviderInstances();
@Path("instances/{id}")
UserFederationProviderResource get(@PathParam("id") String id);
}

View file

@ -0,0 +1,44 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.admin.client.resource;
import org.keycloak.representations.idm.SynchronizationResultRepresentation;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface UserStorageProviderResource {
@POST
@Path("{componentId}/sync")
@Produces(MediaType.APPLICATION_JSON)
SynchronizationResultRepresentation syncUsers(@QueryParam("action") String action);
@POST
@Path("{componentId}/mappers/{mapperId}/sync")
@Produces(MediaType.APPLICATION_JSON)
SynchronizationResultRepresentation syncMapperData(@PathParam("componentId") String componentId, @PathParam("mapperId") String mapperId, @QueryParam("direction") String direction);
}

View file

@ -34,6 +34,7 @@ import org.keycloak.storage.ldap.LDAPStorageProviderFactory;
import org.keycloak.storage.ldap.mappers.LDAPStorageMapper;
import org.keycloak.storage.user.SynchronizationResult;
import javax.ws.rs.BadRequestException;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
@ -141,7 +142,7 @@ public class UserStorageProviderResource {
ComponentModel mapperModel = realm.getComponent(mapperId);
if (mapperModel == null) throw new NotFoundException("Mapper model not found");
LDAPStorageMapper mapper = session.getProvider(LDAPStorageMapper.class, mapperModel);
ProviderFactory factory = session.getKeycloakSessionFactory().getProviderFactory(LDAPStorageProvider.class, parentModel.getProviderId());
ProviderFactory factory = session.getKeycloakSessionFactory().getProviderFactory(UserStorageProvider.class, parentModel.getProviderId());
LDAPStorageProviderFactory providerFactory = (LDAPStorageProviderFactory)factory;
LDAPStorageProvider federationProvider = providerFactory.create(session, parentModel);
@ -154,7 +155,7 @@ public class UserStorageProviderResource {
} else if ("keycloakToFed".equals(direction)) {
syncResult = mapper.syncDataFromKeycloakToFederationProvider(mapperModel, federationProvider, session, realm);
} else {
throw new NotFoundException("Unknown direction: " + direction);
throw new BadRequestException("Unknown direction: " + direction);
}
Map<String, Object> eventRep = new HashMap<>();

View file

@ -17,31 +17,7 @@
package org.keycloak.testsuite.admin;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.keycloak.admin.client.resource.UserFederationProviderResource;
import org.keycloak.events.admin.OperationType;
import org.keycloak.events.admin.ResourceType;
import org.keycloak.representations.idm.ConfigPropertyRepresentation;
import org.keycloak.representations.idm.UserFederationMapperRepresentation;
import org.keycloak.representations.idm.UserFederationMapperTypeRepresentation;
import org.keycloak.representations.idm.UserFederationProviderRepresentation;
import org.keycloak.representations.idm.UserFederationSyncResultRepresentation;
import org.keycloak.testsuite.Assert;
import org.keycloak.testsuite.util.AdminEventPaths;
import org.keycloak.testsuite.util.UserFederationProviderBuilder;
import javax.ws.rs.BadRequestException;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.core.Response;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>

View file

@ -18,37 +18,13 @@
package org.keycloak.testsuite.admin;
import org.junit.Ignore;
import org.junit.Test;
import org.keycloak.admin.client.resource.UserFederationProvidersResource;
import org.keycloak.common.constants.KerberosConstants;
import org.keycloak.events.admin.OperationType;
import org.keycloak.events.admin.ResourceType;
import org.keycloak.models.AuthenticationExecutionModel;
import org.keycloak.models.LDAPConstants;
import org.keycloak.provider.ProviderConfigProperty;
import org.keycloak.representations.idm.AuthenticationExecutionInfoRepresentation;
import org.keycloak.representations.idm.UserFederationProviderFactoryRepresentation;
import org.keycloak.representations.idm.UserFederationProviderRepresentation;
import org.keycloak.representations.idm.UserFederationSyncResultRepresentation;
import org.keycloak.testsuite.Assert;
import org.keycloak.testsuite.admin.authentication.AbstractAuthenticationTest;
import org.keycloak.testsuite.util.AdminEventPaths;
import org.keycloak.testsuite.util.UserFederationProviderBuilder;
import javax.ws.rs.BadRequestException;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.core.Response;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@Ignore
public class UserStorageRestTest extends AbstractAdminTest {
/*
@Test
public void testProviderFactories() {
List<UserFederationProviderFactoryRepresentation> providerFactories = userFederation().getProviderFactories();
@ -339,7 +315,7 @@ public class UserStorageRestTest extends AbstractAdminTest {
Assert.assertEquals(-1, userFederation().get(id1).toRepresentation().getLastSync());
// Sync and assert it happened
UserFederationSyncResultRepresentation syncResult = userFederation().get(id1).syncUsers("triggerFullSync");
SynchronizationResultRepresentation syncResult = userFederation().get(id1).syncUsers("triggerFullSync");
Assert.assertEquals("0 imported users, 0 updated users", syncResult.getStatus());
Map<String, Object> eventRep = new HashMap<>();
@ -404,4 +380,5 @@ public class UserStorageRestTest extends AbstractAdminTest {
Assert.assertNotNull(kerberosExecution);
return kerberosExecution;
}
*/
}

View file

@ -35,8 +35,6 @@ import org.keycloak.admin.client.resource.RoleByIdResource;
import org.keycloak.admin.client.resource.RoleMappingResource;
import org.keycloak.admin.client.resource.RoleResource;
import org.keycloak.admin.client.resource.RolesResource;
import org.keycloak.admin.client.resource.UserFederationProviderResource;
import org.keycloak.admin.client.resource.UserFederationProvidersResource;
import org.keycloak.admin.client.resource.UserResource;
import org.keycloak.admin.client.resource.UsersResource;
@ -284,29 +282,6 @@ public class AdminEventPaths {
return uri.toString();
}
// USER FEDERATION PROVIDERS AND MAPPERS
public static String userFederationsResourcePath() {
URI uri = UriBuilder.fromUri("").path(RealmResource.class, "userFederation").build();
return uri.toString();
}
public static String userFederationCreateResourcePath() {
URI uri = UriBuilder.fromUri(userFederationsResourcePath()).path(UserFederationProvidersResource.class, "create").build();
return uri.toString();
}
public static String userFederationResourcePath(String userFederationId) {
URI uri = UriBuilder.fromUri(userFederationsResourcePath()).path(UserFederationProvidersResource.class, "get").build(userFederationId);
return uri.toString();
}
public static String userFederationMapperResourcePath(String userFederationId, String userFederationMapperId) {
URI uri = UriBuilder.fromUri(userFederationResourcePath(userFederationId))
.path(UserFederationProviderResource.class, "getMapperById").build(userFederationMapperId);
return uri.toString();
}
// CLIENT INITIAL ACCESS
public static String clientInitialAccessPath(String clientInitialAccessId) {

View file

@ -25,8 +25,11 @@ import org.junit.Test;
import org.junit.rules.RuleChain;
import org.junit.rules.TestRule;
import org.junit.runners.MethodSorters;
import org.keycloak.admin.client.Keycloak;
import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.component.ComponentModel;
import org.keycloak.models.Constants;
import org.keycloak.representations.idm.SynchronizationResultRepresentation;
import org.keycloak.storage.UserStorageProvider;
import org.keycloak.storage.UserStorageProviderModel;
import org.keycloak.storage.ldap.LDAPStorageProvider;
@ -50,9 +53,14 @@ import org.keycloak.storage.user.SynchronizationResult;
import org.keycloak.testsuite.rule.KeycloakRule;
import org.keycloak.testsuite.rule.LDAPRule;
import javax.ws.rs.BadRequestException;
import java.util.List;
import java.util.Set;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.MASTER;
import static org.keycloak.models.AdminRoles.ADMIN;
import static org.keycloak.testsuite.Constants.AUTH_SERVER_ROOT;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@ -106,8 +114,12 @@ public class LDAPGroupMapperSyncTest {
.outerRule(ldapRule)
.around(keycloakRule);
protected Keycloak adminClient;
@Before
public void before() {
adminClient = Keycloak.getInstance(AUTH_SERVER_ROOT, MASTER, ADMIN, ADMIN, Constants.ADMIN_CLI_CLIENT_ID);
KeycloakSession session = keycloakRule.startSession();
try {
RealmModel realm = session.realms().getRealmByName("test");
@ -166,6 +178,24 @@ public class LDAPGroupMapperSyncTest {
}
}
@Test
public void testSyncRestAPI() {
KeycloakSession session = keycloakRule.startSession();
try {
RealmModel realm = session.realms().getRealmByName("test");
ComponentModel mapperModel = LDAPTestUtils.getSubcomponentByName(realm,ldapModel, "groupsMapper");
try {
// testing KEYCLOAK-3980 which threw an NPE because I was looking up the factory wrong.
SynchronizationResultRepresentation syncResultRep = adminClient.realm("test").userStorage().syncMapperData(ldapModel.getId(), mapperModel.getId(), "error");
Assert.fail("Should throw 400");
} catch (BadRequestException e) {
}
} finally {
keycloakRule.stopSession(session, false);
}
}
@Test
public void test02_syncWithGroupInheritance() throws Exception {
KeycloakSession session = keycloakRule.startSession();

View file

@ -29,6 +29,7 @@ import org.keycloak.models.UserProvider;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.models.utils.UserModelDelegate;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.representations.idm.SynchronizationResultRepresentation;
import org.keycloak.storage.UserStorageProvider;
import org.keycloak.storage.ldap.LDAPStorageProvider;
import org.keycloak.storage.ldap.LDAPUtils;
@ -309,4 +310,10 @@ public class LDAPTestUtils {
Assert.assertEquals(expectedRemoved, syncResult.getRemoved());
Assert.assertEquals(expectedFailed, syncResult.getFailed());
}
public static void assertSyncEquals(SynchronizationResultRepresentation syncResult, int expectedAdded, int expectedUpdated, int expectedRemoved, int expectedFailed) {
Assert.assertEquals(expectedAdded, syncResult.getAdded());
Assert.assertEquals(expectedUpdated, syncResult.getUpdated());
Assert.assertEquals(expectedRemoved, syncResult.getRemoved());
Assert.assertEquals(expectedFailed, syncResult.getFailed());
}
}