KEYCLOAK-3980
This commit is contained in:
parent
cb4f856ab6
commit
1dacddb7e3
11 changed files with 95 additions and 246 deletions
|
@ -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;
|
||||
}
|
|
@ -208,6 +208,10 @@ public interface RealmResource {
|
|||
@Path("components")
|
||||
ComponentsResource components();
|
||||
|
||||
@Path("user-storage")
|
||||
UserStorageProviderResource userStorage();
|
||||
|
||||
|
||||
@Path("keys")
|
||||
KeyResource keys();
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
||||
|
||||
}
|
|
@ -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<>();
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue