diff --git a/tests/utils-shared/pom.xml b/tests/utils-shared/pom.xml index 53d0a7721c2..8ba86630a90 100755 --- a/tests/utils-shared/pom.xml +++ b/tests/utils-shared/pom.xml @@ -51,6 +51,14 @@ org.keycloak keycloak-services + + org.keycloak + keycloak-model-infinispan + + + org.keycloak + keycloak-ldap-federation + org.keycloak keycloak-admin-client-tests diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/util/LDAPTestUtils.java b/tests/utils-shared/src/main/java/org/keycloak/testsuite/util/LDAPTestUtils.java similarity index 100% rename from testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/util/LDAPTestUtils.java rename to tests/utils-shared/src/main/java/org/keycloak/testsuite/util/LDAPTestUtils.java diff --git a/tests/utils-shared/src/main/java/org/keycloak/testsuite/util/runonserver/CacheHelper.java b/tests/utils-shared/src/main/java/org/keycloak/testsuite/util/runonserver/CacheHelper.java new file mode 100644 index 00000000000..14e2cdde430 --- /dev/null +++ b/tests/utils-shared/src/main/java/org/keycloak/testsuite/util/runonserver/CacheHelper.java @@ -0,0 +1,44 @@ +package org.keycloak.testsuite.util.runonserver; + +import org.keycloak.connections.infinispan.InfinispanConnectionProvider; +import org.keycloak.testframework.remote.providers.runonserver.FetchOnServer; +import org.keycloak.testframework.remote.providers.runonserver.FetchOnServerWrapper; + +public final class CacheHelper { + + public static FetchOnServerWrapper contains(String cacheName, String id) { + return new FetchOnServerWrapper<>() { + + @Override + public FetchOnServer getRunOnServer() { + return session -> { + InfinispanConnectionProvider provider = session.getProvider(InfinispanConnectionProvider.class); + return provider.getCache(cacheName).containsKey(id); + }; + } + + @Override + public Class getResultClass() { + return Boolean.class; + } + }; + } + + public static FetchOnServerWrapper size(String cacheName) { + return new FetchOnServerWrapper<>() { + + @Override + public FetchOnServer getRunOnServer() { + return session -> { + InfinispanConnectionProvider provider = session.getProvider(InfinispanConnectionProvider.class); + return provider.getCache(cacheName).size(); + }; + } + + @Override + public Class getResultClass() { + return Integer.class; + } + }; + } +} diff --git a/tests/utils-shared/src/main/java/org/keycloak/testsuite/util/runonserver/LdapHelper.java b/tests/utils-shared/src/main/java/org/keycloak/testsuite/util/runonserver/LdapHelper.java new file mode 100644 index 00000000000..0593607802d --- /dev/null +++ b/tests/utils-shared/src/main/java/org/keycloak/testsuite/util/runonserver/LdapHelper.java @@ -0,0 +1,139 @@ +package org.keycloak.testsuite.util.runonserver; + +import java.util.Map; + +import org.keycloak.common.util.MultivaluedHashMap; +import org.keycloak.component.ComponentModel; +import org.keycloak.models.LDAPConstants; +import org.keycloak.models.RealmModel; +import org.keycloak.models.utils.KeycloakModelUtils; +import org.keycloak.storage.UserStorageProvider; +import org.keycloak.storage.UserStorageProviderModel; +import org.keycloak.storage.ldap.LDAPStorageProvider; +import org.keycloak.storage.ldap.LDAPStorageProviderFactory; +import org.keycloak.storage.ldap.LDAPUtils; +import org.keycloak.storage.ldap.idm.model.LDAPObject; +import org.keycloak.storage.ldap.mappers.membership.LDAPGroupMapperMode; +import org.keycloak.storage.ldap.mappers.membership.MembershipType; +import org.keycloak.storage.ldap.mappers.membership.group.GroupLDAPStorageMapperFactory; +import org.keycloak.testframework.remote.providers.runonserver.FetchOnServer; +import org.keycloak.testframework.remote.providers.runonserver.RunOnServer; +import org.keycloak.testsuite.util.LDAPTestUtils; + +import static org.keycloak.testsuite.util.LDAPTestUtils.getGroupDescriptionLDAPAttrName; + +public final class LdapHelper { + + /** + * @param ldapCfg configuration of LDAP provider + * @param importEnabled specify if LDAP provider will have import enabled + * @return ID of newly created provider + */ + public static FetchOnServer createLDAPProvider(Map ldapCfg, boolean importEnabled) { + return session -> { + MultivaluedHashMap ldapConfig = toComponentConfig(ldapCfg); + ldapConfig.putSingle(LDAPConstants.SYNC_REGISTRATIONS, "true"); + ldapConfig.putSingle(LDAPConstants.EDIT_MODE, UserStorageProvider.EditMode.WRITABLE.toString()); + UserStorageProviderModel model = new UserStorageProviderModel(); + model.setLastSync(0); + model.setChangedSyncPeriod(-1); + model.setFullSyncPeriod(-1); + model.setName("test-ldap"); + model.setPriority(0); + model.setProviderId(LDAPStorageProviderFactory.PROVIDER_NAME); + model.setConfig(ldapConfig); + + model.setImportEnabled(importEnabled); + + model.setCachePolicy(UserStorageProviderModel.CachePolicy.MAX_LIFESPAN); + model.setMaxLifespan(600000); // Lifetime is 10 minutes + + ComponentModel ldapModel = session.getContext().getRealm().addComponentModel(model); + return ldapModel.getId(); + }; + } + + private static MultivaluedHashMap toComponentConfig(Map ldapConfig) { + MultivaluedHashMap config = new MultivaluedHashMap<>(); + for (Map.Entry entry : ldapConfig.entrySet()) { + config.add(entry.getKey(), entry.getValue()); + + } + return config; + } + + + /** + * Prepare groups LDAP tests. Creates some LDAP mappers as well as some built-in GRoups and users in LDAP + */ + public static RunOnServer prepareGroupsLDAPTest() { + return session -> { + RealmModel realm = session.getContext().getRealm(); + LDAPTestUtils.addLocalUser(session, realm, "mary", "mary@test.com", "password-app"); + LDAPTestUtils.addLocalUser(session, realm, "john", "john@test.com", "password-app"); + + ComponentModel ldapModel = LDAPTestUtils.getLdapProviderModel(realm); + LDAPStorageProvider ldapFedProvider = LDAPTestUtils.getLdapProvider(session, ldapModel); + String descriptionAttrName = getGroupDescriptionLDAPAttrName(ldapFedProvider); + + // Add group mapper + LDAPTestUtils.addOrUpdateGroupMapper(realm, ldapModel, LDAPGroupMapperMode.LDAP_ONLY, descriptionAttrName); + + // Remove all LDAP groups + LDAPTestUtils.removeAllLDAPGroups(session, realm, ldapModel, "groupsMapper"); + + // Add some groups for testing + LDAPObject group1 = LDAPTestUtils.createLDAPGroup(session, realm, ldapModel, "group1", descriptionAttrName, "group1 - description"); + LDAPObject group11 = LDAPTestUtils.createLDAPGroup(session, realm, ldapModel, "group11"); + LDAPObject group12 = LDAPTestUtils.createLDAPGroup(session, realm, ldapModel, "group12", descriptionAttrName, "group12 - description"); + + LDAPObject defaultGroup1 = LDAPTestUtils.createLDAPGroup(session, realm, ldapModel, "defaultGroup1", descriptionAttrName, "Default Group1 - description"); + LDAPObject defaultGroup11 = LDAPTestUtils.createLDAPGroup(session, realm, ldapModel, "defaultGroup11"); + LDAPObject defaultGroup12 = LDAPTestUtils.createLDAPGroup(session, realm, ldapModel, "defaultGroup12", descriptionAttrName, "Default Group12 - description"); + LDAPTestUtils.createLDAPGroup(session, realm, ldapModel, "Team 2016/2017", descriptionAttrName, "A group with slashes in the name"); + LDAPObject teamChild20182019 = LDAPTestUtils.createLDAPGroup(session, realm, ldapModel, "Team Child 2018/2019", descriptionAttrName, "A child group with slashes in the name"); + LDAPObject teamSubChild20202021 = LDAPTestUtils.createLDAPGroup(session, realm, ldapModel, "Team SubChild 2020/2021", descriptionAttrName, "A sub child group with slashes in the name"); + LDAPObject defaultGroup13 = LDAPTestUtils.createLDAPGroup(session, realm, ldapModel, "defaultGroup13", descriptionAttrName, "Default Group13 - description"); + LDAPObject teamSubChild20222023 = LDAPTestUtils.createLDAPGroup(session, realm, ldapModel, "Team SubChild 2022/2023/A/B/C/D/E", descriptionAttrName, "A sub child group with slashes in the name"); + LDAPObject defaultGroup14 = LDAPTestUtils.createLDAPGroup(session, realm, ldapModel, "defaultGroup14", descriptionAttrName, "Default Group14 - description"); + LDAPObject teamRoot20242025 = LDAPTestUtils.createLDAPGroup(session, realm, ldapModel, "Team Root 2024/2025/A/B/C/D", descriptionAttrName, "A sub child group with slashes in the name"); + LDAPObject defaultGroup15 = LDAPTestUtils.createLDAPGroup(session, realm, ldapModel, "defaultGroup15", descriptionAttrName, "Default Group15 - description"); + LDAPObject teamSubChild20262027 = LDAPTestUtils.createLDAPGroup(session, realm, ldapModel, "Team SubChild 2026/2027", descriptionAttrName, "A sub child group with slashes in the name"); + + LDAPUtils.addMember(ldapFedProvider, MembershipType.DN, LDAPConstants.MEMBER, "not-used", group1, group11); + LDAPUtils.addMember(ldapFedProvider, MembershipType.DN, LDAPConstants.MEMBER, "not-used", group1, group12); + + LDAPUtils.addMember(ldapFedProvider, MembershipType.DN, LDAPConstants.MEMBER, "not-used", defaultGroup1, defaultGroup11); + LDAPUtils.addMember(ldapFedProvider, MembershipType.DN, LDAPConstants.MEMBER, "not-used", defaultGroup1, defaultGroup12); + LDAPUtils.addMember(ldapFedProvider, MembershipType.DN, LDAPConstants.MEMBER, "not-used", defaultGroup1, teamChild20182019); + LDAPUtils.addMember(ldapFedProvider, MembershipType.DN, LDAPConstants.MEMBER, "not-used", teamChild20182019, teamSubChild20202021); + LDAPUtils.addMember(ldapFedProvider, MembershipType.DN, LDAPConstants.MEMBER, "not-used", defaultGroup13, teamSubChild20222023); + LDAPUtils.addMember(ldapFedProvider, MembershipType.DN, LDAPConstants.MEMBER, "not-used", teamSubChild20222023, defaultGroup14); + LDAPUtils.addMember(ldapFedProvider, MembershipType.DN, LDAPConstants.MEMBER, "not-used", teamRoot20242025, defaultGroup15); + LDAPUtils.addMember(ldapFedProvider, MembershipType.DN, LDAPConstants.MEMBER, "not-used", defaultGroup15, teamSubChild20262027); + + // Sync LDAP groups to Keycloak DB + ComponentModel mapperModel = LDAPTestUtils.getSubcomponentByName(realm, ldapModel, "groupsMapper"); + new GroupLDAPStorageMapperFactory().create(session, mapperModel).syncDataFromFederationProviderToKeycloak(realm); + + realm.addDefaultGroup(KeycloakModelUtils.findGroupByPath(session, realm, "/defaultGroup1/defaultGroup11")); + realm.addDefaultGroup(KeycloakModelUtils.findGroupByPath(session, realm, "/defaultGroup1/defaultGroup12")); + + // Delete all LDAP users + LDAPTestUtils.removeAllLDAPUsers(ldapFedProvider, realm); + + // Add some LDAP users for testing + LDAPObject john = LDAPTestUtils.addLDAPUser(ldapFedProvider, realm, "johnkeycloak", "John", "Doe", "john@email.org", null, "1234"); + LDAPTestUtils.updateLDAPPassword(ldapFedProvider, john, "Password1"); + + LDAPObject mary = LDAPTestUtils.addLDAPUser(ldapFedProvider, realm, "marykeycloak", "Mary", "Kelly", "mary@email.org", null, "5678"); + LDAPTestUtils.updateLDAPPassword(ldapFedProvider, mary, "Password1"); + + LDAPObject rob = LDAPTestUtils.addLDAPUser(ldapFedProvider, realm, "robkeycloak", "Rob", "Brown", "rob@email.org", null, "8910"); + LDAPTestUtils.updateLDAPPassword(ldapFedProvider, rob, "Password1"); + + LDAPObject james = LDAPTestUtils.addLDAPUser(ldapFedProvider, realm, "jameskeycloak", "James", "Brown", "james@email.org", null, "8910"); + LDAPTestUtils.updateLDAPPassword(ldapFedProvider, james, "Password1"); + }; + } +} diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/TestingResourceProvider.java b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/TestingResourceProvider.java index 874cb63b294..3ffbd761f70 100644 --- a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/TestingResourceProvider.java +++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/TestingResourceProvider.java @@ -54,34 +54,19 @@ import org.keycloak.component.ComponentModel; import org.keycloak.events.Event; import org.keycloak.events.admin.AdminEvent; import org.keycloak.http.HttpRequest; -import org.keycloak.models.AuthenticationFlowModel; -import org.keycloak.models.ClientModel; -import org.keycloak.models.FederatedIdentityModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; import org.keycloak.models.RealmProvider; -import org.keycloak.models.UserCredentialModel; -import org.keycloak.models.UserModel; -import org.keycloak.models.UserProvider; import org.keycloak.models.utils.ModelToRepresentation; import org.keycloak.representations.idm.AdminEventRepresentation; -import org.keycloak.representations.idm.AuthenticationFlowRepresentation; import org.keycloak.representations.idm.EventRepresentation; -import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.services.resource.RealmResourceProvider; -import org.keycloak.storage.UserStorageProvider; import org.keycloak.testframework.remote.providers.runonserver.FetchOnServer; import org.keycloak.testframework.remote.providers.runonserver.RunOnServer; import org.keycloak.testframework.remote.providers.runonserver.SerializationUtil; import org.keycloak.testsuite.components.amphibian.TestAmphibianProvider; import org.keycloak.testsuite.events.TestEventsListenerProvider; -import org.keycloak.testsuite.federation.DummyUserFederationProviderFactory; -import org.keycloak.testsuite.forms.PassThroughAuthenticator; -import org.keycloak.testsuite.forms.PassThroughClientAuthenticator; import org.keycloak.testsuite.model.infinispan.InfinispanTestUtil; -import org.keycloak.testsuite.rest.representation.AuthenticatorState; -import org.keycloak.testsuite.rest.resource.TestCacheResource; -import org.keycloak.testsuite.rest.resource.TestLDAPResource; import org.keycloak.testsuite.util.FeatureDeployerUtil; import org.keycloak.timer.TimerProvider; import org.keycloak.truststore.FileTruststoreProvider; @@ -175,107 +160,10 @@ public class TestingResourceProvider implements RealmResourceProvider { return Response.noContent().build(); } - @Path("/cache/{cache}") - public TestCacheResource getCacheResource(@PathParam("cache") String cacheName) { - return new TestCacheResource(session, cacheName); - } - - - @Path("/ldap/{realm}") - public TestLDAPResource ldap(@PathParam("realm") final String realmName) { - RealmModel realm = session.realms().getRealmByName(realmName); - return new TestLDAPResource(session, realm); - } - - @Override public void close() { } - @POST - @Path("/update-pass-through-auth-state") - @Produces(MediaType.APPLICATION_JSON) - public AuthenticatorState updateAuthenticator(AuthenticatorState state) { - if (state.getClientId() != null) { - PassThroughClientAuthenticator.clientId = state.getClientId(); - } - if (state.getUsername() != null) { - PassThroughAuthenticator.username = state.getUsername(); - } - - AuthenticatorState result = new AuthenticatorState(); - result.setClientId(PassThroughClientAuthenticator.clientId); - result.setUsername(PassThroughAuthenticator.username); - return result; - } - - @GET - @Path("/valid-credentials") - @Produces(MediaType.APPLICATION_JSON) - public boolean validCredentials(@QueryParam("realmName") String realmName, @QueryParam("userName") String userName, @QueryParam("password") String password) { - RealmModel realm = session.realms().getRealmByName(realmName); - if (realm == null) return false; - UserProvider userProvider = session.getProvider(UserProvider.class); - UserModel user = userProvider.getUserByUsername(realm, userName); - return user.credentialManager().isValid(UserCredentialModel.password(password)); - } - - @GET - @Path("/user-by-federated-identity") - @Produces(MediaType.APPLICATION_JSON) - public UserRepresentation getUserByFederatedIdentity(@QueryParam("realmName") String realmName, - @QueryParam("identityProvider") String identityProvider, - @QueryParam("userId") String userId, - @QueryParam("userName") String userName) { - RealmModel realm = getRealmByName(realmName); - UserModel foundFederatedUser = session.users().getUserByFederatedIdentity(realm, new FederatedIdentityModel(identityProvider, userId, userName)); - if (foundFederatedUser == null) return null; - return ModelToRepresentation.toRepresentation(session, realm, foundFederatedUser); - } - - @GET - @Path("/user-by-username-from-fed-factory") - @Produces(MediaType.APPLICATION_JSON) - public UserRepresentation getUserByUsernameFromFedProviderFactory(@QueryParam("realmName") String realmName, - @QueryParam("userName") String userName) { - RealmModel realm = getRealmByName(realmName); - DummyUserFederationProviderFactory factory = (DummyUserFederationProviderFactory) session.getKeycloakSessionFactory().getProviderFactory(UserStorageProvider.class, "dummy"); - UserModel user = factory.create(session, null).getUserByUsername(realm, userName); - if (user == null) return null; - return ModelToRepresentation.toRepresentation(session, realm, user); - } - - @GET - @Path("/get-client-auth-flow") - @Produces(MediaType.APPLICATION_JSON) - public AuthenticationFlowRepresentation getClientAuthFlow(@QueryParam("realmName") String realmName) { - RealmModel realm = getRealmByName(realmName); - AuthenticationFlowModel flow = realm.getClientAuthenticationFlow(); - if (flow == null) return null; - return ModelToRepresentation.toRepresentation(session, realm, flow); - } - - @GET - @Path("/get-reset-cred-flow") - @Produces(MediaType.APPLICATION_JSON) - public AuthenticationFlowRepresentation getResetCredFlow(@QueryParam("realmName") String realmName) { - RealmModel realm = getRealmByName(realmName); - AuthenticationFlowModel flow = realm.getResetCredentialsFlow(); - if (flow == null) return null; - return ModelToRepresentation.toRepresentation(session, realm, flow); - } - - @GET - @Path("/get-user-by-service-account-client") - @Produces(MediaType.APPLICATION_JSON) - public UserRepresentation getUserByServiceAccountClient(@QueryParam("realmName") String realmName, @QueryParam("clientId") String clientId) { - RealmModel realm = getRealmByName(realmName); - ClientModel client = realm.getClientByClientId(clientId); - UserModel user = session.users().getServiceAccount(client); - if (user == null) return null; - return ModelToRepresentation.toRepresentation(session, realm, user); - } - @GET @Path("/test-amphibian-component") @Produces(MediaType.APPLICATION_JSON) diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/representation/AuthenticatorState.java b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/representation/AuthenticatorState.java index fdc5c3a4663..c857168928c 100644 --- a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/representation/AuthenticatorState.java +++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/representation/AuthenticatorState.java @@ -17,10 +17,12 @@ package org.keycloak.testsuite.rest.representation; +import java.io.Serializable; + /** * @author Marko Strukelj */ -public class AuthenticatorState { +public class AuthenticatorState implements Serializable { private String clientId; private String username; diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/resource/TestCacheResource.java b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/resource/TestCacheResource.java deleted file mode 100644 index 7ddf2553626..00000000000 --- a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/resource/TestCacheResource.java +++ /dev/null @@ -1,107 +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.testsuite.rest.resource; - -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; -import java.util.stream.Collectors; - -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; - -import org.keycloak.connections.infinispan.InfinispanConnectionProvider; -import org.keycloak.models.KeycloakSession; -import org.keycloak.utils.MediaType; - -import org.infinispan.Cache; -import org.infinispan.stream.CacheCollectors; - -/** - * @author Marek Posolda - */ -public class TestCacheResource { - - private final Cache cache; - - public TestCacheResource(KeycloakSession session, String cacheName) { - InfinispanConnectionProvider provider = session.getProvider(InfinispanConnectionProvider.class); - cache = provider.getCache(cacheName); - } - - - @GET - @Path("/contains/{id}") - @Produces(MediaType.APPLICATION_JSON) - public boolean contains(@PathParam("id") String id) { - return cache.containsKey(id); - } - - @GET - @Path("/contains-uuid/{id}") - @Produces(MediaType.APPLICATION_JSON) - public boolean containsUuid(@PathParam("id") String id) { - UUID uuid = UUID.fromString(id); - return cache.containsKey(uuid); - } - - - @GET - @Path("/enumerate-keys") - @Produces(MediaType.APPLICATION_JSON) - public Set enumerateKeys() { - // Wrap cache.keySet into another set to avoid infinispan ClassNotFoundExceptions - Set keySet = new HashSet<>(cache.keySet()); - return keySet.stream() - .map(Object::toString) - .collect(CacheCollectors.serializableCollector(Collectors::toSet)); // See https://issues.jboss.org/browse/ISPN-7596 - } - - - @GET - @Path("/size") - @Produces(MediaType.APPLICATION_JSON) - public int size() { - return cache.size(); - } - - @GET - @Path("/clear") - @Consumes(MediaType.TEXT_PLAIN_UTF_8) - public void clear() { - cache.clear(); - } - - @POST - @Path("/remove-key/{id}") - @Produces(MediaType.APPLICATION_JSON) - public void removeKey(@PathParam("id") String id) { - cache.remove(id); - } - - @POST - @Path("/process-expiration") - @Produces(MediaType.APPLICATION_JSON) - public void processExpiration() { - cache.getAdvancedCache().getExpirationManager().processExpiration(); - } -} diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/resource/TestLDAPResource.java b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/resource/TestLDAPResource.java deleted file mode 100644 index 03ec2ad14d7..00000000000 --- a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/resource/TestLDAPResource.java +++ /dev/null @@ -1,310 +0,0 @@ -/* - * Copyright 2017 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.rest.resource; - -import java.util.Map; - -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.DELETE; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.QueryParam; - -import org.keycloak.common.util.MultivaluedHashMap; -import org.keycloak.component.ComponentModel; -import org.keycloak.models.GroupModel; -import org.keycloak.models.KeycloakSession; -import org.keycloak.models.LDAPConstants; -import org.keycloak.models.RealmModel; -import org.keycloak.models.RoleModel; -import org.keycloak.models.utils.KeycloakModelUtils; -import org.keycloak.storage.CacheableStorageProviderModel; -import org.keycloak.storage.UserStorageProvider; -import org.keycloak.storage.UserStorageProviderModel; -import org.keycloak.storage.ldap.LDAPStorageProvider; -import org.keycloak.storage.ldap.LDAPStorageProviderFactory; -import org.keycloak.storage.ldap.LDAPUtils; -import org.keycloak.storage.ldap.idm.model.LDAPObject; -import org.keycloak.storage.ldap.mappers.membership.LDAPGroupMapperMode; -import org.keycloak.storage.ldap.mappers.membership.MembershipType; -import org.keycloak.storage.ldap.mappers.membership.group.GroupLDAPStorageMapperFactory; -import org.keycloak.storage.ldap.mappers.membership.role.RoleLDAPStorageMapperFactory; -import org.keycloak.testsuite.util.LDAPTestUtils; -import org.keycloak.utils.MediaType; - -import static org.keycloak.testsuite.util.LDAPTestUtils.getGroupDescriptionLDAPAttrName; - -/** - * @author Marek Posolda - */ -public class TestLDAPResource { - - private final KeycloakSession session; - private final RealmModel realm; - - public TestLDAPResource(KeycloakSession session, RealmModel realm) { - this.session = session; - this.realm = realm; - } - - - /** - * @param ldapCfg configuration of LDAP provider - * @param importEnabled specify if LDAP provider will have import enabled - * @return ID of newly created provider - */ - @POST - @Path("/create-ldap-provider") - @Produces(MediaType.APPLICATION_JSON) - @Consumes(MediaType.APPLICATION_JSON) - public String createLDAPProvider(Map ldapCfg, @QueryParam("import") boolean importEnabled) { - MultivaluedHashMap ldapConfig = toComponentConfig(ldapCfg); - ldapConfig.putSingle(LDAPConstants.SYNC_REGISTRATIONS, "true"); - ldapConfig.putSingle(LDAPConstants.EDIT_MODE, UserStorageProvider.EditMode.WRITABLE.toString()); - UserStorageProviderModel model = new UserStorageProviderModel(); - model.setLastSync(0); - model.setChangedSyncPeriod(-1); - model.setFullSyncPeriod(-1); - model.setName("test-ldap"); - model.setPriority(0); - model.setProviderId(LDAPStorageProviderFactory.PROVIDER_NAME); - model.setConfig(ldapConfig); - - model.setImportEnabled(importEnabled); - - model.setCachePolicy(UserStorageProviderModel.CachePolicy.MAX_LIFESPAN); - model.setMaxLifespan(600000); // Lifetime is 10 minutes - - ComponentModel ldapModel = realm.addComponentModel(model); - return ldapModel.getId(); - } - - - private static MultivaluedHashMap toComponentConfig(Map ldapConfig) { - MultivaluedHashMap config = new MultivaluedHashMap<>(); - for (Map.Entry entry : ldapConfig.entrySet()) { - config.add(entry.getKey(), entry.getValue()); - - } - return config; - } - - - /** - * Prepare groups LDAP tests. Creates some LDAP mappers as well as some built-in GRoups and users in LDAP - */ - @POST - @Path("/configure-groups") - @Produces(MediaType.APPLICATION_JSON) - @Consumes(MediaType.APPLICATION_JSON) - public void prepareGroupsLDAPTest() { - LDAPTestUtils.addLocalUser(session, realm, "mary", "mary@test.com", "password-app"); - LDAPTestUtils.addLocalUser(session, realm, "john", "john@test.com", "password-app"); - - ComponentModel ldapModel = LDAPTestUtils.getLdapProviderModel(realm); - LDAPStorageProvider ldapFedProvider = LDAPTestUtils.getLdapProvider(session, ldapModel); - String descriptionAttrName = getGroupDescriptionLDAPAttrName(ldapFedProvider); - - // Add group mapper - LDAPTestUtils.addOrUpdateGroupMapper(realm, ldapModel, LDAPGroupMapperMode.LDAP_ONLY, descriptionAttrName); - - // Remove all LDAP groups - LDAPTestUtils.removeAllLDAPGroups(session, realm, ldapModel, "groupsMapper"); - - // Add some groups for testing - LDAPObject group1 = LDAPTestUtils.createLDAPGroup(session, realm, ldapModel, "group1", descriptionAttrName, "group1 - description"); - LDAPObject group11 = LDAPTestUtils.createLDAPGroup(session, realm, ldapModel, "group11"); - LDAPObject group12 = LDAPTestUtils.createLDAPGroup(session, realm, ldapModel, "group12", descriptionAttrName, "group12 - description"); - - LDAPObject defaultGroup1 = LDAPTestUtils.createLDAPGroup(session, realm, ldapModel, "defaultGroup1", descriptionAttrName, "Default Group1 - description"); - LDAPObject defaultGroup11 = LDAPTestUtils.createLDAPGroup(session, realm, ldapModel, "defaultGroup11"); - LDAPObject defaultGroup12 = LDAPTestUtils.createLDAPGroup(session, realm, ldapModel, "defaultGroup12", descriptionAttrName, "Default Group12 - description"); - LDAPTestUtils.createLDAPGroup(session, realm, ldapModel, "Team 2016/2017", descriptionAttrName, "A group with slashes in the name"); - LDAPObject teamChild20182019 = LDAPTestUtils.createLDAPGroup(session, realm, ldapModel, "Team Child 2018/2019", descriptionAttrName, "A child group with slashes in the name"); - LDAPObject teamSubChild20202021 = LDAPTestUtils.createLDAPGroup(session, realm, ldapModel, "Team SubChild 2020/2021", descriptionAttrName, "A sub child group with slashes in the name"); - LDAPObject defaultGroup13 = LDAPTestUtils.createLDAPGroup(session, realm, ldapModel, "defaultGroup13", descriptionAttrName, "Default Group13 - description"); - LDAPObject teamSubChild20222023 = LDAPTestUtils.createLDAPGroup(session, realm, ldapModel, "Team SubChild 2022/2023/A/B/C/D/E", descriptionAttrName, "A sub child group with slashes in the name"); - LDAPObject defaultGroup14 = LDAPTestUtils.createLDAPGroup(session, realm, ldapModel, "defaultGroup14", descriptionAttrName, "Default Group14 - description"); - LDAPObject teamRoot20242025 = LDAPTestUtils.createLDAPGroup(session, realm, ldapModel, "Team Root 2024/2025/A/B/C/D", descriptionAttrName, "A sub child group with slashes in the name"); - LDAPObject defaultGroup15 = LDAPTestUtils.createLDAPGroup(session, realm, ldapModel, "defaultGroup15", descriptionAttrName, "Default Group15 - description"); - LDAPObject teamSubChild20262027 = LDAPTestUtils.createLDAPGroup(session, realm, ldapModel, "Team SubChild 2026/2027", descriptionAttrName, "A sub child group with slashes in the name"); - - LDAPUtils.addMember(ldapFedProvider, MembershipType.DN, LDAPConstants.MEMBER, "not-used", group1, group11); - LDAPUtils.addMember(ldapFedProvider, MembershipType.DN, LDAPConstants.MEMBER, "not-used", group1, group12); - - LDAPUtils.addMember(ldapFedProvider, MembershipType.DN, LDAPConstants.MEMBER, "not-used", defaultGroup1, defaultGroup11); - LDAPUtils.addMember(ldapFedProvider, MembershipType.DN, LDAPConstants.MEMBER, "not-used", defaultGroup1, defaultGroup12); - LDAPUtils.addMember(ldapFedProvider, MembershipType.DN, LDAPConstants.MEMBER, "not-used", defaultGroup1, teamChild20182019); - LDAPUtils.addMember(ldapFedProvider, MembershipType.DN, LDAPConstants.MEMBER, "not-used", teamChild20182019, teamSubChild20202021); - LDAPUtils.addMember(ldapFedProvider, MembershipType.DN, LDAPConstants.MEMBER, "not-used", defaultGroup13, teamSubChild20222023); - LDAPUtils.addMember(ldapFedProvider, MembershipType.DN, LDAPConstants.MEMBER, "not-used", teamSubChild20222023, defaultGroup14); - LDAPUtils.addMember(ldapFedProvider, MembershipType.DN, LDAPConstants.MEMBER, "not-used", teamRoot20242025, defaultGroup15); - LDAPUtils.addMember(ldapFedProvider, MembershipType.DN, LDAPConstants.MEMBER, "not-used", defaultGroup15, teamSubChild20262027); - - // Sync LDAP groups to Keycloak DB - ComponentModel mapperModel = LDAPTestUtils.getSubcomponentByName(realm, ldapModel, "groupsMapper"); - new GroupLDAPStorageMapperFactory().create(session, mapperModel).syncDataFromFederationProviderToKeycloak(realm); - - realm.addDefaultGroup(KeycloakModelUtils.findGroupByPath(session, realm, "/defaultGroup1/defaultGroup11")); - realm.addDefaultGroup(KeycloakModelUtils.findGroupByPath(session, realm, "/defaultGroup1/defaultGroup12")); - - // Delete all LDAP users - LDAPTestUtils.removeAllLDAPUsers(ldapFedProvider, realm); - - // Add some LDAP users for testing - LDAPObject john = LDAPTestUtils.addLDAPUser(ldapFedProvider, realm, "johnkeycloak", "John", "Doe", "john@email.org", null, "1234"); - LDAPTestUtils.updateLDAPPassword(ldapFedProvider, john, "Password1"); - - LDAPObject mary = LDAPTestUtils.addLDAPUser(ldapFedProvider, realm, "marykeycloak", "Mary", "Kelly", "mary@email.org", null, "5678"); - LDAPTestUtils.updateLDAPPassword(ldapFedProvider, mary, "Password1"); - - LDAPObject rob = LDAPTestUtils.addLDAPUser(ldapFedProvider, realm, "robkeycloak", "Rob", "Brown", "rob@email.org", null, "8910"); - LDAPTestUtils.updateLDAPPassword(ldapFedProvider, rob, "Password1"); - - LDAPObject james = LDAPTestUtils.addLDAPUser(ldapFedProvider, realm, "jameskeycloak", "James", "Brown", "james@email.org", null, "8910"); - LDAPTestUtils.updateLDAPPassword(ldapFedProvider, james, "Password1"); - } - - /** - * Prepare roles LDAP tests. Creates some LDAP mappers as well as some built-in GRoups and users in LDAP - */ - @POST - @Path("/configure-roles") - @Produces(MediaType.APPLICATION_JSON) - @Consumes(MediaType.APPLICATION_JSON) - public void prepareRolesLDAPTest() { - ComponentModel ldapModel = LDAPTestUtils.getLdapProviderModel(realm); - LDAPStorageProvider ldapFedProvider = LDAPTestUtils.getLdapProvider(session, ldapModel); - - // Add role mapper - LDAPTestUtils.addOrUpdateRoleMapper(realm, ldapModel, LDAPGroupMapperMode.LDAP_ONLY); - - // Remove all LDAP groups and users - LDAPTestUtils.removeAllLDAPGroups(session, realm, ldapModel, "rolesMapper"); - LDAPTestUtils.removeAllLDAPUsers(ldapFedProvider, realm); - - // Add some LDAP users for testing - LDAPObject john = LDAPTestUtils.addLDAPUser(ldapFedProvider, realm, "johnkeycloak", "John", "Doe", "john@email.org", null, "1234"); - LDAPTestUtils.updateLDAPPassword(ldapFedProvider, john, "Password1"); - LDAPObject mary = LDAPTestUtils.addLDAPUser(ldapFedProvider, realm, "marykeycloak", "Mary", "Kelly", "mary@email.org", null, "5678"); - LDAPTestUtils.updateLDAPPassword(ldapFedProvider, mary, "Password1"); - LDAPObject rob = LDAPTestUtils.addLDAPUser(ldapFedProvider, realm, "robkeycloak", "Rob", "Brown", "rob@email.org", null, "8910"); - LDAPTestUtils.updateLDAPPassword(ldapFedProvider, rob, "Password1"); - LDAPObject james = LDAPTestUtils.addLDAPUser(ldapFedProvider, realm, "jameskeycloak", "James", "Brown", "james@email.org", null, "8910"); - LDAPTestUtils.updateLDAPPassword(ldapFedProvider, james, "Password1"); - - // Add some groups for testing - LDAPObject group1 = LDAPTestUtils.createLDAPGroup("rolesMapper", session, realm, ldapModel, "group1"); - LDAPObject group2 = LDAPTestUtils.createLDAPGroup("rolesMapper", session, realm, ldapModel, "group2"); - LDAPObject group3 = LDAPTestUtils.createLDAPGroup("rolesMapper", session, realm, ldapModel, "group3"); - - // add the users to the groups - LDAPUtils.addMember(ldapFedProvider, MembershipType.DN, LDAPConstants.MEMBER, "not-used", group1, john); - LDAPUtils.addMember(ldapFedProvider, MembershipType.DN, LDAPConstants.MEMBER, "not-used", group1, mary); - LDAPUtils.addMember(ldapFedProvider, MembershipType.DN, LDAPConstants.MEMBER, "not-used", group1, rob); - - LDAPUtils.addMember(ldapFedProvider, MembershipType.DN, LDAPConstants.MEMBER, "not-used", group2, john); - LDAPUtils.addMember(ldapFedProvider, MembershipType.DN, LDAPConstants.MEMBER, "not-used", group2, mary); - - // Sync LDAP groups to Keycloak DB roles - ComponentModel mapperModel = LDAPTestUtils.getSubcomponentByName(realm, ldapModel, "rolesMapper"); - new RoleLDAPStorageMapperFactory().create(session, mapperModel).syncDataFromFederationProviderToKeycloak(realm); - } - - /** - * Prepare roles LDAP tests. Creates some LDAP mappers as well as some built-in GRoups and users in LDAP - */ - @POST - @Path("/configure-hardcoded-roles") - @Produces(MediaType.APPLICATION_JSON) - @Consumes(MediaType.APPLICATION_JSON) - public void prepareHardcodedRolesLDAPTest() { - ComponentModel ldapCompModel = LDAPTestUtils.getLdapProviderModel(realm); - LDAPStorageProvider ldapFedProvider = LDAPTestUtils.getLdapProvider(session, ldapCompModel); - UserStorageProviderModel ldapModel = ldapFedProvider.getModel(); - ldapModel.setCachePolicy(CacheableStorageProviderModel.CachePolicy.NO_CACHE); - ldapModel.setImportEnabled(false); - ldapModel.getConfig().putSingle(LDAPConstants.EDIT_MODE, UserStorageProvider.EditMode.READ_ONLY.name()); - realm.updateComponent(ldapModel); - - // Add a hardcoded and composite role - RoleModel clientRole = realm.getClientByClientId("admin-cli").addRole("client_role"); - RoleModel hardcodedRole = realm.addRole("hardcoded_role"); - hardcodedRole.addCompositeRole(clientRole); - - // Add role mapper - LDAPTestUtils.addOrUpdateHardcodedRoleMapper(realm, ldapModel); - - // Remove all LDAP users - LDAPTestUtils.removeAllLDAPUsers(ldapFedProvider, realm); - - // Add some LDAP users for testing - LDAPObject john = LDAPTestUtils.addLDAPUser(ldapFedProvider, realm, "johnkeycloak", "John", "Doe", "john@email.org", null, "1234"); - LDAPTestUtils.updateLDAPPassword(ldapFedProvider, john, "Password1"); - } - - /** - * Prepare roles LDAP tests. Creates some LDAP mappers as well as some built-in GRoups and users in LDAP - */ - @POST - @Path("/configure-hardcoded-groups") - @Produces(MediaType.APPLICATION_JSON) - @Consumes(MediaType.APPLICATION_JSON) - public void prepareHardcodedGroupsLDAPTest() { - ComponentModel ldapCompModel = LDAPTestUtils.getLdapProviderModel(realm); - LDAPStorageProvider ldapFedProvider = LDAPTestUtils.getLdapProvider(session, ldapCompModel); - UserStorageProviderModel ldapModel = ldapFedProvider.getModel(); - ldapModel.setCachePolicy(CacheableStorageProviderModel.CachePolicy.NO_CACHE); - ldapModel.setImportEnabled(false); - ldapModel.getConfig().putSingle(LDAPConstants.EDIT_MODE, UserStorageProvider.EditMode.READ_ONLY.name()); - realm.updateComponent(ldapModel); - - // Add a hardcoded group hierarchy with role - RoleModel clientRole = realm.getClientByClientId("admin-cli").addRole("client_role"); - GroupModel parentGroup = realm.createGroup("parent_group"); - parentGroup.grantRole(clientRole); - GroupModel hardcodedGroup = realm.createGroup("hardcoded_group"); - parentGroup.addChild(hardcodedGroup); - - // Add group mapper - LDAPTestUtils.addOrUpdateHardcodedGroupMapper(realm, ldapModel); - - // Remove all LDAP users - LDAPTestUtils.removeAllLDAPUsers(ldapFedProvider, realm); - - // Add some LDAP users for testing - LDAPObject john = LDAPTestUtils.addLDAPUser(ldapFedProvider, realm, "johnkeycloak", "John", "Doe", "john@email.org", null, "1234"); - LDAPTestUtils.updateLDAPPassword(ldapFedProvider, john, "Password1"); - } - - /** - * Remove specified user directly just from the LDAP server - */ - @DELETE - @Path("/remove-ldap-user") - @Consumes(MediaType.APPLICATION_JSON) - public void removeLDAPUser(@QueryParam("username") String ldapUsername) { - ComponentModel ldapCompModel = LDAPTestUtils.getLdapProviderModel(realm); - UserStorageProviderModel ldapModel = new UserStorageProviderModel(ldapCompModel); - LDAPStorageProvider ldapProvider = LDAPTestUtils.getLdapProvider(session, ldapModel); - - LDAPTestUtils.removeLDAPUserByUsername(ldapProvider, realm, - ldapProvider.getLdapIdentityStore().getConfig(), ldapUsername); - } -} diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/TestClassProvider.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/TestClassProvider.java index 3f472029f09..1b8abb79bfb 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/TestClassProvider.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/TestClassProvider.java @@ -30,7 +30,9 @@ public class TestClassProvider { "/com/webauthn4j", "/com/fasterxml/jackson/dataformat/cbor", "/org/slf4j", - "/org/apache" + "/org/apache", + "/org/keycloak/util/ldap", + "/kerberos" }; private Undertow server; diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/resources/TestingCacheResource.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/resources/TestingCacheResource.java deleted file mode 100644 index e2d96949243..00000000000 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/resources/TestingCacheResource.java +++ /dev/null @@ -1,76 +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.testsuite.client.resources; - -import java.util.Set; - -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.Produces; - -import org.keycloak.utils.MediaType; - -/** - * @author Marek Posolda - */ -public interface TestingCacheResource { - - - @GET - @Path("/contains/{id}") - @Produces(MediaType.APPLICATION_JSON) - boolean contains(@PathParam("id") String id); - - @GET - @Path("/contains-uuid/{id}") - @Produces(MediaType.APPLICATION_JSON) - boolean containsUuid(@PathParam("id") String id); - - @GET - @Path("/enumerate-keys") - @Produces(MediaType.APPLICATION_JSON) - Set enumerateKeys(); - - - @GET - @Path("/size") - @Produces(MediaType.APPLICATION_JSON) - int size(); - - @GET - @Path("/clear") - @Consumes(MediaType.TEXT_PLAIN_UTF_8) - void clear(); - - @POST - @Path("/remove-key/{id}") - @Produces(MediaType.APPLICATION_JSON) - void removeKey(@PathParam("id") String id); - - /** - * Enforce calling of the expiration on the particular infinispan cache. This will immediately expire the expired cache entries, so that they won't be available in the cache. - * Without calling this, expired entries would be removed by the infinispan expiration (probably by infinispan periodic background cleaner task) - */ - @POST - @Path("/process-expiration") - @Produces(MediaType.APPLICATION_JSON) - void processExpiration(); -} diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/resources/TestingLDAPResource.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/resources/TestingLDAPResource.java deleted file mode 100644 index 27f0bed96dd..00000000000 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/resources/TestingLDAPResource.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2017 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.client.resources; - -import java.util.Map; - -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.DELETE; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.QueryParam; - -import org.keycloak.utils.MediaType; - -/** - * @author Marek Posolda - */ -public interface TestingLDAPResource { - - - /** - * @param ldapCfg configuration of LDAP provider - * @param importEnabled specify if LDAP provider will have import enabled - * @return ID of newly created provider - */ - @POST - @Path("/create-ldap-provider") - @Produces(MediaType.APPLICATION_JSON) - @Consumes(MediaType.APPLICATION_JSON) - String createLDAPProvider(Map ldapCfg, @QueryParam("import") boolean importEnabled); - - - /** - * Prepare groups LDAP tests. Creates some LDAP mappers as well as some built-in GRoups and users in LDAP - */ - @POST - @Path("/configure-groups") - @Produces(MediaType.APPLICATION_JSON) - @Consumes(MediaType.APPLICATION_JSON) - void prepareGroupsLDAPTest(); - - /** - * Prepare hardcoded groups LDAP tests. Creates some LDAP mappers as well as some built-in Groups and users in LDAP - */ - @POST - @Path("/configure-hardcoded-groups") - @Produces(MediaType.APPLICATION_JSON) - @Consumes(MediaType.APPLICATION_JSON) - void prepareHardcodedGroupsLDAPTest(); - - /** - * Prepare groups LDAP tests. Creates some LDAP mappers as well as some built-in Groups and users in LDAP - */ - @POST - @Path("/configure-roles") - @Produces(MediaType.APPLICATION_JSON) - @Consumes(MediaType.APPLICATION_JSON) - void prepareRolesLDAPTest(); - - /** - * Prepare hardcoded roles LDAP tests. Creates some LDAP mappers as well as some hardcoded roles and users in LDAP - */ - @POST - @Path("/configure-hardcoded-roles") - @Produces(MediaType.APPLICATION_JSON) - @Consumes(MediaType.APPLICATION_JSON) - void prepareHardcodedRolesLDAPTest(); - - /** - * Remove specified user directly just from the LDAP server - */ - @DELETE - @Path("/remove-ldap-user") - @Consumes(MediaType.APPLICATION_JSON) - void removeLDAPUser(@QueryParam("username") String ldapUsername); -} diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/resources/TestingResource.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/resources/TestingResource.java index ce382c67676..cbc361ee59e 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/resources/TestingResource.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/resources/TestingResource.java @@ -33,10 +33,7 @@ import jakarta.ws.rs.core.Response; import org.keycloak.common.Profile; import org.keycloak.common.enums.HostnameVerificationPolicy; import org.keycloak.representations.idm.AdminEventRepresentation; -import org.keycloak.representations.idm.AuthenticationFlowRepresentation; import org.keycloak.representations.idm.EventRepresentation; -import org.keycloak.representations.idm.UserRepresentation; -import org.keycloak.testsuite.rest.representation.AuthenticatorState; import org.keycloak.utils.MediaType; import org.infinispan.commons.time.TimeService; @@ -85,57 +82,11 @@ public interface TestingResource { @Produces(MediaType.APPLICATION_JSON) void revertTestingInfinispanTimeService(); - @Path("/cache/{cache}") - TestingCacheResource cache(@PathParam("cache") String cacheName); - - @Path("/ldap/{realm}") - TestingLDAPResource ldap(@PathParam("realm") final String realmName); - - @POST - @Path("/update-pass-through-auth-state") - @Produces(MediaType.APPLICATION_JSON) - AuthenticatorState updateAuthenticator(AuthenticatorState state); - - @GET - @Path("/valid-credentials") - @Produces(MediaType.APPLICATION_JSON) - public boolean validCredentials(@QueryParam("realmName") String realmName, @QueryParam("userName") String userName, @QueryParam("password") String password); - - @GET - @Path("/user-by-federated-identity") - @Produces(MediaType.APPLICATION_JSON) - public UserRepresentation getUserByFederatedIdentity(@QueryParam("realmName") String realmName, - @QueryParam("identityProvider") String identityProvider, - @QueryParam("userId") String userId, - @QueryParam("userName") String userName); - - @GET - @Path("/user-by-username-from-fed-factory") - @Produces(MediaType.APPLICATION_JSON) - public UserRepresentation getUserByUsernameFromFedProviderFactory(@QueryParam("realmName") String realmName, - @QueryParam("userName") String userName); - - @GET - @Path("/get-client-auth-flow") - @Produces(MediaType.APPLICATION_JSON) - public AuthenticationFlowRepresentation getClientAuthFlow(@QueryParam("realmName") String realmName); - - @GET - @Path("/get-reset-cred-flow") - @Produces(MediaType.APPLICATION_JSON) - public AuthenticationFlowRepresentation getResetCredFlow(@QueryParam("realmName") String realmName); - - @GET - @Path("/get-user-by-service-account-client") - @Produces(MediaType.APPLICATION_JSON) - public UserRepresentation getUserByServiceAccountClient(@QueryParam("realmName") String realmName, @QueryParam("clientId") String clientId); - @GET @Path("/test-amphibian-component") @Produces(MediaType.APPLICATION_JSON) Map> getTestAmphibianComponentDetails(); - @PUT @Path("/set-krb5-conf-file") @Consumes(MediaType.APPLICATION_JSON) diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOIDCBrokerWithSignatureTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOIDCBrokerWithSignatureTest.java index d4cadd18d57..538ac199013 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOIDCBrokerWithSignatureTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOIDCBrokerWithSignatureTest.java @@ -45,11 +45,12 @@ import org.keycloak.representations.idm.IdentityProviderRepresentation; import org.keycloak.representations.idm.KeysMetadataRepresentation; import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.testsuite.broker.util.SimpleHttpDefault; -import org.keycloak.testsuite.client.resources.TestingCacheResource; +import org.keycloak.testsuite.client.KeycloakTestingClient; import org.keycloak.testsuite.updaters.ClientAttributeUpdater; import org.keycloak.testsuite.util.AccountHelper; import org.keycloak.testsuite.util.broker.OIDCIdentityProviderConfigRep; import org.keycloak.testsuite.util.oauth.OAuthClient; +import org.keycloak.testsuite.util.runonserver.CacheHelper; import org.junit.Before; import org.junit.Test; @@ -416,7 +417,7 @@ public class KcOIDCBrokerWithSignatureTest extends AbstractBaseBrokerTest { @Test - public void testClearKeysCache() throws Exception { + public void testClearKeysCache() { // Configure OIDC identity provider with JWKS URL updateIdentityProviderWithJwksUrl(); @@ -429,13 +430,13 @@ public class KcOIDCBrokerWithSignatureTest extends AbstractBaseBrokerTest { // Check that key is cached IdentityProviderRepresentation idpRep = getIdentityProvider(); String expectedCacheKey = PublicKeyStorageUtils.getIdpModelCacheKey(consumerRealm().toRepresentation().getId(), idpRep.getInternalId()); - TestingCacheResource cache = testingClient.testing(bc.consumerRealmName()).cache(InfinispanConnectionProvider.KEYS_CACHE_NAME); - Assertions.assertTrue(cache.contains(expectedCacheKey)); + KeycloakTestingClient.Server runOnServerConsumer = testingClient.server(bc.consumerRealmName()); + Assertions.assertTrue(runOnServerConsumer.fetch(CacheHelper.contains(InfinispanConnectionProvider.KEYS_CACHE_NAME, expectedCacheKey))); // Clear cache and check nothing cached consumerRealm().clearKeysCache(); - Assertions.assertFalse(cache.contains(expectedCacheKey)); - Assertions.assertEquals(cache.size(), 0); + Assertions.assertFalse(runOnServerConsumer.fetch(CacheHelper.contains(InfinispanConnectionProvider.KEYS_CACHE_NAME, expectedCacheKey))); + Assertions.assertEquals(0, runOnServerConsumer.fetch(CacheHelper.size(InfinispanConnectionProvider.KEYS_CACHE_NAME))); } @@ -454,8 +455,8 @@ public class KcOIDCBrokerWithSignatureTest extends AbstractBaseBrokerTest { // Check that key is cached IdentityProviderRepresentation idpRep = getIdentityProvider(); String expectedCacheKey = PublicKeyStorageUtils.getIdpModelCacheKey(consumerRealm().toRepresentation().getId(), idpRep.getInternalId()); - TestingCacheResource cache = testingClient.testing(bc.consumerRealmName()).cache(InfinispanConnectionProvider.KEYS_CACHE_NAME); - Assertions.assertTrue(cache.contains(expectedCacheKey)); + KeycloakTestingClient.Server runOnServerConsumer = testingClient.server(bc.consumerRealmName()); + Assertions.assertTrue(runOnServerConsumer.fetch(CacheHelper.contains(InfinispanConnectionProvider.KEYS_CACHE_NAME, expectedCacheKey))); // Update identityProvider to some bad JWKS_URL OIDCIdentityProviderConfigRep cfg = new OIDCIdentityProviderConfigRep(idpRep); @@ -463,7 +464,7 @@ public class KcOIDCBrokerWithSignatureTest extends AbstractBaseBrokerTest { updateIdentityProvider(idpRep); // Check that key is not cached anymore - Assertions.assertFalse(cache.contains(expectedCacheKey)); + Assertions.assertFalse(runOnServerConsumer.fetch(CacheHelper.contains(InfinispanConnectionProvider.KEYS_CACHE_NAME, expectedCacheKey))); // Check that user is not able to login with IDP timeOffSet.set(20); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/OIDCJwksClientRegistrationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/OIDCJwksClientRegistrationTest.java index 77a03f1ac2c..1950720f9c4 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/OIDCJwksClientRegistrationTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/OIDCJwksClientRegistrationTest.java @@ -51,6 +51,7 @@ import org.keycloak.testsuite.client.resources.TestOIDCEndpointsApplicationResou import org.keycloak.testsuite.rest.resource.TestingOIDCEndpointsApplicationResource; import org.keycloak.testsuite.util.oauth.AccessTokenResponse; import org.keycloak.testsuite.util.oauth.OAuthClient; +import org.keycloak.testsuite.util.runonserver.CacheHelper; import org.apache.http.NameValuePair; import org.apache.http.client.entity.UrlEncodedFormEntity; @@ -200,7 +201,7 @@ public class OIDCJwksClientRegistrationTest extends AbstractClientRegistrationTe // Assert item in publicKey cache for client1 String expectedCacheKey = PublicKeyStorageUtils.getClientModelCacheKey( adminClient.realm(REALM_NAME).toRepresentation().getId(), response.getClientId()); - Assertions.assertTrue(testingClient.testing().cache(InfinispanConnectionProvider.KEYS_CACHE_NAME).contains(expectedCacheKey)); + Assertions.assertTrue(runOnServerMaster.fetch(CacheHelper.contains(InfinispanConnectionProvider.KEYS_CACHE_NAME, expectedCacheKey))); // Assert it's not possible to authenticate as client2 with the same "kid" like client1 assertAuthenticateClientError(generatedKeys, clientRep2, "a1"); @@ -219,7 +220,7 @@ public class OIDCJwksClientRegistrationTest extends AbstractClientRegistrationTe // Assert item in publicKey cache for client1 String expectedCacheKey = PublicKeyStorageUtils.getClientModelCacheKey( adminClient.realm(REALM_NAME).toRepresentation().getId(), response.getClientId()); - Assertions.assertTrue(testingClient.testing().cache(InfinispanConnectionProvider.KEYS_CACHE_NAME).contains(expectedCacheKey)); + Assertions.assertTrue(runOnServerMaster.fetch(CacheHelper.contains(InfinispanConnectionProvider.KEYS_CACHE_NAME, expectedCacheKey))); @@ -230,7 +231,7 @@ public class OIDCJwksClientRegistrationTest extends AbstractClientRegistrationTe .oidc().update(response); // Assert item not any longer for client1 - Assertions.assertFalse(testingClient.testing().cache(InfinispanConnectionProvider.KEYS_CACHE_NAME).contains(expectedCacheKey)); + Assertions.assertFalse(runOnServerMaster.fetch(CacheHelper.contains(InfinispanConnectionProvider.KEYS_CACHE_NAME, expectedCacheKey))); // Assert it's not possible to authenticate as client1 assertAuthenticateClientError(generatedKeys, response, "a1"); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/exportimport/ExportImportTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/exportimport/ExportImportTest.java index 212339aee3d..0646ae0bb78 100755 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/exportimport/ExportImportTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/exportimport/ExportImportTest.java @@ -40,7 +40,10 @@ import org.keycloak.exportimport.dir.DirExportProvider; import org.keycloak.exportimport.dir.DirExportProviderFactory; import org.keycloak.exportimport.singlefile.SingleFileExportProviderFactory; import org.keycloak.exportimport.util.ImportUtils; +import org.keycloak.models.RealmModel; +import org.keycloak.models.UserCredentialModel; import org.keycloak.models.UserModel; +import org.keycloak.models.UserProvider; import org.keycloak.representations.idm.AuthenticationExecutionInfoRepresentation; import org.keycloak.representations.idm.ComponentRepresentation; import org.keycloak.representations.idm.IdentityProviderRepresentation; @@ -52,10 +55,13 @@ import org.keycloak.representations.idm.RoleRepresentation; import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.representations.userprofile.config.UPConfig; import org.keycloak.testframework.realm.UserBuilder; +import org.keycloak.testframework.remote.providers.runonserver.FetchOnServer; +import org.keycloak.testframework.remote.providers.runonserver.FetchOnServerWrapper; import org.keycloak.testsuite.AbstractKeycloakTest; import org.keycloak.testsuite.Assert; import org.keycloak.testsuite.arquillian.annotation.EnableFeature; import org.keycloak.testsuite.arquillian.annotation.UncaughtServerErrorExpected; +import org.keycloak.testsuite.client.KeycloakTestingClient; import org.keycloak.testsuite.util.JsonTestUtils; import org.keycloak.testsuite.util.runonserver.ExportImportHelper; import org.keycloak.testsuite.util.runonserver.RunHelpers; @@ -67,6 +73,7 @@ import org.apache.commons.io.FileUtils; import org.hamcrest.Matchers; import org.jboss.arquillian.container.spi.client.container.LifecycleException; import org.junit.After; +import org.junit.Before; import org.junit.Test; import org.junit.jupiter.api.Assertions; @@ -90,6 +97,12 @@ import static org.junit.jupiter.api.Assertions.assertTrue; public class ExportImportTest extends AbstractKeycloakTest { private static final String TEST_REALM = "test-realm"; + private KeycloakTestingClient.Server runOnServerTestRealm; + + @Before + public void setup() { + runOnServerTestRealm = testingClient.server("test-realm"); + } @Override public void addTestRealms(List testRealms) { @@ -186,7 +199,7 @@ public class ExportImportTest extends AbstractKeycloakTest { testFullExportImport(); RealmResource testRealmRealm = adminClient.realm(TEST_REALM); - ExportImportUtil.assertDataImportedInRealm(adminClient, testingClient, testRealmRealm.toRepresentation()); + ExportImportUtil.assertDataImportedInRealm(adminClient, runOnServerTestRealm, testRealmRealm.toRepresentation()); // There should be 6 files in target directory (3 realm, 3 user) assertEquals(6, new File(targetDirPath).listFiles().length); @@ -203,7 +216,7 @@ public class ExportImportTest extends AbstractKeycloakTest { testRealmExportImport(); RealmResource testRealmRealm = adminClient.realm(TEST_REALM); - ExportImportUtil.assertDataImportedInRealm(adminClient, testingClient, testRealmRealm.toRepresentation()); + ExportImportUtil.assertDataImportedInRealm(adminClient, runOnServerTestRealm, testRealmRealm.toRepresentation()); // There should be 5 files in target directory (1 realm, 16 users, 5 users per file) // (+ additional user service-account-test-app-authz that should not be there ???) @@ -260,7 +273,7 @@ public class ExportImportTest extends AbstractKeycloakTest { RealmResource testRealmRealm = adminClient.realm(TEST_REALM); - ExportImportUtil.assertDataImportedInRealm(adminClient, testingClient, testRealmRealm.toRepresentation()); + ExportImportUtil.assertDataImportedInRealm(adminClient, runOnServerTestRealm, testRealmRealm.toRepresentation()); } @Test @@ -495,12 +508,12 @@ public class ExportImportTest extends AbstractKeycloakTest { requiredActionsBeforeImport.put(action.getAlias(), action); }); - assertNotAuthenticated("test", "test-user@localhost", "password"); - assertNotAuthenticated("test", "user1", "password"); - assertNotAuthenticated("test", "user2", "password"); - assertNotAuthenticated("test", "user3", "password"); - assertNotAuthenticated("test", "user-requiredOTP", "password"); - assertNotAuthenticated("test", "user-requiredWebAuthn", "password"); + assertNotAuthenticated("test-user@localhost", "password"); + assertNotAuthenticated("user1", "password"); + assertNotAuthenticated("user2", "password"); + assertNotAuthenticated("user3", "password"); + assertNotAuthenticated("user-requiredOTP", "password"); + assertNotAuthenticated("user-requiredWebAuthn", "password"); // Configure import @@ -511,12 +524,12 @@ public class ExportImportTest extends AbstractKeycloakTest { // Ensure data are imported back Assert.assertNames(adminClient.realms().findAll(), "master", "test", TEST_REALM); - assertAuthenticated("test", "test-user@localhost", "password"); - assertAuthenticated("test", "user1", "password"); - assertAuthenticated("test", "user2", "password"); - assertAuthenticated("test", "user3", "password"); - assertAuthenticated("test", "user-requiredOTP", "password"); - assertAuthenticated("test", "user-requiredWebAuthn", "password"); + assertAuthenticated("test-user@localhost", "password"); + assertAuthenticated("user1", "password"); + assertAuthenticated("user2", "password"); + assertAuthenticated("user3", "password"); + assertAuthenticated("user-requiredOTP", "password"); + assertAuthenticated("user-requiredWebAuthn", "password"); RealmResource testRealmRealm = adminClient.realm("test"); assertTrue(testRealmRealm.users().search("user-requiredOTP").get(0) @@ -525,7 +538,7 @@ public class ExportImportTest extends AbstractKeycloakTest { .getRequiredActions().get(0).equals(WebAuthnRegisterFactory.PROVIDER_ID)); // KEYCLOAK-6050 Check SMTP password is exported/imported - assertEquals("secret", testingClient.server("test").fetch(RunHelpers.internalRealm()).getSmtpServer().get("password")); + assertEquals("secret", runOnServer.fetch(RunHelpers.internalRealm()).getSmtpServer().get("password")); // KEYCLOAK-8176 Check required actions are exported/imported properly List requiredActionsAfterImport = adminClient.realm("master").flows().getRequiredActions(); @@ -560,12 +573,12 @@ public class ExportImportTest extends AbstractKeycloakTest { Assert.assertNames(adminClient.realms().findAll(), TEST_REALM, "master"); - assertNotAuthenticated("test", "test-user@localhost", "password"); - assertNotAuthenticated("test", "user1", "password"); - assertNotAuthenticated("test", "user2", "password"); - assertNotAuthenticated("test", "user3", "password"); - assertNotAuthenticated("test", "user-requiredOTP", "password"); - assertNotAuthenticated("test", "user-requiredWebAuthn", "password"); + assertNotAuthenticated("test-user@localhost", "password"); + assertNotAuthenticated("user1", "password"); + assertNotAuthenticated("user2", "password"); + assertNotAuthenticated("user3", "password"); + assertNotAuthenticated("user-requiredOTP", "password"); + assertNotAuthenticated("user-requiredWebAuthn", "password"); // Configure import runOnServerMaster.run(ExportImportHelper.setAction(ExportImportConfig.ACTION_IMPORT)); @@ -575,12 +588,12 @@ public class ExportImportTest extends AbstractKeycloakTest { // Ensure data are imported back, but just for "test" realm Assert.assertNames(adminClient.realms().findAll(), "master", "test", TEST_REALM); - assertAuthenticated("test", "test-user@localhost", "password"); - assertAuthenticated("test", "user1", "password"); - assertAuthenticated("test", "user2", "password"); - assertAuthenticated("test", "user3", "password"); - assertAuthenticated("test", "user-requiredOTP", "password"); - assertAuthenticated("test", "user-requiredWebAuthn", "password"); + assertAuthenticated("test-user@localhost", "password"); + assertAuthenticated("user1", "password"); + assertAuthenticated("user2", "password"); + assertAuthenticated("user3", "password"); + assertAuthenticated("user-requiredOTP", "password"); + assertAuthenticated("user-requiredWebAuthn", "password"); RealmResource testRealmRealm = adminClient.realm("test"); assertTrue(testRealmRealm.users().search("user-requiredOTP").get(0) @@ -613,16 +626,16 @@ public class ExportImportTest extends AbstractKeycloakTest { checkEventsConfig(adminClient.realm("test").getRealmEventsConfig()); } - private void assertAuthenticated(String realmName, String username, String password) { - assertAuth(true, realmName, username, password); + private void assertAuthenticated(String username, String password) { + assertAuth(true, username, password); } - private void assertNotAuthenticated(String realmName, String username, String password) { - assertAuth(false, realmName, username, password); + private void assertNotAuthenticated(String username, String password) { + assertAuth(false, username, password); } - private void assertAuth(boolean expectedResult, String realmName, String username, String password) { - assertEquals(expectedResult, testingClient.testing().validCredentials(realmName, username, password)); + private void assertAuth(boolean expectedResult, String username, String password) { + assertEquals(expectedResult, runOnServerMaster.fetch(validCredentials(username, password))); } private void assertComponents(List expected, List actual) { @@ -696,4 +709,27 @@ public class ExportImportTest extends AbstractKeycloakTest { runOnServerMaster.run(ExportImportHelper.runImport()); } + + private static FetchOnServerWrapper validCredentials(String userName, String password) { + return new FetchOnServerWrapper<>() { + + @Override + public FetchOnServer getRunOnServer() { + return session -> { + RealmModel realm = session.realms().getRealmByName("test"); + if (realm == null) { + return false; + } + UserProvider userProvider = session.getProvider(UserProvider.class); + UserModel user = userProvider.getUserByUsername(realm, userName); + return user.credentialManager().isValid(UserCredentialModel.password(password)); + }; + } + + @Override + public Class getResultClass() { + return Boolean.class; + } + }; + } } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/exportimport/ExportImportUtil.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/exportimport/ExportImportUtil.java index 6f455192715..dc71f3d8ec5 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/exportimport/ExportImportUtil.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/exportimport/ExportImportUtil.java @@ -40,11 +40,17 @@ import org.keycloak.admin.client.resource.UserResource; import org.keycloak.common.Profile; import org.keycloak.common.constants.KerberosConstants; import org.keycloak.common.constants.ServiceAccountConstants; +import org.keycloak.models.AuthenticationFlowModel; +import org.keycloak.models.ClientModel; import org.keycloak.models.Constants; +import org.keycloak.models.FederatedIdentityModel; import org.keycloak.models.LDAPConstants; +import org.keycloak.models.RealmModel; +import org.keycloak.models.UserModel; import org.keycloak.models.credential.PasswordCredentialModel; import org.keycloak.models.credential.dto.PasswordCredentialData; import org.keycloak.models.utils.DefaultAuthenticationFlows; +import org.keycloak.models.utils.ModelToRepresentation; import org.keycloak.protocol.oidc.OIDCConfigAttributes; import org.keycloak.protocol.oidc.OIDCLoginProtocol; import org.keycloak.protocol.oidc.OIDCLoginProtocolFactory; @@ -73,9 +79,12 @@ import org.keycloak.storage.UserStorageProvider; import org.keycloak.storage.ldap.mappers.FullNameLDAPStorageMapper; import org.keycloak.storage.ldap.mappers.FullNameLDAPStorageMapperFactory; import org.keycloak.storage.ldap.mappers.LDAPStorageMapper; +import org.keycloak.testframework.remote.providers.runonserver.FetchOnServer; +import org.keycloak.testframework.remote.providers.runonserver.FetchOnServerWrapper; import org.keycloak.testsuite.ProfileAssume; import org.keycloak.testsuite.admin.AdminApiUtil; import org.keycloak.testsuite.client.KeycloakTestingClient; +import org.keycloak.testsuite.federation.DummyUserFederationProviderFactory; import org.keycloak.util.JsonSerialization; import org.hamcrest.Matcher; @@ -93,7 +102,7 @@ public class ExportImportUtil { // In the old testsuite, this method exists as a public method of ImportTest from the model package. // However, model package is not ready to be migrated yet. - public static void assertDataImportedInRealm(Keycloak adminClient, KeycloakTestingClient testingClient, RealmRepresentation realm) throws IOException { + public static void assertDataImportedInRealm(Keycloak adminClient, KeycloakTestingClient.Server runOnServer, RealmRepresentation realm) throws IOException { Assertions.assertTrue(realm.isVerifyEmail()); Assertions.assertEquals((Integer)3600000, realm.getOfflineSessionIdleTimeout()); Assertions.assertEquals((Integer)1500, realm.getAccessTokenLifespanForImplicitFlow()); @@ -272,9 +281,9 @@ public class ExportImportUtil { Assertions.assertEquals(1, socialLowercaseLinks.size()); Assertions.assertEquals("lowercasesocialuser@gmail.com", socialLowercaseLinks.get(0).getUserName()); - UserRepresentation foundSocialUser = testingClient.testing(realm.getRealm()).getUserByFederatedIdentity(realm.getRealm(), "facebook1", "facebook1", "fbuser1"); + UserRepresentation foundSocialUser = runOnServer.fetch(getUserByFederatedIdentity("facebook1", "facebook1", "fbuser1")); Assertions.assertEquals(foundSocialUser.getUsername(), socialUser.toRepresentation().getUsername()); - Assertions.assertNull(testingClient.testing(realm.getRealm()).getUserByFederatedIdentity(realm.getRealm(), "facebook", "not-existing", "not-existing")); + Assertions.assertNull(runOnServer.fetch(getUserByFederatedIdentity("facebook", "not-existing", "not-existing"))); Assertions.assertEquals("facebook1", facebookIdentityRep.getUserId()); Assertions.assertEquals("fbuser1", facebookIdentityRep.getUserName()); @@ -337,15 +346,15 @@ public class ExportImportUtil { ///////////////// // Assert that federation link wasn't created during import - Assertions.assertNull(testingClient.testing(realm.getRealm()).getUserByUsernameFromFedProviderFactory(realm.getRealm(), "wburke")); + Assertions.assertNull(runOnServer.fetch(getUserByUsernameFromFedProviderFactory("wburke"))); // Test builtin authentication flows - AuthenticationFlowRepresentation clientFlow = testingClient.testing(realm.getRealm()).getClientAuthFlow(realm.getRealm()); + AuthenticationFlowRepresentation clientFlow = runOnServer.fetch(getClientAuthFlow()); Assertions.assertEquals(DefaultAuthenticationFlows.CLIENT_AUTHENTICATION_FLOW, clientFlow.getAlias()); Assertions.assertNotNull(realmRsc.flows().getFlow(clientFlow.getId())); Assertions.assertTrue(realmRsc.flows().getExecutions(clientFlow.getAlias()).size() > 0); - AuthenticationFlowRepresentation resetFlow = testingClient.testing(realm.getRealm()).getResetCredFlow(realm.getRealm()); + AuthenticationFlowRepresentation resetFlow = runOnServer.fetch(getResetCredFlow()); Assertions.assertEquals(DefaultAuthenticationFlows.RESET_CREDENTIALS_FLOW, resetFlow.getAlias()); Assertions.assertNotNull(realmRsc.flows().getFlow(resetFlow.getId())); Assertions.assertTrue(realmRsc.flows().getExecutions(resetFlow.getAlias()).size() > 0); @@ -424,11 +433,11 @@ public class ExportImportUtil { if (ProfileAssume.isFeatureEnabled(Profile.Feature.AUTHORIZATION)) { Assertions.assertTrue(testAppAuthzApp.isServiceAccountsEnabled()); - Assertions.assertNull(testingClient.testing(realm.getRealm()).getUserByServiceAccountClient(realm.getRealm(), application.getClientId()));//session.users().getUserByServiceAccountClient(application)); - UserRepresentation otherAppSA = testingClient.testing(realm.getRealm()).getUserByServiceAccountClient(realm.getRealm(), otherApp.getClientId());//session.users().getUserByServiceAccountClient(otherApp); + Assertions.assertNull(runOnServer.fetch(getUserByServiceAccountClient(application.getClientId())));//session.users().getUserByServiceAccountClient(application)); + UserRepresentation otherAppSA = runOnServer.fetch(getUserByServiceAccountClient(otherApp.getClientId()));//session.users().getUserByServiceAccountClient(otherApp); Assertions.assertNotNull(otherAppSA); Assertions.assertEquals("service-account-otherapp", otherAppSA.getUsername()); - UserRepresentation testAppAuthzSA = testingClient.testing(realm.getRealm()).getUserByServiceAccountClient(realm.getRealm(), testAppAuthzApp.getClientId()); + UserRepresentation testAppAuthzSA = runOnServer.fetch(getUserByServiceAccountClient(testAppAuthzApp.getClientId())); Assertions.assertNotNull(testAppAuthzSA); Assertions.assertEquals("service-account-test-app-authz", testAppAuthzSA.getUsername()); @@ -782,4 +791,109 @@ public class ExportImportUtil { } } } + + private static FetchOnServerWrapper getUserByServiceAccountClient(String clientId) { + return new FetchOnServerWrapper<>() { + + @Override + public FetchOnServer getRunOnServer() { + return session -> { + RealmModel realm = session.getContext().getRealm(); + ClientModel client = realm.getClientByClientId(clientId); + UserModel user = session.users().getServiceAccount(client); + if (user == null) return null; + return ModelToRepresentation.toRepresentation(session, realm, user); + }; + } + + @Override + public Class getResultClass() { + return UserRepresentation.class; + } + }; + } + + private static FetchOnServerWrapper getResetCredFlow() { + return new FetchOnServerWrapper<>() { + + @Override + public FetchOnServer getRunOnServer() { + return session -> { + RealmModel realm = session.getContext().getRealm(); + AuthenticationFlowModel flow = realm.getResetCredentialsFlow(); + if (flow == null) return null; + return ModelToRepresentation.toRepresentation(session, realm, flow); + }; + } + + @Override + public Class getResultClass() { + return AuthenticationFlowRepresentation.class; + } + }; + } + + private static FetchOnServerWrapper getClientAuthFlow() { + return new FetchOnServerWrapper<>() { + + @Override + public FetchOnServer getRunOnServer() { + return session -> { + RealmModel realm = session.getContext().getRealm(); + AuthenticationFlowModel flow = realm.getClientAuthenticationFlow(); + if (flow == null) return null; + return ModelToRepresentation.toRepresentation(session, realm, flow); + }; + } + + @Override + public Class getResultClass() { + return AuthenticationFlowRepresentation.class; + } + }; + } + + private static FetchOnServerWrapper getUserByUsernameFromFedProviderFactory(String userName) { + return new FetchOnServerWrapper<>() { + + @Override + public FetchOnServer getRunOnServer() { + return session -> { + RealmModel realm = session.getContext().getRealm(); + DummyUserFederationProviderFactory factory = (DummyUserFederationProviderFactory) session.getKeycloakSessionFactory().getProviderFactory(UserStorageProvider.class, "dummy"); + UserModel user = factory.create(session, null).getUserByUsername(realm, userName); + if (user == null) return null; + return ModelToRepresentation.toRepresentation(session, realm, user); + }; + } + + @Override + public Class getResultClass() { + return UserRepresentation.class; + } + }; + } + + private static FetchOnServerWrapper getUserByFederatedIdentity(String identityProvider, + String userId, + String userName) { + return new FetchOnServerWrapper<>() { + + @Override + public FetchOnServer getRunOnServer() { + return session -> { + RealmModel realm = session.getContext().getRealm(); + UserModel foundFederatedUser = session.users().getUserByFederatedIdentity(realm, new FederatedIdentityModel(identityProvider, userId, userName)); + if (foundFederatedUser == null) return null; + return ModelToRepresentation.toRepresentation(session, realm, foundFederatedUser); + }; + } + + @Override + public Class getResultClass() { + return UserRepresentation.class; + } + }; + } + } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/kerberos/KerberosLdapCrossRealmTrustTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/kerberos/KerberosLdapCrossRealmTrustTest.java index 9b7bc667920..fd4c16990e1 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/kerberos/KerberosLdapCrossRealmTrustTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/kerberos/KerberosLdapCrossRealmTrustTest.java @@ -20,13 +20,19 @@ package org.keycloak.testsuite.federation.kerberos; import jakarta.ws.rs.core.Response; import org.keycloak.common.constants.KerberosConstants; +import org.keycloak.component.ComponentModel; import org.keycloak.federation.kerberos.CommonKerberosConfig; +import org.keycloak.models.RealmModel; import org.keycloak.representations.AccessToken; import org.keycloak.representations.idm.ComponentRepresentation; +import org.keycloak.storage.UserStorageProviderModel; +import org.keycloak.storage.ldap.LDAPStorageProvider; import org.keycloak.storage.ldap.LDAPStorageProviderFactory; import org.keycloak.storage.ldap.kerberos.LDAPProviderKerberosConfig; +import org.keycloak.testframework.remote.providers.runonserver.RunOnServer; import org.keycloak.testsuite.KerberosEmbeddedServer; import org.keycloak.testsuite.util.KerberosRule; +import org.keycloak.testsuite.util.LDAPTestUtils; import org.keycloak.testsuite.util.TestAppHelper; import org.keycloak.testsuite.util.oauth.AccessTokenResponse; @@ -155,7 +161,7 @@ public class KerberosLdapCrossRealmTrustTest extends AbstractKerberosTest { public void test05DisableTrust() throws Exception { // Remove the LDAP entry corresponding to the Kerberos principal krbtgt/KEYCLOAK.ORG@KC2.COM // This will effectively disable kerberos cross-realm trust - testingClient.testing().ldap("test").removeLDAPUser("krbtgt2"); + runOnServer.run(removeLDAPUser("krbtgt2")); // There is no trust among kerberos realms anymore. SPNEGO shouldn't work. There would be failure even on Apache HTTP client side @@ -169,4 +175,19 @@ public class KerberosLdapCrossRealmTrustTest extends AbstractKerberosTest { } + /** + * Remove specified user directly just from the LDAP server + */ + public static RunOnServer removeLDAPUser(String ldapUsername) { + return session -> { + RealmModel realm = session.getContext().getRealm(); + ComponentModel ldapCompModel = LDAPTestUtils.getLdapProviderModel(realm); + UserStorageProviderModel ldapModel = new UserStorageProviderModel(ldapCompModel); + LDAPStorageProvider ldapProvider = LDAPTestUtils.getLdapProvider(session, ldapModel); + + LDAPTestUtils.removeLDAPUserByUsername(ldapProvider, realm, + ldapProvider.getLdapIdentityStore().getConfig(), ldapUsername); + }; + } + } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/AbstractLDAPTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/AbstractLDAPTest.java index 1d5d08202d1..fcc575d3f35 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/AbstractLDAPTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/AbstractLDAPTest.java @@ -30,6 +30,7 @@ import org.keycloak.testsuite.pages.LoginPasswordUpdatePage; import org.keycloak.testsuite.pages.OAuthGrantPage; import org.keycloak.testsuite.pages.RegisterPage; import org.keycloak.testsuite.util.LDAPRule; +import org.keycloak.testsuite.util.runonserver.LdapHelper; import org.jboss.arquillian.graphene.page.Page; import org.junit.Rule; @@ -79,7 +80,7 @@ public abstract class AbstractLDAPTest extends AbstractTestRealmKeycloakTest { protected void createLDAPProvider() { Map cfg = getLDAPRule().getConfig(); - ldapModelId = testingClient.testing().ldap(TEST_REALM_NAME).createLDAPProvider(cfg, isImportEnabled()); + ldapModelId = runOnServer.fetchString(LdapHelper.createLDAPProvider(cfg, isImportEnabled())).replace("\"", ""); Assertions.assertEquals(22, ldapModelId.length(), "Short ID not used for ldap id"); log.infof("LDAP Provider created"); } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/LDAPGroupMapperTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/LDAPGroupMapperTest.java index fa5bde19f17..294ac33b86a 100755 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/LDAPGroupMapperTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/LDAPGroupMapperTest.java @@ -46,6 +46,7 @@ import org.keycloak.storage.ldap.mappers.membership.group.GroupLDAPStorageMapper import org.keycloak.storage.ldap.mappers.membership.group.GroupMapperConfig; import org.keycloak.testsuite.util.LDAPRule; import org.keycloak.testsuite.util.LDAPTestUtils; +import org.keycloak.testsuite.util.runonserver.LdapHelper; import org.junit.ClassRule; import org.junit.FixMethodOrder; @@ -77,7 +78,7 @@ public class LDAPGroupMapperTest extends AbstractLDAPTest { @Override protected void afterImportTestRealm() { - testingClient.testing().ldap(TEST_REALM_NAME).prepareGroupsLDAPTest(); + runOnServer.run(LdapHelper.prepareGroupsLDAPTest()); } @Override diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/LDAPHardcodedGroupMapperTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/LDAPHardcodedGroupMapperTest.java index 749a4a9a235..8674de4c50a 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/LDAPHardcodedGroupMapperTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/LDAPHardcodedGroupMapperTest.java @@ -18,11 +18,20 @@ package org.keycloak.testsuite.federation.ldap; import java.io.Serializable; +import org.keycloak.component.ComponentModel; import org.keycloak.models.GroupModel; +import org.keycloak.models.LDAPConstants; import org.keycloak.models.RealmModel; import org.keycloak.models.RoleModel; import org.keycloak.models.UserModel; +import org.keycloak.storage.CacheableStorageProviderModel; +import org.keycloak.storage.UserStorageProvider; +import org.keycloak.storage.UserStorageProviderModel; +import org.keycloak.storage.ldap.LDAPStorageProvider; +import org.keycloak.storage.ldap.idm.model.LDAPObject; +import org.keycloak.testframework.remote.providers.runonserver.RunOnServer; import org.keycloak.testsuite.util.LDAPRule; +import org.keycloak.testsuite.util.LDAPTestUtils; import org.junit.ClassRule; import org.junit.Test; @@ -47,7 +56,7 @@ public class LDAPHardcodedGroupMapperTest extends AbstractLDAPTest implements Se @Override protected void afterImportTestRealm() { - testingClient.testing().ldap(TEST_REALM_NAME).prepareHardcodedGroupsLDAPTest(); + runOnServer.run(prepareHardcodedGroupsLDAPTest()); } /** @@ -86,4 +95,37 @@ public class LDAPHardcodedGroupMapperTest extends AbstractLDAPTest implements Se }); } + /** + * Prepare hardcoded groups LDAP tests. Creates some LDAP mappers as well as some built-in Groups and users in LDAP + */ + public static RunOnServer prepareHardcodedGroupsLDAPTest() { + return session -> { + RealmModel realm = session.getContext().getRealm(); + ComponentModel ldapCompModel = LDAPTestUtils.getLdapProviderModel(realm); + LDAPStorageProvider ldapFedProvider = LDAPTestUtils.getLdapProvider(session, ldapCompModel); + UserStorageProviderModel ldapModel = ldapFedProvider.getModel(); + ldapModel.setCachePolicy(CacheableStorageProviderModel.CachePolicy.NO_CACHE); + ldapModel.setImportEnabled(false); + ldapModel.getConfig().putSingle(LDAPConstants.EDIT_MODE, UserStorageProvider.EditMode.READ_ONLY.name()); + realm.updateComponent(ldapModel); + + // Add a hardcoded group hierarchy with role + RoleModel clientRole = realm.getClientByClientId("admin-cli").addRole("client_role"); + GroupModel parentGroup = realm.createGroup("parent_group"); + parentGroup.grantRole(clientRole); + GroupModel hardcodedGroup = realm.createGroup("hardcoded_group"); + parentGroup.addChild(hardcodedGroup); + + // Add group mapper + LDAPTestUtils.addOrUpdateHardcodedGroupMapper(realm, ldapModel); + + // Remove all LDAP users + LDAPTestUtils.removeAllLDAPUsers(ldapFedProvider, realm); + + // Add some LDAP users for testing + LDAPObject john = LDAPTestUtils.addLDAPUser(ldapFedProvider, realm, "johnkeycloak", "John", "Doe", "john@email.org", null, "1234"); + LDAPTestUtils.updateLDAPPassword(ldapFedProvider, john, "Password1"); + }; + } + } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/LDAPHardcodedRoleMapperTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/LDAPHardcodedRoleMapperTest.java index 830486eae79..fc03d0e37d7 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/LDAPHardcodedRoleMapperTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/LDAPHardcodedRoleMapperTest.java @@ -18,10 +18,19 @@ package org.keycloak.testsuite.federation.ldap; import java.util.stream.Collectors; +import org.keycloak.component.ComponentModel; +import org.keycloak.models.LDAPConstants; import org.keycloak.models.RealmModel; import org.keycloak.models.RoleModel; import org.keycloak.models.UserModel; +import org.keycloak.storage.CacheableStorageProviderModel; +import org.keycloak.storage.UserStorageProvider; +import org.keycloak.storage.UserStorageProviderModel; +import org.keycloak.storage.ldap.LDAPStorageProvider; +import org.keycloak.storage.ldap.idm.model.LDAPObject; +import org.keycloak.testframework.remote.providers.runonserver.RunOnServer; import org.keycloak.testsuite.util.LDAPRule; +import org.keycloak.testsuite.util.LDAPTestUtils; import org.junit.ClassRule; import org.junit.Test; @@ -46,7 +55,7 @@ public class LDAPHardcodedRoleMapperTest extends AbstractLDAPTest { @Override protected void afterImportTestRealm() { - testingClient.testing().ldap(TEST_REALM_NAME).prepareHardcodedRolesLDAPTest(); + runOnServer.run(prepareHardcodedRolesLDAPTest()); } /** @@ -77,4 +86,34 @@ public class LDAPHardcodedRoleMapperTest extends AbstractLDAPTest { }); } + /** + * Prepare hardcoded roles LDAP tests. Creates some LDAP mappers as well as some hardcoded roles and users in LDAP + */ + public static RunOnServer prepareHardcodedRolesLDAPTest() { + return session -> { + RealmModel realm = session.getContext().getRealm(); + ComponentModel ldapCompModel = LDAPTestUtils.getLdapProviderModel(realm); + LDAPStorageProvider ldapFedProvider = LDAPTestUtils.getLdapProvider(session, ldapCompModel); + UserStorageProviderModel ldapModel = ldapFedProvider.getModel(); + ldapModel.setCachePolicy(CacheableStorageProviderModel.CachePolicy.NO_CACHE); + ldapModel.setImportEnabled(false); + ldapModel.getConfig().putSingle(LDAPConstants.EDIT_MODE, UserStorageProvider.EditMode.READ_ONLY.name()); + realm.updateComponent(ldapModel); + + // Add a hardcoded and composite role + RoleModel clientRole = realm.getClientByClientId("admin-cli").addRole("client_role"); + RoleModel hardcodedRole = realm.addRole("hardcoded_role"); + hardcodedRole.addCompositeRole(clientRole); + + // Add role mapper + LDAPTestUtils.addOrUpdateHardcodedRoleMapper(realm, ldapModel); + + // Remove all LDAP users + LDAPTestUtils.removeAllLDAPUsers(ldapFedProvider, realm); + + // Add some LDAP users for testing + LDAPObject john = LDAPTestUtils.addLDAPUser(ldapFedProvider, realm, "johnkeycloak", "John", "Doe", "john@email.org", null, "1234"); + LDAPTestUtils.updateLDAPPassword(ldapFedProvider, john, "Password1"); + }; + } } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/LDAPProvidersIntegrationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/LDAPProvidersIntegrationTest.java index e5e598aeb36..79fbdd31d18 100755 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/LDAPProvidersIntegrationTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/LDAPProvidersIntegrationTest.java @@ -80,6 +80,7 @@ import org.keycloak.testsuite.util.AccountHelper; import org.keycloak.testsuite.util.LDAPRule; import org.keycloak.testsuite.util.LDAPTestUtils; import org.keycloak.testsuite.util.oauth.AccessTokenResponse; +import org.keycloak.testsuite.util.runonserver.LdapHelper; import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; @@ -525,7 +526,7 @@ public class LDAPProvidersIntegrationTest extends AbstractLDAPTest { // Re-add LDAP provider Map cfg = getLDAPRule().getConfig(); - ldapModelId = testingClient.testing().ldap(TEST_REALM_NAME).createLDAPProvider(cfg, isImportEnabled()); + ldapModelId = runOnServer.fetchString(LdapHelper.createLDAPProvider(cfg, isImportEnabled())).replace("\"", ""); testingClient.server().run(session -> { LDAPTestContext ctx = LDAPTestContext.init(session); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/LDAPRoleMapperTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/LDAPRoleMapperTest.java index 61648c170b8..23bc66e3e33 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/LDAPRoleMapperTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/LDAPRoleMapperTest.java @@ -20,11 +20,18 @@ import java.util.stream.Collectors; import org.keycloak.component.ComponentModel; import org.keycloak.models.ClientModel; +import org.keycloak.models.LDAPConstants; import org.keycloak.models.RealmModel; import org.keycloak.models.RoleModel; import org.keycloak.models.UserModel; +import org.keycloak.storage.ldap.LDAPStorageProvider; +import org.keycloak.storage.ldap.LDAPUtils; +import org.keycloak.storage.ldap.idm.model.LDAPObject; +import org.keycloak.storage.ldap.mappers.membership.LDAPGroupMapperMode; +import org.keycloak.storage.ldap.mappers.membership.MembershipType; import org.keycloak.storage.ldap.mappers.membership.role.RoleLDAPStorageMapperFactory; import org.keycloak.storage.ldap.mappers.membership.role.RoleMapperConfig; +import org.keycloak.testframework.remote.providers.runonserver.RunOnServer; import org.keycloak.testsuite.util.LDAPRule; import org.keycloak.testsuite.util.LDAPTestUtils; @@ -55,7 +62,7 @@ public class LDAPRoleMapperTest extends AbstractLDAPTest { @Override protected void afterImportTestRealm() { - testingClient.testing().ldap(TEST_REALM_NAME).prepareRolesLDAPTest(); + runOnServer.run(prepareRolesLDAPTest()); } @Test @@ -192,4 +199,49 @@ public class LDAPRoleMapperTest extends AbstractLDAPTest { } }); } + + /** + * Prepare groups LDAP tests. Creates some LDAP mappers as well as some built-in Groups and users in LDAP + */ + public static RunOnServer prepareRolesLDAPTest() { + return session -> { + RealmModel realm = session.getContext().getRealm(); + ComponentModel ldapModel = LDAPTestUtils.getLdapProviderModel(realm); + LDAPStorageProvider ldapFedProvider = LDAPTestUtils.getLdapProvider(session, ldapModel); + + // Add role mapper + LDAPTestUtils.addOrUpdateRoleMapper(realm, ldapModel, LDAPGroupMapperMode.LDAP_ONLY); + + // Remove all LDAP groups and users + LDAPTestUtils.removeAllLDAPGroups(session, realm, ldapModel, "rolesMapper"); + LDAPTestUtils.removeAllLDAPUsers(ldapFedProvider, realm); + + // Add some LDAP users for testing + LDAPObject john = LDAPTestUtils.addLDAPUser(ldapFedProvider, realm, "johnkeycloak", "John", "Doe", "john@email.org", null, "1234"); + LDAPTestUtils.updateLDAPPassword(ldapFedProvider, john, "Password1"); + LDAPObject mary = LDAPTestUtils.addLDAPUser(ldapFedProvider, realm, "marykeycloak", "Mary", "Kelly", "mary@email.org", null, "5678"); + LDAPTestUtils.updateLDAPPassword(ldapFedProvider, mary, "Password1"); + LDAPObject rob = LDAPTestUtils.addLDAPUser(ldapFedProvider, realm, "robkeycloak", "Rob", "Brown", "rob@email.org", null, "8910"); + LDAPTestUtils.updateLDAPPassword(ldapFedProvider, rob, "Password1"); + LDAPObject james = LDAPTestUtils.addLDAPUser(ldapFedProvider, realm, "jameskeycloak", "James", "Brown", "james@email.org", null, "8910"); + LDAPTestUtils.updateLDAPPassword(ldapFedProvider, james, "Password1"); + + // Add some groups for testing + LDAPObject group1 = LDAPTestUtils.createLDAPGroup("rolesMapper", session, realm, ldapModel, "group1"); + LDAPObject group2 = LDAPTestUtils.createLDAPGroup("rolesMapper", session, realm, ldapModel, "group2"); + LDAPObject group3 = LDAPTestUtils.createLDAPGroup("rolesMapper", session, realm, ldapModel, "group3"); + + // add the users to the groups + LDAPUtils.addMember(ldapFedProvider, MembershipType.DN, LDAPConstants.MEMBER, "not-used", group1, john); + LDAPUtils.addMember(ldapFedProvider, MembershipType.DN, LDAPConstants.MEMBER, "not-used", group1, mary); + LDAPUtils.addMember(ldapFedProvider, MembershipType.DN, LDAPConstants.MEMBER, "not-used", group1, rob); + + LDAPUtils.addMember(ldapFedProvider, MembershipType.DN, LDAPConstants.MEMBER, "not-used", group2, john); + LDAPUtils.addMember(ldapFedProvider, MembershipType.DN, LDAPConstants.MEMBER, "not-used", group2, mary); + + // Sync LDAP groups to Keycloak DB roles + ComponentModel mapperModel = LDAPTestUtils.getSubcomponentByName(realm, ldapModel, "rolesMapper"); + new RoleLDAPStorageMapperFactory().create(session, mapperModel).syncDataFromFederationProviderToKeycloak(realm); + }; + } } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/LDAPSpecialCharsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/LDAPSpecialCharsTest.java index 08689019f4a..1955fc25a8b 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/LDAPSpecialCharsTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/LDAPSpecialCharsTest.java @@ -37,6 +37,7 @@ import org.keycloak.testsuite.pages.AppPage; import org.keycloak.testsuite.util.LDAPRule; import org.keycloak.testsuite.util.LDAPTestConfiguration; import org.keycloak.testsuite.util.LDAPTestUtils; +import org.keycloak.testsuite.util.runonserver.LdapHelper; import org.junit.ClassRule; import org.junit.FixMethodOrder; @@ -74,7 +75,7 @@ public class LDAPSpecialCharsTest extends AbstractLDAPTest { @Override protected void afterImportTestRealm() { - testingClient.testing().ldap(TEST_REALM_NAME).prepareGroupsLDAPTest(); + runOnServer.run(LdapHelper.prepareGroupsLDAPTest()); testingClient.server().run(session -> { LDAPTestContext ctx = LDAPTestContext.init(session); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/UserFederationLdapConnectionTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/UserFederationLdapConnectionTest.java index 333c2a3ee58..eaf5f7016c2 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/UserFederationLdapConnectionTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/UserFederationLdapConnectionTest.java @@ -31,9 +31,12 @@ import org.keycloak.services.managers.LDAPServerCapabilitiesManager; import org.keycloak.storage.ldap.idm.store.ldap.extended.PasswordModifyRequest; import org.keycloak.testsuite.AbstractAdminTest; import org.keycloak.testsuite.arquillian.annotation.EnableVault; +import org.keycloak.testsuite.client.KeycloakTestingClient; import org.keycloak.testsuite.util.LDAPRule; +import org.keycloak.testsuite.util.runonserver.LdapHelper; import org.hamcrest.Matchers; +import org.junit.Before; import org.junit.ClassRule; import org.junit.Test; import org.junit.jupiter.api.Assertions; @@ -49,6 +52,13 @@ public class UserFederationLdapConnectionTest extends AbstractAdminTest { @ClassRule public static LDAPRule ldapRule = new LDAPRule(); + KeycloakTestingClient.Server runOnServerAdminClientTest; + + @Before + public void setup() { + runOnServerAdminClientTest = testingClient.server(REALM_NAME); + } + @Test public void testLdapConnections() { // Unknown action @@ -64,7 +74,7 @@ public class UserFederationLdapConnectionTest extends AbstractAdminTest { assertStatus(response, 204); // Connection success with invalid credentials - String ldapModelId = testingClient.testing().ldap(REALM_NAME).createLDAPProvider(ldapRule.getConfig(), false); + String ldapModelId = runOnServerAdminClientTest.fetchString(LdapHelper.createLDAPProvider(ldapRule.getConfig(), false)).replace("\"", ""); getCleanup().addCleanup(() -> { adminClient.realm(REALM_NAME).components().removeComponent(ldapModelId);; }); @@ -162,7 +172,7 @@ public class UserFederationLdapConnectionTest extends AbstractAdminTest { Map cfg = ldapRule.getConfig(); cfg.put(LDAPConstants.CONNECTION_URL, "ldap://invalid:10389 ldap://localhost:10389"); cfg.put(LDAPConstants.CONNECTION_TIMEOUT, "1000"); - String ldapModelId = testingClient.testing().ldap(REALM_NAME).createLDAPProvider(cfg, false); + String ldapModelId = runOnServerAdminClientTest.fetchString(LdapHelper.createLDAPProvider(cfg, false)).replace("\"", ""); // Only 2nd server works with stored LDAP federation provider response = realm.testLDAPConnection(new TestLdapConnectionRepresentation(LDAPServerCapabilitiesManager.TEST_AUTHENTICATION, @@ -179,7 +189,7 @@ public class UserFederationLdapConnectionTest extends AbstractAdminTest { cfg.put(LDAPConstants.CONNECTION_URL, "ldaps://localhost:10636"); cfg.put(LDAPConstants.START_TLS, "false"); cfg.put(LDAPConstants.USE_TRUSTSTORE_SPI, "true"); - String ldapModelId = testingClient.testing().ldap(REALM_NAME).createLDAPProvider(cfg, false); + String ldapModelId = runOnServerAdminClientTest.fetchString(LdapHelper.createLDAPProvider(cfg, false)).replace("\"", ""); try { // test passing everything with password included Response response = realm.testLDAPConnection(new TestLdapConnectionRepresentation(LDAPServerCapabilitiesManager.TEST_AUTHENTICATION, diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/CustomFlowTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/CustomFlowTest.java index 2c6da624986..2e4db6b2b16 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/CustomFlowTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/CustomFlowTest.java @@ -45,6 +45,7 @@ import org.keycloak.testframework.realm.AuthenticationExecutionBuilder; import org.keycloak.testframework.realm.AuthenticationFlowBuilder; import org.keycloak.testframework.realm.ClientBuilder; import org.keycloak.testframework.realm.UserBuilder; +import org.keycloak.testframework.remote.providers.runonserver.RunOnServer; import org.keycloak.testsuite.AssertEvents; import org.keycloak.testsuite.admin.ApiUtil; import org.keycloak.testsuite.pages.AppPage; @@ -306,7 +307,7 @@ public class CustomFlowTest extends AbstractFlowTest { AuthenticatorState state = new AuthenticatorState(); state.setUsername("login-test"); state.setClientId("test-app"); - testingClient.testing().updateAuthenticator(state); + runOnServerMaster.run(updateAuthenticator(state)); oauth.openLoginForm(); @@ -321,7 +322,7 @@ public class CustomFlowTest extends AbstractFlowTest { AuthenticatorState state = new AuthenticatorState(); state.setUsername("login-test"); state.setClientId("test-app"); - testingClient.testing().updateAuthenticator(state); + runOnServerMaster.run(updateAuthenticator(state)); grantAccessToken("test-app", "login-test"); } @@ -331,15 +332,15 @@ public class CustomFlowTest extends AbstractFlowTest { AuthenticatorState state = new AuthenticatorState(); state.setClientId("dummy-client"); state.setUsername("login-test"); - testingClient.testing().updateAuthenticator(state); + runOnServerMaster.run(updateAuthenticator(state)); grantAccessToken("dummy-client", "login-test"); state.setClientId("test-app"); - testingClient.testing().updateAuthenticator(state); + runOnServerMaster.run(updateAuthenticator(state)); grantAccessToken("test-app", "login-test"); state.setClientId("unknown"); - testingClient.testing().updateAuthenticator(state); + runOnServerMaster.run(updateAuthenticator(state)); AccessTokenResponse response = oauth.doPasswordGrantRequest("test-user", "password"); assertEquals(401, response.getStatusCode()); @@ -356,7 +357,7 @@ public class CustomFlowTest extends AbstractFlowTest { .error(Errors.CLIENT_NOT_FOUND); state.setClientId("test-app"); - testingClient.testing().updateAuthenticator(state); + runOnServerMaster.run(updateAuthenticator(state)); // Test throwing exception from the client authenticator. No error details should be displayed response = oauth.passwordGrantRequest("test-user", "password").param(PassThroughClientAuthenticator.TEST_ERROR_PARAM, "Some Random Error").send(); @@ -408,5 +409,15 @@ public class CustomFlowTest extends AbstractFlowTest { .details(Details.CLIENT_AUTH_METHOD, PassThroughClientAuthenticator.PROVIDER_ID); } + public static RunOnServer updateAuthenticator(AuthenticatorState state) { + return session -> { + if (state.getClientId() != null) { + PassThroughClientAuthenticator.clientId = state.getClientId(); + } + if (state.getUsername() != null) { + PassThroughAuthenticator.username = state.getUsername(); + } + }; + } } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ResourceOwnerPasswordCredentialsGrantTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ResourceOwnerPasswordCredentialsGrantTest.java index 922ee49fe34..74457c40642 100755 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ResourceOwnerPasswordCredentialsGrantTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ResourceOwnerPasswordCredentialsGrantTest.java @@ -68,6 +68,7 @@ import org.keycloak.testsuite.util.TokenSignatureUtil; import org.keycloak.testsuite.util.UserManager; import org.keycloak.testsuite.util.oauth.AccessTokenResponse; import org.keycloak.testsuite.util.oauth.LogoutResponse; +import org.keycloak.testsuite.util.runonserver.CacheHelper; import org.keycloak.util.TokenUtil; import org.apache.http.NameValuePair; @@ -821,6 +822,6 @@ public class ResourceOwnerPasswordCredentialsGrantTest extends AbstractKeycloakT } private int getAuthenticationSessionsCount() { - return testingClient.testing().cache(InfinispanConnectionProvider.AUTHENTICATION_SESSIONS_CACHE_NAME).size(); + return runOnServerMaster.fetch(CacheHelper.size(InfinispanConnectionProvider.AUTHENTICATION_SESSIONS_CACHE_NAME)); } } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/organization/member/OrganizationMemberWithLdapTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/organization/member/OrganizationMemberWithLdapTest.java index fe2553a1f5e..5587d0ef9c6 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/organization/member/OrganizationMemberWithLdapTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/organization/member/OrganizationMemberWithLdapTest.java @@ -38,6 +38,7 @@ import org.keycloak.testsuite.federation.ldap.LDAPTestContext; import org.keycloak.testsuite.organization.admin.AbstractOrganizationTest; import org.keycloak.testsuite.util.LDAPRule; import org.keycloak.testsuite.util.LDAPTestUtils; +import org.keycloak.testsuite.util.runonserver.LdapHelper; import org.junit.ClassRule; import org.junit.Test; @@ -61,8 +62,8 @@ public class OrganizationMemberWithLdapTest extends AbstractOrganizationTest { // add an LDAP provider with a group mapper Map cfg = ldapRule.getConfig(); - testingClient.testing().ldap(TEST_REALM_NAME).createLDAPProvider(cfg, true); - testingClient.testing().ldap(TEST_REALM_NAME).prepareGroupsLDAPTest(); + runOnServer.fetchString(LdapHelper.createLDAPProvider(cfg, true)); + runOnServer.run(LdapHelper.prepareGroupsLDAPTest()); } @Test