/*
* 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 org.junit.Test;
import org.keycloak.common.constants.KerberosConstants;
import org.keycloak.common.util.MultivaluedHashMap;
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.representations.idm.AuthenticationExecutionInfoRepresentation;
import org.keycloak.representations.idm.ComponentRepresentation;
import org.keycloak.storage.UserStorageProvider;
import org.keycloak.testsuite.Assert;
import org.keycloak.testsuite.admin.authentication.AbstractAuthenticationTest;
import org.keycloak.testsuite.util.AdminEventPaths;
import javax.ws.rs.BadRequestException;
import javax.ws.rs.core.Response;
import java.util.List;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class UserStorageRestTest extends AbstractAdminTest {
private AuthenticationExecutionInfoRepresentation findKerberosExecution() {
AuthenticationExecutionInfoRepresentation kerberosExecution = null;
List<AuthenticationExecutionInfoRepresentation> executionReps = realm.flows().getExecutions("browser");
kerberosExecution = AbstractAuthenticationTest.findExecutionByProvider("auth-spnego", executionReps);
Assert.assertNotNull(kerberosExecution);
return kerberosExecution;
}
private String createComponent(ComponentRepresentation rep) {
Response resp = realm.components().add(rep);
Assert.assertEquals(201, resp.getStatus());
resp.close();
String id = ApiUtil.getCreatedId(resp);
assertAdminEvents.clear();
return id;
}
private void removeComponent(String id) {
realm.components().component(id).remove();
assertAdminEvents.clear();
}
private void assertFederationProvider(ComponentRepresentation rep, String id, String displayName, String providerId,
String... config) {
Assert.assertEquals(id, rep.getId());
Assert.assertEquals(displayName, rep.getName());
Assert.assertEquals(providerId, rep.getProviderId());
Assert.assertMultivaluedMap(rep.getConfig(), config);
}
@Test
public void testKerberosAuthenticatorEnabledAutomatically() {
// Assert kerberos authenticator DISABLED
AuthenticationExecutionInfoRepresentation kerberosExecution = findKerberosExecution();
Assert.assertEquals(kerberosExecution.getRequirement(), AuthenticationExecutionModel.Requirement.DISABLED.toString());
// create LDAP provider with kerberos
ComponentRepresentation ldapRep = new ComponentRepresentation();
ldapRep.setName("ldap2");
ldapRep.setProviderId("ldap");
ldapRep.setProviderType(UserStorageProvider.class.getName());
ldapRep.setConfig(new MultivaluedHashMap<>());
ldapRep.getConfig().putSingle("priority", Integer.toString(2));
ldapRep.getConfig().putSingle(KerberosConstants.ALLOW_KERBEROS_AUTHENTICATION, "true");
String id = createComponent(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);
assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.authUpdateExecutionPath("browser"), kerberosExecution, ResourceType.AUTH_EXECUTION);
// update LDAP provider with kerberos
ldapRep = realm.components().component(id).toRepresentation();
realm.components().component(id).update(ldapRep);
assertAdminEvents.clear();
// 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);
assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.authUpdateExecutionPath("browser"), kerberosExecution, ResourceType.AUTH_EXECUTION);
removeComponent(id);
}
@Test
public void testKerberosAuthenticatorChangedOnlyIfDisabled() {
// Change kerberos to REQUIRED
AuthenticationExecutionInfoRepresentation kerberosExecution = findKerberosExecution();
kerberosExecution.setRequirement(AuthenticationExecutionModel.Requirement.REQUIRED.toString());
realm.flows().updateExecutions("browser", kerberosExecution);
assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.authUpdateExecutionPath("browser"), kerberosExecution, ResourceType.AUTH_EXECUTION);
// create LDAP provider with kerberos
ComponentRepresentation ldapRep = new ComponentRepresentation();
ldapRep.setName("ldap2");
ldapRep.setProviderId("ldap");
ldapRep.setProviderType(UserStorageProvider.class.getName());
ldapRep.setConfig(new MultivaluedHashMap<>());
ldapRep.getConfig().putSingle("priority", Integer.toString(2));
ldapRep.getConfig().putSingle(KerberosConstants.ALLOW_KERBEROS_AUTHENTICATION, "true");
String id = createComponent(ldapRep);
// Assert kerberos authenticator still REQUIRED
kerberosExecution = findKerberosExecution();
Assert.assertEquals(kerberosExecution.getRequirement(), AuthenticationExecutionModel.Requirement.REQUIRED.toString());
// update LDAP provider with kerberos
ldapRep = realm.components().component(id).toRepresentation();
realm.components().component(id).update(ldapRep);
assertAdminEvents.clear();
// Assert kerberos authenticator still REQUIRED
kerberosExecution = findKerberosExecution();
Assert.assertEquals(kerberosExecution.getRequirement(), AuthenticationExecutionModel.Requirement.REQUIRED.toString());
// Cleanup
kerberosExecution.setRequirement(AuthenticationExecutionModel.Requirement.DISABLED.toString());
realm.flows().updateExecutions("browser", kerberosExecution);
assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.authUpdateExecutionPath("browser"), kerberosExecution, ResourceType.AUTH_EXECUTION);
removeComponent(id);
}
@Test
public void testValidateAndCreateLdapProvider() {
// Invalid filter
ComponentRepresentation ldapRep = new ComponentRepresentation();
ldapRep.setName("ldap2");
ldapRep.setProviderId("ldap");
ldapRep.setProviderType(UserStorageProvider.class.getName());
ldapRep.setConfig(new MultivaluedHashMap<>());
ldapRep.getConfig().putSingle("priority", Integer.toString(2));
ldapRep.getConfig().putSingle(LDAPConstants.CUSTOM_USER_SEARCH_FILTER, "dc=something");
Response resp = realm.components().add(ldapRep);
Assert.assertEquals(400, resp.getStatus());
resp.close();
// Invalid filter
ldapRep.getConfig().putSingle(LDAPConstants.CUSTOM_USER_SEARCH_FILTER, "(dc=something");
resp = realm.components().add(ldapRep);
Assert.assertEquals(400, resp.getStatus());
resp.close();
// Invalid filter
ldapRep.getConfig().putSingle(LDAPConstants.CUSTOM_USER_SEARCH_FILTER, "dc=something)");
resp = realm.components().add(ldapRep);
Assert.assertEquals(400, resp.getStatus());
resp.close();
// Assert nothing created so far
Assert.assertTrue(realm.components().query(realmId, UserStorageProvider.class.getName()).isEmpty());
assertAdminEvents.assertEmpty();
// Valid filter. Creation success
ldapRep.getConfig().putSingle(LDAPConstants.CUSTOM_USER_SEARCH_FILTER, "(dc=something)");
String id1 = createComponent(ldapRep);
// Missing filter is ok too. Creation success
ComponentRepresentation ldapRep2 = new ComponentRepresentation();
ldapRep2.setName("ldap3");
ldapRep2.setProviderId("ldap");
ldapRep2.setProviderType(UserStorageProvider.class.getName());
ldapRep2.setConfig(new MultivaluedHashMap<>());
ldapRep2.getConfig().putSingle("priority", Integer.toString(2));
ldapRep2.getConfig().putSingle(LDAPConstants.BIND_DN, "cn=manager");
ldapRep2.getConfig().putSingle(LDAPConstants.BIND_CREDENTIAL, "password");
String id2 = createComponent(ldapRep2);
// Assert both providers created
List<ComponentRepresentation> providerInstances = realm.components().query(realmId, UserStorageProvider.class.getName());
Assert.assertEquals(providerInstances.size(), 2);
// Cleanup
removeComponent(id1);
removeComponent(id2);
}
@Test
public void testUpdateProvider() {
ComponentRepresentation ldapRep = new ComponentRepresentation();
ldapRep.setName("ldap2");
ldapRep.setProviderId("ldap");
ldapRep.setProviderType(UserStorageProvider.class.getName());
ldapRep.setConfig(new MultivaluedHashMap<>());
ldapRep.getConfig().putSingle("priority", Integer.toString(2));
ldapRep.getConfig().putSingle(LDAPConstants.BIND_DN, "cn=manager");
ldapRep.getConfig().putSingle(LDAPConstants.BIND_CREDENTIAL, "password");
String id = createComponent(ldapRep);
// Assert update with invalid filter should fail
ldapRep = realm.components().component(id).toRepresentation();
ldapRep.getConfig().putSingle(LDAPConstants.CUSTOM_USER_SEARCH_FILTER, "(dc=something2");
ldapRep.getConfig().putSingle(LDAPConstants.BIND_DN, "cn=manager-updated");
try {
realm.components().component(id).update(ldapRep);
Assert.fail("Not expected to successfull update");
} catch (BadRequestException bre) {
// Expected
}
// Assert nothing was updated
assertFederationProvider(realm.components().component(id).toRepresentation(), id, "ldap2", "ldap", LDAPConstants.BIND_DN, "cn=manager", LDAPConstants.BIND_CREDENTIAL, "**********");
// Change filter to be valid
ldapRep.getConfig().putSingle(LDAPConstants.CUSTOM_USER_SEARCH_FILTER, "(dc=something2)");
realm.components().component(id).update(ldapRep);
assertAdminEvents.clear();
// Assert updated successfully
ldapRep = realm.components().component(id).toRepresentation();
assertFederationProvider(ldapRep, id, "ldap2", "ldap", LDAPConstants.BIND_DN, "cn=manager-updated", LDAPConstants.BIND_CREDENTIAL, "**********",
LDAPConstants.CUSTOM_USER_SEARCH_FILTER, "(dc=something2)");
// Assert update displayName
ldapRep.setName("ldap2");
realm.components().component(id).update(ldapRep);
assertFederationProvider(realm.components().component(id).toRepresentation(), id, "ldap2", "ldap",LDAPConstants.BIND_DN, "cn=manager-updated", LDAPConstants.BIND_CREDENTIAL, "**********",
LDAPConstants.CUSTOM_USER_SEARCH_FILTER, "(dc=something2)");
// Cleanup
removeComponent(id);
}
/*
@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());
Assert.assertProviderConfigProperty(dummyConfiguredProvider.getProperties().get(0), "prop1", "Prop1", "prop1Default", "Prop1 HelpText", ProviderConfigProperty.STRING_TYPE);
Assert.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) {
// Expected
}
}
private UserFederationProvidersResource userFederation() {
return null;//realm.userFederation();
}
@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
removeUserFederationProvider(id1);
removeUserFederationProvider(id2);
}
@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) {
// Expected
}
// Assert sync didn't happen
Assert.assertEquals(-1, userFederation().get(id1).toRepresentation().getLastSync());
// Sync and assert it happened
SynchronizationResultRepresentation syncResult = userFederation().get(id1).syncUsers("triggerFullSync");
Assert.assertEquals("0 imported users, 0 updated users", syncResult.getStatus());
Map<String, Object> eventRep = new HashMap<>();
eventRep.put("action", "triggerFullSync");
assertAdminEvents.assertEvent(realmId, OperationType.ACTION, AdminEventPaths.userFederationResourcePath(id1) + "/sync", eventRep, ResourceType.USER_FEDERATION_PROVIDER);
int fullSyncTime = userFederation().get(id1).toRepresentation().getLastSync();
Assert.assertTrue(fullSyncTime > 0);
// Changed sync
setTimeOffset(50);
syncResult = userFederation().get(id1).syncUsers("triggerChangedUsersSync");
eventRep.put("action", "triggerChangedUsersSync");
assertAdminEvents.assertEvent(realmId, OperationType.ACTION, AdminEventPaths.userFederationResourcePath(id1) + "/sync", eventRep, ResourceType.USER_FEDERATION_PROVIDER);
Assert.assertEquals("0 imported users, 0 updated users", syncResult.getStatus());
int changedSyncTime = userFederation().get(id1).toRepresentation().getLastSync();
Assert.assertTrue(fullSyncTime + 50 <= changedSyncTime);
// Cleanup
resetTimeOffset();
removeUserFederationProvider(id1);
}
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());
Assert.assertMap(rep.getConfig(), config);
}
*/
}