keycloak-uncached
Changes
core/src/main/java/org/keycloak/representations/idm/UserFederationProviderFactoryRepresentation.java 21(+20 -1)
core/src/main/java/org/keycloak/representations/idm/UserFederationSyncResultRepresentation.java 82(+82 -0)
integration/admin-client/src/main/java/org/keycloak/admin/client/resource/RealmResource.java 10(+10 -0)
integration/admin-client/src/main/java/org/keycloak/admin/client/resource/UserFederationProviderResource.java 103(+103 -0)
integration/admin-client/src/main/java/org/keycloak/admin/client/resource/UserFederationProvidersResource.java 66(+66 -0)
services/src/main/java/org/keycloak/services/resources/admin/UserFederationProviderResource.java 2(+2 -0)
testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/federation/DummyConfigurableUserFederationProviderFactory.java 62(+62 -0)
testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/federation/DummyUserFederationProvider.java 149(+149 -0)
testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/federation/DummyUserFederationProviderFactory.java 108(+108 -0)
testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/META-INF/services/org.keycloak.models.UserFederationProviderFactory 36(+36 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/AbstractAuthenticationTest.java 2(+1 -1)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserFederationTest.java 363(+363 -0)
Details
diff --git a/core/src/main/java/org/keycloak/representations/idm/UserFederationProviderFactoryRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/UserFederationProviderFactoryRepresentation.java
index 1a6fec8..bbf5741 100755
--- a/core/src/main/java/org/keycloak/representations/idm/UserFederationProviderFactoryRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/UserFederationProviderFactoryRepresentation.java
@@ -17,6 +17,7 @@
package org.keycloak.representations.idm;
+import java.util.List;
import java.util.Set;
/**
@@ -25,7 +26,9 @@ import java.util.Set;
public class UserFederationProviderFactoryRepresentation {
private String id;
- private Set<String> options;
+ private Set<String> options; // TODO:Remove as configurable providers are more flexible?
+ private String helpText; // Used for configurable providers
+ private List<ConfigPropertyRepresentation> properties; // Used for configurable providers
public String getId() {
return id;
@@ -43,6 +46,22 @@ public class UserFederationProviderFactoryRepresentation {
this.options = options;
}
+ public String getHelpText() {
+ return helpText;
+ }
+
+ public void setHelpText(String helpText) {
+ this.helpText = helpText;
+ }
+
+ public List<ConfigPropertyRepresentation> getProperties() {
+ return properties;
+ }
+
+ public void setProperties(List<ConfigPropertyRepresentation> properties) {
+ this.properties = properties;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
diff --git a/core/src/main/java/org/keycloak/representations/idm/UserFederationSyncResultRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/UserFederationSyncResultRepresentation.java
new file mode 100644
index 0000000..08509ef
--- /dev/null
+++ b/core/src/main/java/org/keycloak/representations/idm/UserFederationSyncResultRepresentation.java
@@ -0,0 +1,82 @@
+/*
+ * 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.representations.idm;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class UserFederationSyncResultRepresentation {
+
+ private boolean ignored;
+
+ private int added;
+ private int updated;
+ private int removed;
+ private int failed;
+
+ private String status;
+
+ public boolean isIgnored() {
+ return ignored;
+ }
+
+ public void setIgnored(boolean ignored) {
+ this.ignored = ignored;
+ }
+
+ public int getAdded() {
+ return added;
+ }
+
+ public void setAdded(int added) {
+ this.added = added;
+ }
+
+ public int getUpdated() {
+ return updated;
+ }
+
+ public void setUpdated(int updated) {
+ this.updated = updated;
+ }
+
+ public int getRemoved() {
+ return removed;
+ }
+
+ public void setRemoved(int removed) {
+ this.removed = removed;
+ }
+
+ public int getFailed() {
+ return failed;
+ }
+
+ public void setFailed(int failed) {
+ this.failed = failed;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ public void setStatus(String status) {
+ this.status = status;
+ }
+
+}
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
index 6b4f368..34ca64a 100644
--- 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
@@ -160,4 +160,14 @@ public interface RealmResource {
@Path("attack-detection")
AttackDetectionResource attackDetection();
+ @Path("user-federation")
+ UserFederationProvidersResource userFederation();
+
+ @Path("testLDAPConnection")
+ @GET
+ @NoCache
+ Response testLDAPConnection(@QueryParam("action") String action, @QueryParam("connectionUrl") String connectionUrl,
+ @QueryParam("bindDn") String bindDn, @QueryParam("bindCredential") String bindCredential,
+ @QueryParam("useTruststoreSpi") String useTruststoreSpi);
+
}
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/UserFederationProviderResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/UserFederationProviderResource.java
new file mode 100644
index 0000000..5e1a99f
--- /dev/null
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/UserFederationProviderResource.java
@@ -0,0 +1,103 @@
+/*
+ * 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 java.util.List;
+import java.util.Map;
+
+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 org.keycloak.representations.idm.UserFederationMapperRepresentation;
+import org.keycloak.representations.idm.UserFederationMapperTypeRepresentation;
+import org.keycloak.representations.idm.UserFederationProviderRepresentation;
+import org.keycloak.representations.idm.UserFederationSyncResultRepresentation;
+
+/**
+ * @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")
+ 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);
+}
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/UserFederationProvidersResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/UserFederationProvidersResource.java
new file mode 100644
index 0000000..e56ea3c
--- /dev/null
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/UserFederationProvidersResource.java
@@ -0,0 +1,66 @@
+/*
+ * 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 java.util.List;
+
+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 org.keycloak.representations.idm.UserFederationProviderFactoryRepresentation;
+import org.keycloak.representations.idm.UserFederationProviderRepresentation;
+
+/**
+ * @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);
+
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/UserFederationProviderResource.java b/services/src/main/java/org/keycloak/services/resources/admin/UserFederationProviderResource.java
index ecfc307..2a56aa0 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/UserFederationProviderResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/UserFederationProviderResource.java
@@ -158,6 +158,7 @@ public class UserFederationProviderResource {
@POST
@Path("sync")
@NoCache
+ @Produces(MediaType.APPLICATION_JSON)
public UserFederationSyncResult syncUsers(@QueryParam("action") String action) {
auth.requireManage();
@@ -352,6 +353,7 @@ public class UserFederationProviderResource {
@POST
@Path("mappers/{id}/sync")
@NoCache
+ @Produces(MediaType.APPLICATION_JSON)
public UserFederationSyncResult syncMapperData(@PathParam("id") String mapperId, @QueryParam("direction") String direction) {
auth.requireManage();
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/federation/DummyConfigurableUserFederationProviderFactory.java b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/federation/DummyConfigurableUserFederationProviderFactory.java
new file mode 100644
index 0000000..ec63c89
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/federation/DummyConfigurableUserFederationProviderFactory.java
@@ -0,0 +1,62 @@
+/*
+ * 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.testsuite.federation;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.keycloak.provider.ConfiguredProvider;
+import org.keycloak.provider.ProviderConfigProperty;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class DummyConfigurableUserFederationProviderFactory extends DummyUserFederationProviderFactory implements ConfiguredProvider {
+
+ public static final String PROVIDER_NAME = "dummy-configurable";
+
+ @Override
+ public String getId() {
+ return PROVIDER_NAME;
+ }
+
+ @Override
+ public String getHelpText() {
+ return "Dummy User Federation Provider Help Text";
+ }
+
+ @Override
+ public List<ProviderConfigProperty> getConfigProperties() {
+
+ ProviderConfigProperty prop1 = new ProviderConfigProperty();
+ prop1.setName("prop1");
+ prop1.setLabel("Prop1");
+ prop1.setDefaultValue("prop1Default");
+ prop1.setHelpText("Prop1 HelpText");
+ prop1.setType(ProviderConfigProperty.STRING_TYPE);
+
+ ProviderConfigProperty prop2 = new ProviderConfigProperty();
+ prop2.setName("prop2");
+ prop2.setLabel("Prop2");
+ prop2.setDefaultValue("true");
+ prop2.setHelpText("Prop2 HelpText");
+ prop2.setType(ProviderConfigProperty.BOOLEAN_TYPE);
+
+ return Arrays.asList(prop1, prop2);
+ }
+}
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/federation/DummyUserFederationProvider.java b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/federation/DummyUserFederationProvider.java
new file mode 100644
index 0000000..0ba4816
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/federation/DummyUserFederationProvider.java
@@ -0,0 +1,149 @@
+/*
+ * 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.testsuite.federation;
+
+import org.keycloak.models.CredentialValidationOutput;
+import org.keycloak.models.GroupModel;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserFederationProvider;
+import org.keycloak.models.UserModel;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class DummyUserFederationProvider implements UserFederationProvider {
+
+ private final Map<String, UserModel> users;
+
+ public DummyUserFederationProvider(Map<String, UserModel> users) {
+ this.users = users;
+ }
+
+ @Override
+ public UserModel validateAndProxy(RealmModel realm, UserModel local) {
+ return local;
+ }
+
+ @Override
+ public boolean synchronizeRegistrations() {
+ return true;
+ }
+
+ @Override
+ public UserModel register(RealmModel realm, UserModel user) {
+ users.put(user.getUsername(), user);
+ return user;
+ }
+
+ @Override
+ public boolean removeUser(RealmModel realm, UserModel user) {
+ return users.remove(user.getUsername()) != null;
+ }
+
+ @Override
+ public UserModel getUserByUsername(RealmModel realm, String username) {
+ return users.get(username);
+ }
+
+ @Override
+ public UserModel getUserByEmail(RealmModel realm, String email) {
+ return null;
+ }
+
+ @Override
+ public List<UserModel> searchByAttributes(Map<String, String> attributes, RealmModel realm, int maxResults) {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group, int firstResult, int maxResults) {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public void preRemove(RealmModel realm) {
+
+ }
+
+ @Override
+ public void preRemove(RealmModel realm, RoleModel role) {
+
+ }
+
+ @Override
+ public void preRemove(RealmModel realm, GroupModel group) {
+
+ }
+
+ @Override
+ public boolean isValid(RealmModel realm, UserModel local) {
+ String username = local.getUsername();
+ return users.containsKey(username);
+ }
+
+ @Override
+ public Set<String> getSupportedCredentialTypes(UserModel user) {
+ // Just user "test-user" is able to validate password with this federationProvider
+ if (user.getUsername().equals("test-user")) {
+ return Collections.singleton(UserCredentialModel.PASSWORD);
+ } else {
+ return Collections.emptySet();
+ }
+ }
+
+ @Override
+ public Set<String> getSupportedCredentialTypes() {
+ return Collections.singleton(UserCredentialModel.PASSWORD);
+ }
+
+ @Override
+ public boolean validCredentials(RealmModel realm, UserModel user, List<UserCredentialModel> input) {
+ if (user.getUsername().equals("test-user") && input.size() == 1) {
+ UserCredentialModel password = input.get(0);
+ if (password.getType().equals(UserCredentialModel.PASSWORD)) {
+ return "secret".equals(password.getValue());
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean validCredentials(RealmModel realm, UserModel user, UserCredentialModel... input) {
+ return validCredentials(realm, user, Arrays.asList(input));
+ }
+
+ @Override
+ public CredentialValidationOutput validCredentials(RealmModel realm, UserCredentialModel credential) {
+ return CredentialValidationOutput.failed();
+ }
+
+ @Override
+ public void close() {
+
+ }
+}
+
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/federation/DummyUserFederationProviderFactory.java b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/federation/DummyUserFederationProviderFactory.java
new file mode 100644
index 0000000..8bb9e11
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/federation/DummyUserFederationProviderFactory.java
@@ -0,0 +1,108 @@
+/*
+ * 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.testsuite.federation;
+
+import org.jboss.logging.Logger;
+import org.keycloak.Config;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.UserFederationProvider;
+import org.keycloak.models.UserFederationProviderFactory;
+import org.keycloak.models.UserFederationProviderModel;
+import org.keycloak.models.UserFederationSyncResult;
+import org.keycloak.models.UserModel;
+import org.keycloak.provider.ConfiguredProvider;
+import org.keycloak.provider.ProviderConfigProperty;
+
+import java.util.*;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class DummyUserFederationProviderFactory implements UserFederationProviderFactory {
+
+ private static final Logger logger = Logger.getLogger(DummyUserFederationProviderFactory.class);
+ public static final String PROVIDER_NAME = "dummy";
+
+ private AtomicInteger fullSyncCounter = new AtomicInteger();
+ private AtomicInteger changedSyncCounter = new AtomicInteger();
+
+ private Map<String, UserModel> users = new HashMap<String, UserModel>();
+
+ @Override
+ public UserFederationProvider getInstance(KeycloakSession session, UserFederationProviderModel model) {
+ return new DummyUserFederationProvider(users);
+ }
+
+ @Override
+ public Set<String> getConfigurationOptions() {
+ Set<String> list = new HashSet<String>();
+ list.add("important.config");
+ return list;
+ }
+
+ @Override
+ public UserFederationProvider create(KeycloakSession session) {
+ return new DummyUserFederationProvider(users);
+ }
+
+ @Override
+ public void init(Config.Scope config) {
+
+ }
+
+ @Override
+ public void postInit(KeycloakSessionFactory factory) {
+
+ }
+
+ @Override
+ public void close() {
+
+ }
+
+ @Override
+ public String getId() {
+ return PROVIDER_NAME;
+ }
+
+ @Override
+ public UserFederationSyncResult syncAllUsers(KeycloakSessionFactory sessionFactory, String realmId, UserFederationProviderModel model) {
+ logger.info("syncAllUsers invoked");
+ fullSyncCounter.incrementAndGet();
+ return UserFederationSyncResult.empty();
+ }
+
+ @Override
+ public UserFederationSyncResult syncChangedUsers(KeycloakSessionFactory sessionFactory, String realmId, UserFederationProviderModel model, Date lastSync) {
+ logger.info("syncChangedUsers invoked");
+ changedSyncCounter.incrementAndGet();
+ return UserFederationSyncResult.empty();
+ }
+
+ public int getFullSyncCounter() {
+ return fullSyncCounter.get();
+ }
+
+ public int getChangedSyncCounter() {
+ return changedSyncCounter.get();
+ }
+
+}
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/META-INF/services/org.keycloak.models.UserFederationProviderFactory b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/META-INF/services/org.keycloak.models.UserFederationProviderFactory
new file mode 100644
index 0000000..015d4cd
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/META-INF/services/org.keycloak.models.UserFederationProviderFactory
@@ -0,0 +1,36 @@
+#
+# 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.
+#
+
+#
+# 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.
+#
+
+org.keycloak.testsuite.federation.DummyUserFederationProviderFactory
+org.keycloak.testsuite.federation.DummyConfigurableUserFederationProviderFactory
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/AbstractAuthenticationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/AbstractAuthenticationTest.java
index fb7e966..50b11ac 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/AbstractAuthenticationTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/AbstractAuthenticationTest.java
@@ -63,7 +63,7 @@ public abstract class AbstractAuthenticationTest extends AbstractKeycloakTest {
}
- AuthenticationExecutionInfoRepresentation findExecutionByProvider(String provider, List<AuthenticationExecutionInfoRepresentation> executions) {
+ public static AuthenticationExecutionInfoRepresentation findExecutionByProvider(String provider, List<AuthenticationExecutionInfoRepresentation> executions) {
for (AuthenticationExecutionInfoRepresentation exec : executions) {
if (provider.equals(exec.getProviderId())) {
return exec;
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserFederationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserFederationTest.java
new file mode 100644
index 0000000..3ad31a6
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserFederationTest.java
@@ -0,0 +1,363 @@
+/*
+ * 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.testsuite.admin;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.ws.rs.BadRequestException;
+import javax.ws.rs.NotFoundException;
+import javax.ws.rs.core.GenericType;
+import javax.ws.rs.core.Response;
+
+import org.junit.Test;
+import org.keycloak.admin.client.resource.UserFederationProvidersResource;
+import org.keycloak.common.constants.KerberosConstants;
+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.ConfigPropertyRepresentation;
+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.UserFederationProviderBuilder;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class UserFederationTest extends AbstractAdminTest {
+
+ @Test
+ public void testProviderFactories() {
+ List<UserFederationProviderFactoryRepresentation> providerFactories = userFederation().getProviderFactories();
+ Assert.assertNames(providerFactories, "ldap", "kerberos", "dummy", "dummy-configurable");
+
+ // Builtin provider without properties
+ UserFederationProviderFactoryRepresentation ldapProvider = userFederation().getProviderFactory("ldap");
+ Assert.assertEquals(ldapProvider.getId(), "ldap");
+ Assert.assertEquals(0, ldapProvider.getOptions().size());
+
+ // Configurable through the "old-way" options
+ UserFederationProviderFactoryRepresentation dummyProvider = userFederation().getProviderFactory("dummy");
+ Assert.assertEquals(dummyProvider.getId(), "dummy");
+ Assert.assertNames(new LinkedList<>(dummyProvider.getOptions()), "important.config");
+
+ // Configurable through the "new-way" ConfiguredProvider
+ UserFederationProviderFactoryRepresentation dummyConfiguredProvider = userFederation().getProviderFactory("dummy-configurable");
+ Assert.assertEquals(dummyConfiguredProvider.getId(), "dummy-configurable");
+ Assert.assertTrue(dummyConfiguredProvider.getOptions() == null || dummyConfiguredProvider.getOptions().isEmpty());
+ Assert.assertEquals("Dummy User Federation Provider Help Text", dummyConfiguredProvider.getHelpText());
+ Assert.assertEquals(2, dummyConfiguredProvider.getProperties().size());
+ assertProviderConfigProperty(dummyConfiguredProvider.getProperties().get(0), "prop1", "Prop1", "prop1Default", "Prop1 HelpText", ProviderConfigProperty.STRING_TYPE);
+ assertProviderConfigProperty(dummyConfiguredProvider.getProperties().get(1), "prop2", "Prop2", "true", "Prop2 HelpText", ProviderConfigProperty.BOOLEAN_TYPE);
+
+ try {
+ userFederation().getProviderFactory("not-existent");
+ Assert.fail("Not expected to find not-existent provider");
+ } catch (NotFoundException nfe) {
+ nfe.getResponse().close();
+ }
+ }
+
+ private UserFederationProvidersResource userFederation() {
+ return realm.userFederation();
+ }
+
+ private void assertProviderConfigProperty(ConfigPropertyRepresentation property, String name, String label, String defaultValue, String helpText, String type) {
+ Assert.assertEquals(name, property.getName());
+ Assert.assertEquals(label, property.getLabel());
+ Assert.assertEquals(defaultValue, property.getDefaultValue());
+ Assert.assertEquals(helpText, property.getHelpText());
+ Assert.assertEquals(type, property.getType());
+ }
+
+
+ @Test
+ public void testCreateProvider() {
+ // create provider without configuration and displayName
+ UserFederationProviderRepresentation dummyRep1 = UserFederationProviderBuilder.create()
+ .providerName("dummy")
+ .displayName("")
+ .priority(2)
+ .fullSyncPeriod(1000)
+ .changedSyncPeriod(500)
+ .lastSync(123)
+ .build();
+
+ String id1 = createUserFederationProvider(dummyRep1);
+
+ // create provider with configuration and displayName
+ UserFederationProviderRepresentation dummyRep2 = UserFederationProviderBuilder.create()
+ .providerName("dummy")
+ .displayName("dn1")
+ .priority(1)
+ .configProperty("prop1", "prop1Val")
+ .configProperty("prop2", "true")
+ .build();
+ String id2 = createUserFederationProvider(dummyRep2);
+
+ // Assert provider instances available
+ assertFederationProvider(userFederation().get(id1).toRepresentation(), id1, id1, "dummy", 2, 1000, 500, 123);
+ assertFederationProvider(userFederation().get(id2).toRepresentation(), id2, "dn1", "dummy", 1, -1, -1, -1, "prop1", "prop1Val", "prop2", "true");
+
+ // Assert sorted
+ List<UserFederationProviderRepresentation> providerInstances = userFederation().getProviderInstances();
+ Assert.assertEquals(providerInstances.size(), 2);
+ assertFederationProvider(providerInstances.get(0), id2, "dn1", "dummy", 1, -1, -1, -1, "prop1", "prop1Val", "prop2", "true");
+ assertFederationProvider(providerInstances.get(1), id1, id1, "dummy", 2, 1000, 500, 123);
+
+ // Remove providers
+ userFederation().get(id1).remove();
+ userFederation().get(id2).remove();
+ }
+
+
+ @Test
+ public void testValidateAndCreateLdapProvider() {
+ // Invalid filter
+ UserFederationProviderRepresentation ldapRep = UserFederationProviderBuilder.create()
+ .displayName("ldap1")
+ .providerName("ldap")
+ .priority(1)
+ .configProperty(LDAPConstants.CUSTOM_USER_SEARCH_FILTER, "dc=something")
+ .build();
+ Response resp = userFederation().create(ldapRep);
+ Assert.assertEquals(400, resp.getStatus());
+ resp.close();
+
+ // Invalid filter
+ ldapRep.getConfig().put(LDAPConstants.CUSTOM_USER_SEARCH_FILTER, "(dc=something");
+ resp = userFederation().create(ldapRep);
+ Assert.assertEquals(400, resp.getStatus());
+ resp.close();
+
+ // Invalid filter
+ ldapRep.getConfig().put(LDAPConstants.CUSTOM_USER_SEARCH_FILTER, "dc=something)");
+ resp = userFederation().create(ldapRep);
+ Assert.assertEquals(400, resp.getStatus());
+ resp.close();
+
+ // Assert nothing created so far
+ Assert.assertTrue(userFederation().getProviderInstances().isEmpty());
+
+
+ // Valid filter. Creation success
+ ldapRep.getConfig().put(LDAPConstants.CUSTOM_USER_SEARCH_FILTER, "(dc=something)");
+ String id1 = createUserFederationProvider(ldapRep);
+
+ // Missing filter is ok too. Creation success
+ UserFederationProviderRepresentation ldapRep2 = UserFederationProviderBuilder.create()
+ .displayName("ldap2")
+ .providerName("ldap")
+ .priority(2)
+ .configProperty(LDAPConstants.BIND_DN, "cn=manager")
+ .configProperty(LDAPConstants.BIND_CREDENTIAL, "password")
+ .build();
+ String id2 = createUserFederationProvider(ldapRep2);
+
+ // Assert both providers created
+ List<UserFederationProviderRepresentation> providerInstances = userFederation().getProviderInstances();
+ Assert.assertEquals(providerInstances.size(), 2);
+ assertFederationProvider(providerInstances.get(0), id1, "ldap1", "ldap", 1, -1, -1, -1, LDAPConstants.CUSTOM_USER_SEARCH_FILTER, "(dc=something)");
+ assertFederationProvider(providerInstances.get(1), id2, "ldap2", "ldap", 2, -1, -1, -1, LDAPConstants.BIND_DN, "cn=manager", LDAPConstants.BIND_CREDENTIAL, "password");
+
+ // Cleanup
+ userFederation().get(id1).remove();
+ userFederation().get(id2).remove();
+ }
+
+
+ @Test
+ public void testUpdateProvider() {
+ UserFederationProviderRepresentation ldapRep = UserFederationProviderBuilder.create()
+ .providerName("ldap")
+ .priority(2)
+ .configProperty(LDAPConstants.BIND_DN, "cn=manager")
+ .configProperty(LDAPConstants.BIND_CREDENTIAL, "password")
+ .build();
+ String id = createUserFederationProvider(ldapRep);
+ assertFederationProvider(userFederation().get(id).toRepresentation(), id, id, "ldap", 2, -1, -1, -1, LDAPConstants.BIND_DN, "cn=manager", LDAPConstants.BIND_CREDENTIAL, "password");
+
+ // Assert update with invalid filter should fail
+ ldapRep = userFederation().get(id).toRepresentation();
+ ldapRep.setDisplayName("");
+ ldapRep.getConfig().put(LDAPConstants.CUSTOM_USER_SEARCH_FILTER, "(dc=something2");
+ ldapRep.getConfig().put(LDAPConstants.BIND_DN, "cn=manager-updated");
+ try {
+ userFederation().get(id).update(ldapRep);
+ Assert.fail("Not expected to successfull update");
+ } catch (BadRequestException bre) {
+ bre.getResponse().close();
+ }
+
+ // Assert nothing was updated
+ assertFederationProvider(userFederation().get(id).toRepresentation(), id, id, "ldap", 2, -1, -1, -1, LDAPConstants.BIND_DN, "cn=manager", LDAPConstants.BIND_CREDENTIAL, "password");
+
+ // Change filter to be valid
+ ldapRep.getConfig().put(LDAPConstants.CUSTOM_USER_SEARCH_FILTER, "(dc=something2)");
+ userFederation().get(id).update(ldapRep);
+
+ // Assert updated successfully
+ ldapRep = userFederation().get(id).toRepresentation();
+ assertFederationProvider(ldapRep, id, id, "ldap", 2, -1, -1, -1, LDAPConstants.BIND_DN, "cn=manager-updated", LDAPConstants.BIND_CREDENTIAL, "password",
+ LDAPConstants.CUSTOM_USER_SEARCH_FILTER, "(dc=something2)");
+
+ // Assert update displayName
+ ldapRep.setDisplayName("ldap2");
+ userFederation().get(id).update(ldapRep);
+ assertFederationProvider(userFederation().get(id).toRepresentation(), id, "ldap2", "ldap", 2, -1, -1, -1, LDAPConstants.BIND_DN, "cn=manager-updated", LDAPConstants.BIND_CREDENTIAL, "password",
+ LDAPConstants.CUSTOM_USER_SEARCH_FILTER, "(dc=something2)");
+
+
+
+ // Cleanup
+ userFederation().get(id).remove();
+ }
+
+
+ @Test
+ public void testKerberosAuthenticatorEnabledAutomatically() {
+ // Assert kerberos authenticator DISABLED
+ AuthenticationExecutionInfoRepresentation kerberosExecution = findKerberosExecution();
+ Assert.assertEquals(kerberosExecution.getRequirement(), AuthenticationExecutionModel.Requirement.DISABLED.toString());
+
+ // create LDAP provider with kerberos
+ UserFederationProviderRepresentation ldapRep = UserFederationProviderBuilder.create()
+ .displayName("ldap2")
+ .providerName("ldap")
+ .priority(2)
+ .configProperty(KerberosConstants.ALLOW_KERBEROS_AUTHENTICATION, "true")
+ .build();
+ String id = createUserFederationProvider(ldapRep);
+
+ // Assert kerberos authenticator ALTERNATIVE
+ kerberosExecution = findKerberosExecution();
+ Assert.assertEquals(kerberosExecution.getRequirement(), AuthenticationExecutionModel.Requirement.ALTERNATIVE.toString());
+
+ // Switch kerberos authenticator to DISABLED
+ kerberosExecution.setRequirement(AuthenticationExecutionModel.Requirement.DISABLED.toString());
+ realm.flows().updateExecutions("browser", kerberosExecution);
+
+ // update LDAP provider with kerberos
+ ldapRep = userFederation().get(id).toRepresentation();
+ userFederation().get(id).update(ldapRep);
+
+ // Assert kerberos authenticator ALTERNATIVE
+ kerberosExecution = findKerberosExecution();
+ Assert.assertEquals(kerberosExecution.getRequirement(), AuthenticationExecutionModel.Requirement.ALTERNATIVE.toString());
+
+ // Cleanup
+ kerberosExecution.setRequirement(AuthenticationExecutionModel.Requirement.DISABLED.toString());
+ realm.flows().updateExecutions("browser", kerberosExecution);
+ userFederation().get(id).remove();
+ }
+
+
+ @Test (expected = NotFoundException.class)
+ public void testLookupNotExistentProvider() {
+ userFederation().get("not-existent").toRepresentation();
+ }
+
+
+ @Test
+ public void testSyncFederationProvider() {
+ // create provider
+ UserFederationProviderRepresentation dummyRep1 = UserFederationProviderBuilder.create()
+ .providerName("dummy")
+ .build();
+ String id1 = createUserFederationProvider(dummyRep1);
+
+
+ // Sync with unknown action shouldn't pass
+ try {
+ userFederation().get(id1).syncUsers("unknown");
+ Assert.fail("Not expected to sync with unknown action");
+ } catch (NotFoundException nfe) {
+ nfe.getResponse().close();
+ }
+
+ // Assert sync didn't happen
+ Assert.assertEquals(-1, userFederation().get(id1).toRepresentation().getLastSync());
+
+ // Sync and assert it happened
+ UserFederationSyncResultRepresentation syncResult = userFederation().get(id1).syncUsers("triggerFullSync");
+ Assert.assertEquals("0 imported users, 0 updated users", syncResult.getStatus());
+ int fullSyncTime = userFederation().get(id1).toRepresentation().getLastSync();
+ Assert.assertTrue(fullSyncTime > 0);
+
+ // Changed sync
+ setTimeOffset(50);
+ syncResult = userFederation().get(id1).syncUsers("triggerChangedUsersSync");
+ Assert.assertEquals("0 imported users, 0 updated users", syncResult.getStatus());
+ int changedSyncTime = userFederation().get(id1).toRepresentation().getLastSync();
+ Assert.assertTrue(fullSyncTime + 50 <= changedSyncTime);
+
+ // Cleanup
+ resetTimeOffset();
+ userFederation().get(id1).remove();
+ }
+
+
+ private String createUserFederationProvider(UserFederationProviderRepresentation rep) {
+ Response resp = userFederation().create(rep);
+ Assert.assertEquals(201, resp.getStatus());
+ resp.close();
+ return ApiUtil.getCreatedId(resp);
+ }
+
+ private void assertFederationProvider(UserFederationProviderRepresentation rep, String id, String displayName, String providerName,
+ int priority, int fullSyncPeriod, int changeSyncPeriod, int lastSync,
+ String... config) {
+ Assert.assertEquals(id, rep.getId());
+ Assert.assertEquals(displayName, rep.getDisplayName());
+ Assert.assertEquals(providerName, rep.getProviderName());
+ Assert.assertEquals(priority, rep.getPriority());
+ Assert.assertEquals(fullSyncPeriod, rep.getFullSyncPeriod());
+ Assert.assertEquals(changeSyncPeriod, rep.getChangedSyncPeriod());
+ Assert.assertEquals(lastSync, rep.getLastSync());
+ if (config == null) {
+ config = new String[] {};
+ }
+
+ Assert.assertEquals(rep.getConfig().size() * 2, config.length);
+ for (int i=0 ; i<config.length ; i+=2) {
+ String key = config[i];
+ String value = config[i+1];
+ Assert.assertEquals(value, rep.getConfig().get(key));
+ }
+ }
+
+
+ private AuthenticationExecutionInfoRepresentation findKerberosExecution() {
+ AuthenticationExecutionInfoRepresentation kerberosExecution = null;
+ Response response = realm.flows().getExecutions("browser");
+ try {
+ List<AuthenticationExecutionInfoRepresentation> executionReps = response.readEntity(new GenericType<List<AuthenticationExecutionInfoRepresentation>>() {
+ });
+ kerberosExecution = AbstractAuthenticationTest.findExecutionByProvider("auth-spnego", executionReps);
+ } finally {
+ response.close();
+ }
+
+ Assert.assertNotNull(kerberosExecution);
+ return kerberosExecution;
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/Assert.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/Assert.java
index 2a82d48..267c832 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/Assert.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/Assert.java
@@ -22,16 +22,13 @@ import org.keycloak.representations.idm.IdentityProviderRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.representations.idm.UserFederationProviderFactoryRepresentation;
import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
-import static org.junit.Assert.assertArrayEquals;
-
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
@@ -49,16 +46,6 @@ public class Assert extends org.junit.Assert {
assertArrayEquals("Expected: " + Arrays.toString(expected) + ", was: " + Arrays.toString(actualNames), expected, actualNames);
}
- private static <T> List<T> sort(List<T> list) {
- Collections.sort(list, new Comparator<Object>() {
- @Override
- public int compare(Object o1, Object o2) {
- return name(o1).compareTo(name(o2));
- }
- });
- return list;
- }
-
private static <T> String[] names(List<T> list) {
String[] names = new String[list.size()];
for (int i = 0; i < list.size(); i++) {
@@ -69,7 +56,9 @@ public class Assert extends org.junit.Assert {
}
private static String name(Object o1) {
- if (o1 instanceof RealmRepresentation) {
+ if (o1 instanceof String) {
+ return (String) o1;
+ } else if (o1 instanceof RealmRepresentation) {
return ((RealmRepresentation) o1).getRealm();
} else if (o1 instanceof ClientRepresentation) {
return ((ClientRepresentation) o1).getClientId();
@@ -79,7 +68,10 @@ public class Assert extends org.junit.Assert {
return ((RoleRepresentation) o1).getName();
} else if (o1 instanceof UserRepresentation) {
return ((UserRepresentation) o1).getUsername();
+ } else if (o1 instanceof UserFederationProviderFactoryRepresentation) {
+ return ((UserFederationProviderFactoryRepresentation) o1).getId();
}
+
throw new IllegalArgumentException();
}
}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/UserFederationProviderBuilder.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/UserFederationProviderBuilder.java
new file mode 100644
index 0000000..61f45c7
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/UserFederationProviderBuilder.java
@@ -0,0 +1,108 @@
+/*
+ * 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.testsuite.util;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.keycloak.representations.idm.UserFederationProviderRepresentation;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class UserFederationProviderBuilder {
+
+ private String id;
+ private String displayName;
+ private String providerName;
+ private Map<String, String> config;
+ private int priority = 1;
+ private int fullSyncPeriod = -1;
+ private int changedSyncPeriod = -1;
+ private int lastSync = -1;
+
+ private UserFederationProviderBuilder() {};
+
+ public static UserFederationProviderBuilder create() {
+ return new UserFederationProviderBuilder();
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public UserFederationProviderBuilder displayName(String displayName) {
+ this.displayName = displayName;
+ return this;
+ }
+
+ public UserFederationProviderBuilder providerName(String providerName) {
+ this.providerName = providerName;
+ return this;
+ }
+
+ public UserFederationProviderBuilder configProperty(String key, String value) {
+ if (this.config == null) {
+ this.config = new HashMap<>();
+ }
+ this.config.put(key, value);
+ return this;
+ }
+
+ public UserFederationProviderBuilder removeConfigProperty(String key) {
+ if (this.config != null) {
+ this.config.remove(key);
+ }
+ return this;
+ }
+
+ public UserFederationProviderBuilder priority(int priority) {
+ this.priority = priority;
+ return this;
+ }
+
+ public UserFederationProviderBuilder fullSyncPeriod(int fullSyncPeriod) {
+ this.fullSyncPeriod = fullSyncPeriod;
+ return this;
+ }
+
+ public UserFederationProviderBuilder changedSyncPeriod(int changedSyncPeriod) {
+ this.changedSyncPeriod = changedSyncPeriod;
+ return this;
+ }
+
+ public UserFederationProviderBuilder lastSync(int lastSync) {
+ this.lastSync = lastSync;
+ return this;
+ }
+
+ public UserFederationProviderRepresentation build() {
+ UserFederationProviderRepresentation rep = new UserFederationProviderRepresentation();
+ rep.setId(id);
+ rep.setDisplayName(displayName);
+ rep.setProviderName(providerName);
+ rep.setConfig(config);
+ rep.setPriority(priority);
+ rep.setFullSyncPeriod(fullSyncPeriod);
+ rep.setChangedSyncPeriod(changedSyncPeriod);
+ rep.setLastSync(lastSync);
+ return rep;
+ }
+
+
+}