KEYCLOAK-3159 Migrate federation package from old testsuite
This commit is contained in:
parent
f295a2e303
commit
89d0c51e13
26 changed files with 1149 additions and 1658 deletions
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
* Copyright 2017 Red Hat, Inc. and/or its affiliates
|
||||||
* and other contributors as indicated by the @author tags.
|
* and other contributors as indicated by the @author tags.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@ -14,7 +14,7 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.keycloak.testsuite.federation.storage;
|
package org.keycloak.testsuite.federation;
|
||||||
|
|
||||||
import org.keycloak.common.util.MultivaluedHashMap;
|
import org.keycloak.common.util.MultivaluedHashMap;
|
||||||
import org.keycloak.component.ComponentModel;
|
import org.keycloak.component.ComponentModel;
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
* Copyright 2017 Red Hat, Inc. and/or its affiliates
|
||||||
* and other contributors as indicated by the @author tags.
|
* and other contributors as indicated by the @author tags.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@ -14,7 +14,7 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.keycloak.testsuite.federation.storage;
|
package org.keycloak.testsuite.federation;
|
||||||
|
|
||||||
import org.keycloak.component.ComponentModel;
|
import org.keycloak.component.ComponentModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
|
@ -16,13 +16,16 @@
|
||||||
*/
|
*/
|
||||||
package org.keycloak.testsuite.federation;
|
package org.keycloak.testsuite.federation;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import org.keycloak.Config;
|
import org.keycloak.Config;
|
||||||
import org.keycloak.component.ComponentModel;
|
import org.keycloak.component.ComponentModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.KeycloakSessionFactory;
|
import org.keycloak.models.KeycloakSessionFactory;
|
||||||
|
import org.keycloak.provider.ProviderConfigProperty;
|
||||||
import org.keycloak.storage.UserStorageProviderFactory;
|
import org.keycloak.storage.UserStorageProviderFactory;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -34,8 +37,22 @@ public class UserMapStorageFactory implements UserStorageProviderFactory<UserMap
|
||||||
|
|
||||||
public static final String PROVIDER_ID = "user-password-map-arq";
|
public static final String PROVIDER_ID = "user-password-map-arq";
|
||||||
|
|
||||||
|
protected static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
ProviderConfigProperty attr = new ProviderConfigProperty("attr", "attr",
|
||||||
|
"This is some attribute",
|
||||||
|
ProviderConfigProperty.STRING_TYPE, null);
|
||||||
|
configProperties.add(attr);
|
||||||
|
}
|
||||||
|
|
||||||
protected Map<String, String> userPasswords = new HashMap<>();
|
protected Map<String, String> userPasswords = new HashMap<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ProviderConfigProperty> getConfigProperties() {
|
||||||
|
return configProperties;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UserMapStorage create(KeycloakSession session, ComponentModel model) {
|
public UserMapStorage create(KeycloakSession session, ComponentModel model) {
|
||||||
return new UserMapStorage(session, model, userPasswords);
|
return new UserMapStorage(session, model, userPasswords);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
* Copyright 2017 Red Hat, Inc. and/or its affiliates
|
||||||
* and other contributors as indicated by the @author tags.
|
* and other contributors as indicated by the @author tags.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@ -41,10 +41,10 @@ import java.util.concurrent.TimeUnit;
|
||||||
public class SyncDummyUserFederationProviderFactory extends DummyUserFederationProviderFactory {
|
public class SyncDummyUserFederationProviderFactory extends DummyUserFederationProviderFactory {
|
||||||
|
|
||||||
// Used during SyncFederationTest
|
// Used during SyncFederationTest
|
||||||
static volatile CountDownLatch latch1 = new CountDownLatch(1);
|
public static volatile CountDownLatch latch1 = new CountDownLatch(1);
|
||||||
static volatile CountDownLatch latch2 = new CountDownLatch(1);
|
public static volatile CountDownLatch latch2 = new CountDownLatch(1);
|
||||||
|
|
||||||
static void restartLatches() {
|
public static void restartLatches() {
|
||||||
latch1 = new CountDownLatch(1);
|
latch1 = new CountDownLatch(1);
|
||||||
latch2 = new CountDownLatch(1);
|
latch2 = new CountDownLatch(1);
|
||||||
}
|
}
|
|
@ -1,4 +1,6 @@
|
||||||
org.keycloak.testsuite.federation.DummyUserFederationProviderFactory
|
org.keycloak.testsuite.federation.DummyUserFederationProviderFactory
|
||||||
|
org.keycloak.testsuite.federation.FailableHardcodedStorageProviderFactory
|
||||||
org.keycloak.testsuite.federation.UserMapStorageFactory
|
org.keycloak.testsuite.federation.UserMapStorageFactory
|
||||||
org.keycloak.testsuite.federation.UserPropertyFileStorageFactory
|
org.keycloak.testsuite.federation.UserPropertyFileStorageFactory
|
||||||
org.keycloak.testsuite.federation.PassThroughFederatedUserStorageProviderFactory
|
org.keycloak.testsuite.federation.PassThroughFederatedUserStorageProviderFactory
|
||||||
|
org.keycloak.testsuite.federation.sync.SyncDummyUserFederationProviderFactory
|
||||||
|
|
|
@ -171,7 +171,7 @@ public final class TestContext {
|
||||||
public TestCleanup getOrCreateCleanup(String realmName) {
|
public TestCleanup getOrCreateCleanup(String realmName) {
|
||||||
TestCleanup cleanup = cleanups.get(realmName);
|
TestCleanup cleanup = cleanups.get(realmName);
|
||||||
if (cleanup == null) {
|
if (cleanup == null) {
|
||||||
cleanup = new TestCleanup(adminClient, realmName);
|
cleanup = new TestCleanup(this, realmName);
|
||||||
TestCleanup existing = cleanups.putIfAbsent(realmName, cleanup);
|
TestCleanup existing = cleanups.putIfAbsent(realmName, cleanup);
|
||||||
|
|
||||||
if (existing != null) {
|
if (existing != null) {
|
||||||
|
|
|
@ -24,6 +24,7 @@ import javax.ws.rs.NotFoundException;
|
||||||
import org.keycloak.admin.client.Keycloak;
|
import org.keycloak.admin.client.Keycloak;
|
||||||
import org.keycloak.admin.client.resource.RealmResource;
|
import org.keycloak.admin.client.resource.RealmResource;
|
||||||
import org.keycloak.common.util.ConcurrentMultivaluedHashMap;
|
import org.keycloak.common.util.ConcurrentMultivaluedHashMap;
|
||||||
|
import org.keycloak.testsuite.arquillian.TestContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enlist resources to be cleaned after test method
|
* Enlist resources to be cleaned after test method
|
||||||
|
@ -42,15 +43,15 @@ public class TestCleanup {
|
||||||
private static final String AUTH_FLOW_IDS = "AUTH_FLOW_IDS";
|
private static final String AUTH_FLOW_IDS = "AUTH_FLOW_IDS";
|
||||||
private static final String AUTH_CONFIG_IDS = "AUTH_CONFIG_IDS";
|
private static final String AUTH_CONFIG_IDS = "AUTH_CONFIG_IDS";
|
||||||
|
|
||||||
private final Keycloak adminClient;
|
private final TestContext testContext;
|
||||||
private final String realmName;
|
private final String realmName;
|
||||||
|
|
||||||
// Key is kind of entity (eg. "client", "role", "user" etc), Values are all kind of entities of given type to cleanup
|
// Key is kind of entity (eg. "client", "role", "user" etc), Values are all kind of entities of given type to cleanup
|
||||||
private ConcurrentMultivaluedHashMap<String, String> entities = new ConcurrentMultivaluedHashMap<>();
|
private ConcurrentMultivaluedHashMap<String, String> entities = new ConcurrentMultivaluedHashMap<>();
|
||||||
|
|
||||||
|
|
||||||
public TestCleanup(Keycloak adminClient, String realmName) {
|
public TestCleanup(TestContext testContext, String realmName) {
|
||||||
this.adminClient = adminClient;
|
this.testContext = testContext;
|
||||||
this.realmName = realmName;
|
this.realmName = realmName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,7 +102,7 @@ public class TestCleanup {
|
||||||
|
|
||||||
|
|
||||||
public void executeCleanup() {
|
public void executeCleanup() {
|
||||||
RealmResource realm = adminClient.realm(realmName);
|
RealmResource realm = getAdminClient().realm(realmName);
|
||||||
|
|
||||||
List<String> userIds = entities.get(USER_IDS);
|
List<String> userIds = entities.get(USER_IDS);
|
||||||
if (userIds != null) {
|
if (userIds != null) {
|
||||||
|
@ -204,4 +205,8 @@ public class TestCleanup {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Keycloak getAdminClient() {
|
||||||
|
return testContext.getAdminClient();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,130 @@
|
||||||
|
/*
|
||||||
|
* 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.federation.storage;
|
||||||
|
|
||||||
|
import org.jboss.arquillian.container.test.api.ContainerController;
|
||||||
|
import org.jboss.arquillian.container.test.api.Deployment;
|
||||||
|
import org.jboss.arquillian.graphene.page.Page;
|
||||||
|
import org.jboss.arquillian.test.api.ArquillianResource;
|
||||||
|
import org.jboss.shrinkwrap.api.spec.WebArchive;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.keycloak.OAuth2Constants;
|
||||||
|
import org.keycloak.admin.client.resource.RealmResource;
|
||||||
|
import org.keycloak.component.ComponentModel;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.models.jpa.RealmAdapter;
|
||||||
|
import org.keycloak.representations.idm.ComponentRepresentation;
|
||||||
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
|
import org.keycloak.storage.UserStorageProvider;
|
||||||
|
import org.keycloak.storage.UserStorageProviderModel;
|
||||||
|
import org.keycloak.testsuite.AbstractAuthTest;
|
||||||
|
import org.keycloak.testsuite.AbstractTestRealmKeycloakTest;
|
||||||
|
import org.keycloak.testsuite.pages.AppPage;
|
||||||
|
import org.keycloak.testsuite.pages.LoginPage;
|
||||||
|
import org.keycloak.testsuite.runonserver.RunOnServerDeployment;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* KEYCLOAK-3903 and KEYCLOAK-3620
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
public class BrokenUserStorageTest extends AbstractTestRealmKeycloakTest {
|
||||||
|
|
||||||
|
@Deployment
|
||||||
|
public static WebArchive deploy() {
|
||||||
|
return RunOnServerDeployment.create(ComponentExportImportTest.class, AbstractAuthTest.class, RealmResource.class)
|
||||||
|
.addPackages(true, "org.keycloak.testsuite");
|
||||||
|
}
|
||||||
|
|
||||||
|
@ArquillianResource
|
||||||
|
protected ContainerController controller;
|
||||||
|
|
||||||
|
@Page
|
||||||
|
protected LoginPage loginPage;
|
||||||
|
|
||||||
|
@Page
|
||||||
|
protected AppPage appPage;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configureTestRealm(RealmRepresentation testRealm) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void loginSuccessAndLogout(String username, String password) {
|
||||||
|
loginPage.open();
|
||||||
|
loginPage.login(username, password);
|
||||||
|
Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||||
|
Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
|
||||||
|
oauth.openLogout();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBootWithBadProviderId() throws Exception {
|
||||||
|
testingClient.server().run(session -> {
|
||||||
|
// set this system property
|
||||||
|
System.setProperty(RealmAdapter.COMPONENT_PROVIDER_EXISTS_DISABLED, "true");
|
||||||
|
|
||||||
|
RealmModel realm = session.realms().getRealmByName("master");
|
||||||
|
|
||||||
|
UserStorageProviderModel model = new UserStorageProviderModel();
|
||||||
|
model.setName("bad-provider-id");
|
||||||
|
model.setPriority(2);
|
||||||
|
model.setParentId(realm.getId());
|
||||||
|
model.setProviderId("error");
|
||||||
|
ComponentModel component = realm.importComponentModel(model);
|
||||||
|
});
|
||||||
|
|
||||||
|
controller.stop(suiteContext.getAuthServerInfo().getQualifier());
|
||||||
|
controller.start(suiteContext.getAuthServerInfo().getQualifier());
|
||||||
|
reconnectAdminClient();
|
||||||
|
|
||||||
|
loginSuccessAndLogout("test-user@localhost", "password");
|
||||||
|
|
||||||
|
// make sure we can list components and delete provider as this is an admin console operation
|
||||||
|
|
||||||
|
RealmResource master = adminClient.realms().realm("master");
|
||||||
|
String masterId = master.toRepresentation().getId();
|
||||||
|
List<ComponentRepresentation> components = master.components().query(masterId, UserStorageProvider.class.getName());
|
||||||
|
|
||||||
|
ComponentRepresentation found = null;
|
||||||
|
for (ComponentRepresentation rep : components) {
|
||||||
|
if (rep.getName().equals("bad-provider-id")) {
|
||||||
|
found = rep;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Assert.assertNotNull(found);
|
||||||
|
|
||||||
|
master.components().component(found.getId()).remove();
|
||||||
|
|
||||||
|
List<ComponentRepresentation> components2 = master.components().query(masterId, UserStorageProvider.class.getName());
|
||||||
|
Assert.assertEquals(components.size() - 1, components2.size());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void resetSystemProperty() {
|
||||||
|
testingClient.server().run(session -> {
|
||||||
|
System.getProperties().remove(RealmAdapter.COMPONENT_PROVIDER_EXISTS_DISABLED);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -18,19 +18,26 @@ import org.keycloak.common.util.MultivaluedHashMap;
|
||||||
import org.keycloak.exportimport.ExportImportConfig;
|
import org.keycloak.exportimport.ExportImportConfig;
|
||||||
import org.keycloak.exportimport.ExportImportManager;
|
import org.keycloak.exportimport.ExportImportManager;
|
||||||
import org.keycloak.exportimport.singlefile.SingleFileExportProviderFactory;
|
import org.keycloak.exportimport.singlefile.SingleFileExportProviderFactory;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.representations.idm.ComponentRepresentation;
|
import org.keycloak.representations.idm.ComponentRepresentation;
|
||||||
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
import org.keycloak.storage.UserStorageProvider;
|
import org.keycloak.storage.UserStorageProvider;
|
||||||
import org.keycloak.testsuite.AbstractAuthTest;
|
import org.keycloak.testsuite.AbstractAuthTest;
|
||||||
import org.keycloak.testsuite.admin.ApiUtil;
|
import org.keycloak.testsuite.admin.ApiUtil;
|
||||||
import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
|
import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
|
||||||
|
|
||||||
|
import org.keycloak.testsuite.client.KeycloakTestingClient;
|
||||||
import org.keycloak.testsuite.federation.UserMapStorageFactory;
|
import org.keycloak.testsuite.federation.UserMapStorageFactory;
|
||||||
import org.keycloak.testsuite.runonserver.RunOnServerDeployment;
|
import org.keycloak.testsuite.runonserver.RunOnServerDeployment;
|
||||||
|
import org.keycloak.testsuite.util.RealmBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author tkyjovsk
|
* @author tkyjovsk
|
||||||
*/
|
*/
|
||||||
public class ComponentExportImportTest extends AbstractAuthTest implements Serializable {
|
public class ComponentExportImportTest extends AbstractAuthTest {
|
||||||
|
|
||||||
|
private static final String REALM_NAME = "exported-component";
|
||||||
|
|
||||||
private File exportFile;
|
private File exportFile;
|
||||||
|
|
||||||
|
@ -44,9 +51,25 @@ public class ComponentExportImportTest extends AbstractAuthTest implements Seria
|
||||||
public void setDirs() {
|
public void setDirs() {
|
||||||
exportFile = new File (new File(System.getProperty("auth.server.config.dir", "target")), "singleFile-full.json");
|
exportFile = new File (new File(System.getProperty("auth.server.config.dir", "target")), "singleFile-full.json");
|
||||||
log.infof("Export file: %s", exportFile);
|
log.infof("Export file: %s", exportFile);
|
||||||
|
|
||||||
|
// Remove realm if exists
|
||||||
|
testingClient.server().run(session -> {
|
||||||
|
RealmModel realm = session.realms().getRealmByName(REALM_NAME);
|
||||||
|
if (realm != null) {
|
||||||
|
session.realms().removeRealm(realm.getId());
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearExportImportProperties() {
|
|
||||||
|
@Override
|
||||||
|
public RealmResource testRealmResource() {
|
||||||
|
return adminClient.realm(REALM_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void clearExportImportProperties(KeycloakTestingClient testingClient) {
|
||||||
|
testingClient.server().run(session -> {
|
||||||
// Clear export/import properties after test
|
// Clear export/import properties after test
|
||||||
Properties systemProps = System.getProperties();
|
Properties systemProps = System.getProperties();
|
||||||
Set<String> propsToRemove = new HashSet<>();
|
Set<String> propsToRemove = new HashSet<>();
|
||||||
|
@ -60,19 +83,23 @@ public class ComponentExportImportTest extends AbstractAuthTest implements Seria
|
||||||
for (String propToRemove : propsToRemove) {
|
for (String propToRemove : propsToRemove) {
|
||||||
systemProps.remove(propToRemove);
|
systemProps.remove(propToRemove);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected String addComponent(ComponentRepresentation component) {
|
protected String addComponent(ComponentRepresentation component) {
|
||||||
return ApiUtil.getCreatedId(testRealmResource().components().add(component));
|
return ApiUtil.getCreatedId(testRealmResource().components().add(component));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Ignore
|
|
||||||
public void testSingleFile() {
|
public void testSingleFile() {
|
||||||
clearExportImportProperties();
|
clearExportImportProperties(testingClient);
|
||||||
|
|
||||||
|
RealmRepresentation realmRep = RealmBuilder.create()
|
||||||
|
.name(REALM_NAME)
|
||||||
|
.build();
|
||||||
|
adminClient.realms().create(realmRep);
|
||||||
String realmId = testRealmResource().toRepresentation().getId();
|
String realmId = testRealmResource().toRepresentation().getId();
|
||||||
String realmName = testRealmResource().toRepresentation().getRealm();
|
|
||||||
|
|
||||||
ComponentRepresentation parentComponent = new ComponentRepresentation();
|
ComponentRepresentation parentComponent = new ComponentRepresentation();
|
||||||
parentComponent.setParentId(realmId);
|
parentComponent.setParentId(realmId);
|
||||||
|
@ -96,23 +123,36 @@ public class ComponentExportImportTest extends AbstractAuthTest implements Seria
|
||||||
subcomponent.getConfig().putSingle("attr", "value2");
|
subcomponent.getConfig().putSingle("attr", "value2");
|
||||||
String subcomponentId = addComponent(subcomponent);
|
String subcomponentId = addComponent(subcomponent);
|
||||||
|
|
||||||
|
final String exportFilePath = exportFile.getAbsolutePath();
|
||||||
|
|
||||||
// export
|
// export
|
||||||
testingClient.server().run(session -> {
|
testingClient.server().run(session -> {
|
||||||
ExportImportConfig.setProvider(SingleFileExportProviderFactory.PROVIDER_ID);
|
ExportImportConfig.setProvider(SingleFileExportProviderFactory.PROVIDER_ID);
|
||||||
ExportImportConfig.setFile(exportFile.getAbsolutePath());
|
ExportImportConfig.setFile(exportFilePath);
|
||||||
ExportImportConfig.setRealmName(realmName);
|
ExportImportConfig.setRealmName(REALM_NAME);
|
||||||
ExportImportConfig.setAction(ExportImportConfig.ACTION_EXPORT);
|
ExportImportConfig.setAction(ExportImportConfig.ACTION_EXPORT);
|
||||||
new ExportImportManager(session).runExport();
|
new ExportImportManager(session).runExport();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testRealmResource().remove();
|
||||||
|
|
||||||
|
try {
|
||||||
|
testRealmResource().toRepresentation();
|
||||||
|
Assert.fail("Realm wasn't expected to be found");
|
||||||
|
} catch (NotFoundException nfe) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
|
||||||
// import
|
// import
|
||||||
testingClient.server().run(session -> {
|
testingClient.server().run(session -> {
|
||||||
Assert.assertNull(session.realms().getRealmByName(TEST));
|
Assert.assertNull(session.realms().getRealmByName(REALM_NAME));
|
||||||
ExportImportConfig.setAction(ExportImportConfig.ACTION_IMPORT);
|
ExportImportConfig.setAction(ExportImportConfig.ACTION_IMPORT);
|
||||||
new ExportImportManager(session).runImport();
|
new ExportImportManager(session).runImport();
|
||||||
Assert.assertNotNull(session.realms().getRealmByName(TEST));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Assert realm was imported
|
||||||
|
Assert.assertNotNull(testRealmResource().toRepresentation());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
parentComponent = testRealmResource().components().component(parentComponentId).toRepresentation();
|
parentComponent = testRealmResource().components().component(parentComponentId).toRepresentation();
|
||||||
subcomponent = testRealmResource().components().component(subcomponentId).toRepresentation();
|
subcomponent = testRealmResource().components().component(subcomponentId).toRepresentation();
|
||||||
|
@ -127,7 +167,7 @@ public class ComponentExportImportTest extends AbstractAuthTest implements Seria
|
||||||
Assert.assertEquals(parentComponent.getProviderType(), UserStorageProvider.class.getName());
|
Assert.assertEquals(parentComponent.getProviderType(), UserStorageProvider.class.getName());
|
||||||
Assert.assertEquals(parentComponent.getConfig().getFirst("attr"), "value");
|
Assert.assertEquals(parentComponent.getConfig().getFirst("attr"), "value");
|
||||||
|
|
||||||
Assert.assertEquals(subcomponent.getParentId(), realmId);
|
Assert.assertEquals(subcomponent.getParentId(), parentComponent.getId());
|
||||||
Assert.assertEquals(subcomponent.getName(), "child");
|
Assert.assertEquals(subcomponent.getName(), "child");
|
||||||
Assert.assertEquals(subcomponent.getSubType(), "subtype2");
|
Assert.assertEquals(subcomponent.getSubType(), "subtype2");
|
||||||
Assert.assertEquals(subcomponent.getProviderId(), UserMapStorageFactory.PROVIDER_ID);
|
Assert.assertEquals(subcomponent.getProviderId(), UserMapStorageFactory.PROVIDER_ID);
|
||||||
|
|
|
@ -0,0 +1,237 @@
|
||||||
|
/*
|
||||||
|
* 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.federation.storage;
|
||||||
|
|
||||||
|
import org.jboss.arquillian.container.test.api.Deployment;
|
||||||
|
import org.jboss.shrinkwrap.api.spec.WebArchive;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.keycloak.admin.client.resource.RealmResource;
|
||||||
|
import org.keycloak.common.util.MultivaluedHashMap;
|
||||||
|
import org.keycloak.credential.CredentialModel;
|
||||||
|
import org.keycloak.credential.hash.PasswordHashProvider;
|
||||||
|
import org.keycloak.exportimport.ExportImportConfig;
|
||||||
|
import org.keycloak.exportimport.ExportImportManager;
|
||||||
|
import org.keycloak.exportimport.dir.DirExportProviderFactory;
|
||||||
|
import org.keycloak.exportimport.singlefile.SingleFileExportProviderFactory;
|
||||||
|
import org.keycloak.models.GroupModel;
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.PasswordPolicy;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.models.RoleModel;
|
||||||
|
import org.keycloak.services.managers.RealmManager;
|
||||||
|
import org.keycloak.testsuite.AbstractAuthTest;
|
||||||
|
import org.keycloak.testsuite.runonserver.RunOnServerDeployment;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.ws.rs.NotFoundException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
public class FederatedStorageExportImportTest extends AbstractAuthTest {
|
||||||
|
|
||||||
|
private static final String REALM_NAME = "exported";
|
||||||
|
|
||||||
|
private String exportFileAbsolutePath;
|
||||||
|
private String exportDirAbsolutePath;
|
||||||
|
|
||||||
|
|
||||||
|
@Deployment
|
||||||
|
public static WebArchive deploy() {
|
||||||
|
return RunOnServerDeployment.create(ComponentExportImportTest.class, AbstractAuthTest.class, RealmResource.class)
|
||||||
|
.addPackages(true, "org.keycloak.testsuite");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setDirs() {
|
||||||
|
File baseDir = new File(System.getProperty("auth.server.config.dir", "target"));
|
||||||
|
|
||||||
|
exportFileAbsolutePath = new File (baseDir, "singleFile-full.json").getAbsolutePath();
|
||||||
|
log.infof("Export file: %s", exportFileAbsolutePath);
|
||||||
|
|
||||||
|
exportDirAbsolutePath = baseDir.getAbsolutePath() + File.separator + "dirExport";
|
||||||
|
log.infof("Export dir: %s", exportDirAbsolutePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RealmResource testRealmResource() {
|
||||||
|
return adminClient.realm(REALM_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void cleanup() {
|
||||||
|
try {
|
||||||
|
testRealmResource().remove();
|
||||||
|
} catch (NotFoundException ignore) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PasswordHashProvider getHashProvider(KeycloakSession session, PasswordPolicy policy) {
|
||||||
|
PasswordHashProvider hash = session.getProvider(PasswordHashProvider.class, policy.getHashAlgorithm());
|
||||||
|
if (hash == null) {
|
||||||
|
return session.getProvider(PasswordHashProvider.class, PasswordPolicy.HASH_ALGORITHM_DEFAULT);
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSingleFile() throws Exception {
|
||||||
|
ComponentExportImportTest.clearExportImportProperties(testingClient);
|
||||||
|
|
||||||
|
final String userId = "f:1:path";
|
||||||
|
|
||||||
|
testingClient.server().run(session -> {
|
||||||
|
RealmModel realm = new RealmManager(session).createRealm(REALM_NAME);
|
||||||
|
RoleModel role = realm.addRole("test-role");
|
||||||
|
GroupModel group = realm.createGroup("test-group");
|
||||||
|
|
||||||
|
List<String> attrValues = new LinkedList<>();
|
||||||
|
attrValues.add("1");
|
||||||
|
attrValues.add("2");
|
||||||
|
session.userFederatedStorage().setSingleAttribute(realm, userId, "single1", "value1");
|
||||||
|
session.userFederatedStorage().setAttribute(realm, userId, "list1", attrValues);
|
||||||
|
session.userFederatedStorage().addRequiredAction(realm, userId, "UPDATE_PASSWORD");
|
||||||
|
CredentialModel credential = new CredentialModel();
|
||||||
|
FederatedStorageExportImportTest.getHashProvider(session, realm.getPasswordPolicy()).encode("password", realm.
|
||||||
|
getPasswordPolicy().getHashIterations(), credential);
|
||||||
|
session.userFederatedStorage().createCredential(realm, userId, credential);
|
||||||
|
session.userFederatedStorage().grantRole(realm, userId, role);
|
||||||
|
session.userFederatedStorage().joinGroup(realm, userId, group);
|
||||||
|
});
|
||||||
|
|
||||||
|
final String realmId = testRealmResource().toRepresentation().getId();
|
||||||
|
final String groupId = testRealmResource().getGroupByPath("/test-group").getId();
|
||||||
|
final String exportFileAbsolutePath = this.exportFileAbsolutePath;
|
||||||
|
|
||||||
|
testingClient.server().run(session -> {
|
||||||
|
ExportImportConfig.setProvider(SingleFileExportProviderFactory.PROVIDER_ID);
|
||||||
|
ExportImportConfig.setFile(exportFileAbsolutePath);
|
||||||
|
ExportImportConfig.setRealmName(REALM_NAME);
|
||||||
|
ExportImportConfig.setAction(ExportImportConfig.ACTION_EXPORT);
|
||||||
|
new ExportImportManager(session).runExport();
|
||||||
|
session.realms().removeRealm(realmId);
|
||||||
|
});
|
||||||
|
|
||||||
|
testingClient.server().run(session -> {
|
||||||
|
Assert.assertNull(session.realms().getRealmByName(REALM_NAME));
|
||||||
|
ExportImportConfig.setAction(ExportImportConfig.ACTION_IMPORT);
|
||||||
|
new ExportImportManager(session).runImport();
|
||||||
|
});
|
||||||
|
|
||||||
|
testingClient.server().run(session -> {
|
||||||
|
RealmModel realm = session.realms().getRealmByName(REALM_NAME);
|
||||||
|
Assert.assertNotNull(realm);
|
||||||
|
RoleModel role = realm.getRole("test-role");
|
||||||
|
GroupModel group = realm.getGroupById(groupId);
|
||||||
|
|
||||||
|
Assert.assertEquals(1, session.userFederatedStorage().getStoredUsersCount(realm));
|
||||||
|
MultivaluedHashMap<String, String> attributes = session.userFederatedStorage().getAttributes(realm, userId);
|
||||||
|
Assert.assertEquals(3, attributes.size());
|
||||||
|
Assert.assertEquals("value1", attributes.getFirst("single1"));
|
||||||
|
Assert.assertTrue(attributes.getList("list1").contains("1"));
|
||||||
|
Assert.assertTrue(attributes.getList("list1").contains("2"));
|
||||||
|
Assert.assertTrue(session.userFederatedStorage().getRequiredActions(realm, userId).contains("UPDATE_PASSWORD"));
|
||||||
|
Assert.assertTrue(session.userFederatedStorage().getRoleMappings(realm, userId).contains(role));
|
||||||
|
Assert.assertTrue(session.userFederatedStorage().getGroups(realm, userId).contains(group));
|
||||||
|
List<CredentialModel> creds = session.userFederatedStorage().getStoredCredentials(realm, userId);
|
||||||
|
Assert.assertEquals(1, creds.size());
|
||||||
|
Assert.assertTrue(FederatedStorageExportImportTest.getHashProvider(session, realm.getPasswordPolicy()).verify("password", creds.get(0)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDir() throws Exception {
|
||||||
|
ComponentExportImportTest.clearExportImportProperties(testingClient);
|
||||||
|
|
||||||
|
final String userId = "f:1:path";
|
||||||
|
|
||||||
|
testingClient.server().run(session -> {
|
||||||
|
RealmModel realm = new RealmManager(session).createRealm(REALM_NAME);
|
||||||
|
|
||||||
|
RoleModel role = realm.addRole("test-role");
|
||||||
|
GroupModel group = realm.createGroup("test-group");
|
||||||
|
List<String> attrValues = new LinkedList<>();
|
||||||
|
attrValues.add("1");
|
||||||
|
attrValues.add("2");
|
||||||
|
session.userFederatedStorage().setSingleAttribute(realm, userId, "single1", "value1");
|
||||||
|
session.userFederatedStorage().setAttribute(realm, userId, "list1", attrValues);
|
||||||
|
session.userFederatedStorage().addRequiredAction(realm, userId, "UPDATE_PASSWORD");
|
||||||
|
CredentialModel credential = new CredentialModel();
|
||||||
|
FederatedStorageExportImportTest.getHashProvider(session, realm.getPasswordPolicy()).encode("password", realm.
|
||||||
|
getPasswordPolicy().getHashIterations(), credential);
|
||||||
|
session.userFederatedStorage().createCredential(realm, userId, credential);
|
||||||
|
session.userFederatedStorage().grantRole(realm, userId, role);
|
||||||
|
session.userFederatedStorage().joinGroup(realm, userId, group);
|
||||||
|
session.userFederatedStorage().setNotBeforeForUser(realm, userId, 50);
|
||||||
|
});
|
||||||
|
|
||||||
|
final String realmId = testRealmResource().toRepresentation().getId();
|
||||||
|
final String groupId = testRealmResource().getGroupByPath("/test-group").getId();
|
||||||
|
final String exportDirAbsolutePath = this.exportDirAbsolutePath;
|
||||||
|
|
||||||
|
testingClient.server().run(session -> {
|
||||||
|
ExportImportConfig.setProvider(DirExportProviderFactory.PROVIDER_ID);
|
||||||
|
ExportImportConfig.setDir(exportDirAbsolutePath);
|
||||||
|
ExportImportConfig.setRealmName(REALM_NAME);
|
||||||
|
ExportImportConfig.setAction(ExportImportConfig.ACTION_EXPORT);
|
||||||
|
new ExportImportManager(session).runExport();
|
||||||
|
session.realms().removeRealm(realmId);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
testingClient.server().run(session -> {
|
||||||
|
Assert.assertNull(session.realms().getRealmByName(REALM_NAME));
|
||||||
|
ExportImportConfig.setAction(ExportImportConfig.ACTION_IMPORT);
|
||||||
|
new ExportImportManager(session).runImport();
|
||||||
|
});
|
||||||
|
|
||||||
|
testingClient.server().run(session -> {
|
||||||
|
RealmModel realm = session.realms().getRealmByName(REALM_NAME);
|
||||||
|
Assert.assertNotNull(realm);
|
||||||
|
RoleModel role = realm.getRole("test-role");
|
||||||
|
GroupModel group = realm.getGroupById(groupId);
|
||||||
|
|
||||||
|
Assert.assertEquals(1, session.userFederatedStorage().getStoredUsersCount(realm));
|
||||||
|
MultivaluedHashMap<String, String> attributes = session.userFederatedStorage().getAttributes(realm, userId);
|
||||||
|
Assert.assertEquals(3, attributes.size());
|
||||||
|
Assert.assertEquals("value1", attributes.getFirst("single1"));
|
||||||
|
Assert.assertTrue(attributes.getList("list1").contains("1"));
|
||||||
|
Assert.assertTrue(attributes.getList("list1").contains("2"));
|
||||||
|
Assert.assertTrue(session.userFederatedStorage().getRequiredActions(realm, userId).contains("UPDATE_PASSWORD"));
|
||||||
|
Assert.assertTrue(session.userFederatedStorage().getRoleMappings(realm, userId).contains(role));
|
||||||
|
Assert.assertTrue(session.userFederatedStorage().getGroups(realm, userId).contains(group));
|
||||||
|
Assert.assertEquals(50, session.userFederatedStorage().getNotBeforeOfUser(realm, userId));
|
||||||
|
List<CredentialModel> creds = session.userFederatedStorage().getStoredCredentials(realm, userId);
|
||||||
|
Assert.assertEquals(1, creds.size());
|
||||||
|
Assert.assertTrue(FederatedStorageExportImportTest.getHashProvider(session, realm.getPasswordPolicy()).verify("password", creds.get(0)));
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
* Copyright 2017 Red Hat, Inc. and/or its affiliates
|
||||||
* and other contributors as indicated by the @author tags.
|
* and other contributors as indicated by the @author tags.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@ -16,17 +16,22 @@
|
||||||
*/
|
*/
|
||||||
package org.keycloak.testsuite.federation.storage;
|
package org.keycloak.testsuite.federation.storage;
|
||||||
|
|
||||||
|
import org.jboss.arquillian.container.test.api.ContainerController;
|
||||||
|
import org.jboss.arquillian.container.test.api.Deployment;
|
||||||
|
import org.jboss.arquillian.graphene.page.Page;
|
||||||
|
import org.jboss.arquillian.test.api.ArquillianResource;
|
||||||
|
import org.jboss.shrinkwrap.api.spec.WebArchive;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.ClassRule;
|
import org.junit.Before;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.keycloak.OAuth2Constants;
|
import org.keycloak.OAuth2Constants;
|
||||||
|
import org.keycloak.admin.client.resource.RealmResource;
|
||||||
import org.keycloak.common.constants.ServiceAccountConstants;
|
import org.keycloak.common.constants.ServiceAccountConstants;
|
||||||
|
import org.keycloak.common.util.MultivaluedHashMap;
|
||||||
import org.keycloak.component.ComponentModel;
|
import org.keycloak.component.ComponentModel;
|
||||||
import org.keycloak.events.Details;
|
import org.keycloak.events.Details;
|
||||||
import org.keycloak.events.Event;
|
|
||||||
import org.keycloak.models.ClientModel;
|
import org.keycloak.models.ClientModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.RoleModel;
|
import org.keycloak.models.RoleModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
|
@ -34,19 +39,27 @@ import org.keycloak.models.cache.CachedUserModel;
|
||||||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||||
import org.keycloak.representations.AccessToken;
|
import org.keycloak.representations.AccessToken;
|
||||||
import org.keycloak.representations.RefreshToken;
|
import org.keycloak.representations.RefreshToken;
|
||||||
|
import org.keycloak.representations.idm.ComponentRepresentation;
|
||||||
|
import org.keycloak.representations.idm.EventRepresentation;
|
||||||
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
import org.keycloak.services.managers.RealmManager;
|
import org.keycloak.services.managers.RealmManager;
|
||||||
|
import org.keycloak.storage.UserStorageProvider;
|
||||||
import org.keycloak.storage.UserStorageProviderModel;
|
import org.keycloak.storage.UserStorageProviderModel;
|
||||||
import org.keycloak.testsuite.ApplicationServlet;
|
import org.keycloak.testsuite.AbstractAuthTest;
|
||||||
|
import org.keycloak.testsuite.AbstractTestRealmKeycloakTest;
|
||||||
import org.keycloak.testsuite.AssertEvents;
|
import org.keycloak.testsuite.AssertEvents;
|
||||||
import org.keycloak.testsuite.Constants;
|
import org.keycloak.testsuite.auth.page.AuthRealm;
|
||||||
import org.keycloak.testsuite.OAuthClient;
|
import org.keycloak.testsuite.federation.FailableHardcodedStorageProvider;
|
||||||
|
import org.keycloak.testsuite.federation.FailableHardcodedStorageProviderFactory;
|
||||||
|
import org.keycloak.testsuite.pages.AccountApplicationsPage;
|
||||||
import org.keycloak.testsuite.pages.AppPage;
|
import org.keycloak.testsuite.pages.AppPage;
|
||||||
import org.keycloak.testsuite.pages.LoginPage;
|
import org.keycloak.testsuite.pages.LoginPage;
|
||||||
import org.keycloak.testsuite.rule.KeycloakRule;
|
import org.keycloak.testsuite.runonserver.RunOnServerDeployment;
|
||||||
import org.keycloak.testsuite.rule.WebResource;
|
import org.keycloak.testsuite.util.Matchers;
|
||||||
import org.keycloak.testsuite.rule.WebRule;
|
import org.keycloak.testsuite.util.OAuthClient;
|
||||||
import org.openqa.selenium.WebDriver;
|
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -56,22 +69,52 @@ import java.util.Map;
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public class UserStorageFailureTest {
|
public class UserStorageFailureTest extends AbstractTestRealmKeycloakTest {
|
||||||
public static ComponentModel memoryProvider = null;
|
|
||||||
public static String realmName;
|
private static boolean initialized = false;
|
||||||
public static final String LOCAL_USER = "localUser";
|
|
||||||
@ClassRule
|
@Deployment
|
||||||
public static KeycloakRule keycloakRule = new KeycloakRule(new KeycloakRule.KeycloakSetup() {
|
public static WebArchive deploy() {
|
||||||
|
return RunOnServerDeployment.create(ComponentExportImportTest.class, AbstractAuthTest.class, RealmResource.class)
|
||||||
|
.addPackages(true, "org.keycloak.testsuite");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final String LOCAL_USER = "localUser";
|
||||||
|
|
||||||
|
private String failureProviderId;
|
||||||
|
|
||||||
|
@ArquillianResource
|
||||||
|
protected ContainerController controller;
|
||||||
|
|
||||||
|
@Page
|
||||||
|
protected LoginPage loginPage;
|
||||||
|
|
||||||
|
@Page
|
||||||
|
protected AppPage appPage;
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public AssertEvents events = new AssertEvents(this);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
public void configureTestRealm(RealmRepresentation testRealm) {
|
||||||
UserStorageProviderModel model = new UserStorageProviderModel();
|
}
|
||||||
model.setName("failure");
|
|
||||||
model.setPriority(0);
|
|
||||||
model.setProviderId(FailableHardcodedStorageProviderFactory.PROVIDER_ID);
|
@Before
|
||||||
model.setParentId(appRealm.getId());
|
public void addProvidersBeforeTest() throws URISyntaxException, IOException {
|
||||||
memoryProvider = appRealm.addComponentModel(model);
|
ComponentRepresentation memProvider = new ComponentRepresentation();
|
||||||
realmName = appRealm.getName();
|
memProvider.setName("failure");
|
||||||
|
memProvider.setProviderId(FailableHardcodedStorageProviderFactory.PROVIDER_ID);
|
||||||
|
memProvider.setProviderType(UserStorageProvider.class.getName());
|
||||||
|
memProvider.setConfig(new MultivaluedHashMap<>());
|
||||||
|
memProvider.getConfig().putSingle("priority", Integer.toString(0));
|
||||||
|
failureProviderId = addComponent(memProvider);
|
||||||
|
|
||||||
|
if (initialized) return;
|
||||||
|
|
||||||
|
testingClient.server().run(session -> {
|
||||||
|
RealmManager manager = new RealmManager(session);
|
||||||
|
RealmModel appRealm = manager.getRealmByName(AuthRealm.TEST);
|
||||||
|
|
||||||
ClientModel offlineClient = appRealm.addClient("offline-client");
|
ClientModel offlineClient = appRealm.addClient("offline-client");
|
||||||
offlineClient.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
|
offlineClient.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
|
||||||
|
@ -79,7 +122,7 @@ public class UserStorageFailureTest {
|
||||||
offlineClient.setDirectAccessGrantsEnabled(true);
|
offlineClient.setDirectAccessGrantsEnabled(true);
|
||||||
offlineClient.setSecret("secret");
|
offlineClient.setSecret("secret");
|
||||||
HashSet<String> redirects = new HashSet<>();
|
HashSet<String> redirects = new HashSet<>();
|
||||||
redirects.add(Constants.AUTH_SERVER_ROOT + "/offline-client");
|
redirects.add(OAuthClient.AUTH_SERVER_ROOT + "/offline-client");
|
||||||
offlineClient.setRedirectUris(redirects);
|
offlineClient.setRedirectUris(redirects);
|
||||||
offlineClient.setServiceAccountsEnabled(true);
|
offlineClient.setServiceAccountsEnabled(true);
|
||||||
offlineClient.setFullScopeAllowed(true);
|
offlineClient.setFullScopeAllowed(true);
|
||||||
|
@ -93,29 +136,19 @@ public class UserStorageFailureTest {
|
||||||
|
|
||||||
UserModel localUser = manager.getSession().userLocalStorage().addUser(appRealm, LOCAL_USER);
|
UserModel localUser = manager.getSession().userLocalStorage().addUser(appRealm, LOCAL_USER);
|
||||||
localUser.setEnabled(true);
|
localUser.setEnabled(true);
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@Rule
|
initialized = true;
|
||||||
public WebRule webRule = new WebRule(this);
|
}
|
||||||
|
|
||||||
@WebResource
|
|
||||||
protected OAuthClient oauth;
|
|
||||||
|
|
||||||
@WebResource
|
public RealmResource testRealmResource() {
|
||||||
protected WebDriver driver;
|
return adminClient.realm(AuthRealm.TEST);
|
||||||
|
}
|
||||||
@WebResource
|
|
||||||
protected AppPage appPage;
|
|
||||||
|
|
||||||
@WebResource
|
|
||||||
protected LoginPage loginPage;
|
|
||||||
|
|
||||||
@Rule
|
|
||||||
public AssertEvents events = new AssertEvents(keycloakRule);
|
|
||||||
|
|
||||||
|
private String addComponent(ComponentRepresentation component) {
|
||||||
|
return UserStorageTest.addComponent(testRealmResource(), getCleanup(), component);
|
||||||
|
}
|
||||||
|
|
||||||
// this is a hack so that UserModel doesn't have to be available when offline token is imported.
|
// this is a hack so that UserModel doesn't have to be available when offline token is imported.
|
||||||
// see related JIRA - KEYCLOAK-5350 and corresponding test
|
// see related JIRA - KEYCLOAK-5350 and corresponding test
|
||||||
|
@ -124,16 +157,17 @@ public class UserStorageFailureTest {
|
||||||
* KEYCLOAK-5350
|
* KEYCLOAK-5350
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testKeycloak5350() {
|
public void testKeycloak5350() throws Exception {
|
||||||
oauth.scope(OAuth2Constants.OFFLINE_ACCESS);
|
oauth.scope(OAuth2Constants.OFFLINE_ACCESS);
|
||||||
oauth.clientId("offline-client");
|
oauth.clientId("offline-client");
|
||||||
oauth.redirectUri(Constants.AUTH_SERVER_ROOT + "/offline-client");
|
oauth.redirectUri(OAuthClient.AUTH_SERVER_ROOT + "/offline-client");
|
||||||
oauth.doLogin(FailableHardcodedStorageProvider.username, "password");
|
oauth.doLogin(FailableHardcodedStorageProvider.username, "password");
|
||||||
|
|
||||||
Event loginEvent = events.expectLogin()
|
EventRepresentation loginEvent = events.expectLogin()
|
||||||
|
.user(AssertEvents.isUUID())
|
||||||
.client("offline-client")
|
.client("offline-client")
|
||||||
.detail(Details.REDIRECT_URI, Constants.AUTH_SERVER_ROOT + "/offline-client")
|
.detail(Details.REDIRECT_URI, OAuthClient.AUTH_SERVER_ROOT + "/offline-client")
|
||||||
.event();
|
.assertEvent();
|
||||||
|
|
||||||
final String sessionId = loginEvent.getSessionId();
|
final String sessionId = loginEvent.getSessionId();
|
||||||
String codeId = loginEvent.getDetails().get(Details.CODE_ID);
|
String codeId = loginEvent.getDetails().get(Details.CODE_ID);
|
||||||
|
@ -148,27 +182,23 @@ public class UserStorageFailureTest {
|
||||||
|
|
||||||
evictUser(FailableHardcodedStorageProvider.username);
|
evictUser(FailableHardcodedStorageProvider.username);
|
||||||
|
|
||||||
KeycloakSession session;
|
|
||||||
RealmModel realm;
|
|
||||||
UserModel user;
|
|
||||||
|
|
||||||
toggleForceFail(true);
|
toggleForceFail(true);
|
||||||
|
|
||||||
// make sure failure is turned on
|
// make sure failure is turned on
|
||||||
session = keycloakRule.startSession();
|
testingClient.server().run(session -> {
|
||||||
realm = session.realms().getRealmByName(realmName);
|
RealmModel realm = session.realms().getRealmByName(AuthRealm.TEST);
|
||||||
try {
|
try {
|
||||||
user = session.users().getUserByUsername(FailableHardcodedStorageProvider.username, realm);
|
UserModel user = session.users().getUserByUsername(FailableHardcodedStorageProvider.username, realm);
|
||||||
Assert.fail();
|
Assert.fail();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Assert.assertEquals("FORCED FAILURE", e.getMessage());
|
Assert.assertEquals("FORCED FAILURE", e.getMessage());
|
||||||
|
|
||||||
}
|
}
|
||||||
keycloakRule.stopSession(session, false);
|
});
|
||||||
|
|
||||||
// restart server to make sure we can still boot if user storage is down
|
controller.stop(suiteContext.getAuthServerInfo().getQualifier());
|
||||||
keycloakRule.restartServer();
|
controller.start(suiteContext.getAuthServerInfo().getQualifier());
|
||||||
keycloakRule.deployServlet("app", "/app", ApplicationServlet.class);
|
reconnectAdminClient();
|
||||||
|
|
||||||
toggleForceFail(false);
|
toggleForceFail(false);
|
||||||
|
|
||||||
|
@ -184,33 +214,35 @@ public class UserStorageFailureTest {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void evictUser(String username) {
|
protected void evictUser(final String username) {
|
||||||
KeycloakSession session = keycloakRule.startSession();
|
testingClient.server().run(session -> {
|
||||||
RealmModel realm = session.realms().getRealmByName(realmName);
|
RealmModel realm = session.realms().getRealmByName(AuthRealm.TEST);
|
||||||
UserModel user = session.users().getUserByUsername(username, realm);
|
UserModel user = session.users().getUserByUsername(username, realm);
|
||||||
session.userCache().evict(realm, user);
|
session.userCache().evict(realm, user);
|
||||||
keycloakRule.stopSession(session, true);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void toggleForceFail(boolean toggle) {
|
protected void toggleForceFail(final boolean toggle) {
|
||||||
KeycloakSession session;
|
final String failureProviderId = this.failureProviderId;
|
||||||
RealmModel realm;
|
|
||||||
session = keycloakRule.startSession();
|
testingClient.server().run(session -> {
|
||||||
|
RealmModel realm = session.realms().getRealmByName(AuthRealm.TEST);
|
||||||
|
ComponentModel memoryProvider = realm.getComponent(failureProviderId);
|
||||||
memoryProvider.getConfig().putSingle("fail", Boolean.toString(toggle));
|
memoryProvider.getConfig().putSingle("fail", Boolean.toString(toggle));
|
||||||
realm = session.realms().getRealmByName(realmName);
|
|
||||||
realm.updateComponent(memoryProvider);
|
realm.updateComponent(memoryProvider);
|
||||||
keycloakRule.stopSession(session, true);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void toggleProviderEnabled(boolean toggle) {
|
protected void toggleProviderEnabled(final boolean toggle) {
|
||||||
KeycloakSession session;
|
final String failureProviderId = this.failureProviderId;
|
||||||
RealmModel realm;
|
|
||||||
session = keycloakRule.startSession();
|
testingClient.server().run(session -> {
|
||||||
|
RealmModel realm = session.realms().getRealmByName(AuthRealm.TEST);
|
||||||
|
ComponentModel memoryProvider = realm.getComponent(failureProviderId);
|
||||||
UserStorageProviderModel model = new UserStorageProviderModel(memoryProvider);
|
UserStorageProviderModel model = new UserStorageProviderModel(memoryProvider);
|
||||||
model.setEnabled(toggle);
|
model.setEnabled(toggle);
|
||||||
realm = session.realms().getRealmByName(realmName);
|
|
||||||
realm.updateComponent(model);
|
realm.updateComponent(model);
|
||||||
keycloakRule.stopSession(session, true);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loginSuccessAndLogout(String username, String password) {
|
private void loginSuccessAndLogout(String username, String password) {
|
||||||
|
@ -226,37 +258,37 @@ public class UserStorageFailureTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testKeycloak5926() {
|
public void testKeycloak5926() {
|
||||||
|
oauth.clientId("test-app");
|
||||||
|
oauth.redirectUri(OAuthClient.APP_AUTH_ROOT);
|
||||||
|
|
||||||
// make sure local copy is deleted
|
// make sure local copy is deleted
|
||||||
{
|
testingClient.server().run(session -> {
|
||||||
KeycloakSession session = keycloakRule.startSession();
|
RealmModel realm = session.realms().getRealmByName(AuthRealm.TEST);
|
||||||
RealmModel realm = session.realms().getRealmByName(realmName);
|
|
||||||
UserModel user = session.userLocalStorage().getUserByUsername(FailableHardcodedStorageProvider.username, realm);
|
UserModel user = session.userLocalStorage().getUserByUsername(FailableHardcodedStorageProvider.username, realm);
|
||||||
if (user != null) {
|
if (user != null) {
|
||||||
session.userLocalStorage().removeUser(realm, user);
|
session.userLocalStorage().removeUser(realm, user);
|
||||||
}
|
}
|
||||||
keycloakRule.stopSession(session, true);
|
});
|
||||||
}
|
|
||||||
|
|
||||||
// query user to make sure its imported
|
// query user to make sure its imported
|
||||||
{
|
testingClient.server().run(session -> {
|
||||||
KeycloakSession session = keycloakRule.startSession();
|
RealmModel realm = session.realms().getRealmByName(AuthRealm.TEST);
|
||||||
RealmModel realm = session.realms().getRealmByName(realmName);
|
|
||||||
UserModel user = session.users().getUserByUsername(FailableHardcodedStorageProvider.username, realm);
|
UserModel user = session.users().getUserByUsername(FailableHardcodedStorageProvider.username, realm);
|
||||||
Assert.assertNotNull(user);
|
Assert.assertNotNull(user);
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
evictUser(FailableHardcodedStorageProvider.username);
|
evictUser(FailableHardcodedStorageProvider.username);
|
||||||
evictUser(LOCAL_USER);
|
evictUser(LOCAL_USER);
|
||||||
|
|
||||||
toggleForceFail(true);
|
toggleForceFail(true);
|
||||||
{
|
|
||||||
KeycloakSession session = keycloakRule.startSession();
|
testingClient.server().run(session -> {
|
||||||
// make sure we can still query local users
|
RealmModel realm = session.realms().getRealmByName(AuthRealm.TEST);
|
||||||
RealmModel realm = session.realms().getRealmByName(realmName);
|
|
||||||
UserModel local = session.users().getUserByUsername(LOCAL_USER, realm);
|
UserModel local = session.users().getUserByUsername(LOCAL_USER, realm);
|
||||||
Assert.assertNotNull(local);
|
Assert.assertNotNull(local);
|
||||||
// assert that lookup of user storage user fails
|
// assert that lookup of user storage user fails
|
||||||
|
@ -268,16 +300,16 @@ public class UserStorageFailureTest {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
keycloakRule.stopSession(session, true);
|
});
|
||||||
}
|
|
||||||
// test that we can still login to a user
|
// test that we can still login to a user
|
||||||
loginSuccessAndLogout("test-user@localhost", "password");
|
loginSuccessAndLogout("test-user@localhost", "password");
|
||||||
|
|
||||||
toggleProviderEnabled(false);
|
toggleProviderEnabled(false);
|
||||||
{
|
|
||||||
KeycloakSession session = keycloakRule.startSession();
|
testingClient.server().run(session -> {
|
||||||
// make sure we can still query local users
|
RealmModel realm = session.realms().getRealmByName(AuthRealm.TEST);
|
||||||
RealmModel realm = session.realms().getRealmByName(realmName);
|
|
||||||
UserModel local = session.users().getUserByUsername(LOCAL_USER, realm);
|
UserModel local = session.users().getUserByUsername(LOCAL_USER, realm);
|
||||||
Assert.assertNotNull(local);
|
Assert.assertNotNull(local);
|
||||||
List<UserModel> result;
|
List<UserModel> result;
|
||||||
|
@ -319,29 +351,27 @@ public class UserStorageFailureTest {
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
|
|
||||||
}
|
}
|
||||||
keycloakRule.stopSession(session, true);
|
});
|
||||||
}
|
|
||||||
// make sure user isn't cached as provider is disabled
|
// make sure user isn't cached as provider is disabled
|
||||||
{
|
testingClient.server().run(session -> {
|
||||||
KeycloakSession session = keycloakRule.startSession();
|
RealmModel realm = session.realms().getRealmByName(AuthRealm.TEST);
|
||||||
RealmModel realm = session.realms().getRealmByName(realmName);
|
|
||||||
UserModel user = session.users().getUserByUsername(FailableHardcodedStorageProvider.username, realm);
|
UserModel user = session.users().getUserByUsername(FailableHardcodedStorageProvider.username, realm);
|
||||||
Assert.assertFalse(user instanceof CachedUserModel);
|
Assert.assertFalse(user instanceof CachedUserModel);
|
||||||
Assert.assertEquals(FailableHardcodedStorageProvider.username, user.getUsername());
|
Assert.assertEquals(FailableHardcodedStorageProvider.username, user.getUsername());
|
||||||
Assert.assertEquals(FailableHardcodedStorageProvider.email, user.getEmail());
|
Assert.assertEquals(FailableHardcodedStorageProvider.email, user.getEmail());
|
||||||
keycloakRule.stopSession(session, true);
|
});
|
||||||
}
|
|
||||||
|
|
||||||
// make ABSOLUTELY sure user isn't cached as provider is disabled
|
// make ABSOLUTELY sure user isn't cached as provider is disabled
|
||||||
{
|
testingClient.server().run(session -> {
|
||||||
KeycloakSession session = keycloakRule.startSession();
|
RealmModel realm = session.realms().getRealmByName(AuthRealm.TEST);
|
||||||
RealmModel realm = session.realms().getRealmByName(realmName);
|
|
||||||
UserModel user = session.users().getUserByUsername(FailableHardcodedStorageProvider.username, realm);
|
UserModel user = session.users().getUserByUsername(FailableHardcodedStorageProvider.username, realm);
|
||||||
Assert.assertFalse(user instanceof CachedUserModel);
|
Assert.assertFalse(user instanceof CachedUserModel);
|
||||||
Assert.assertEquals(FailableHardcodedStorageProvider.username, user.getUsername());
|
Assert.assertEquals(FailableHardcodedStorageProvider.username, user.getUsername());
|
||||||
Assert.assertEquals(FailableHardcodedStorageProvider.email, user.getEmail());
|
Assert.assertEquals(FailableHardcodedStorageProvider.email, user.getEmail());
|
||||||
keycloakRule.stopSession(session, true);
|
});
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -349,15 +379,14 @@ public class UserStorageFailureTest {
|
||||||
toggleForceFail(false);
|
toggleForceFail(false);
|
||||||
|
|
||||||
// user should be cachable now
|
// user should be cachable now
|
||||||
{
|
testingClient.server().run(session -> {
|
||||||
KeycloakSession session = keycloakRule.startSession();
|
RealmModel realm = session.realms().getRealmByName(AuthRealm.TEST);
|
||||||
RealmModel realm = session.realms().getRealmByName(realmName);
|
|
||||||
UserModel user = session.users().getUserByUsername(FailableHardcodedStorageProvider.username, realm);
|
UserModel user = session.users().getUserByUsername(FailableHardcodedStorageProvider.username, realm);
|
||||||
Assert.assertTrue(user instanceof CachedUserModel);
|
Assert.assertTrue(user instanceof CachedUserModel);
|
||||||
Assert.assertEquals(FailableHardcodedStorageProvider.username, user.getUsername());
|
Assert.assertEquals(FailableHardcodedStorageProvider.username, user.getUsername());
|
||||||
Assert.assertEquals(FailableHardcodedStorageProvider.email, user.getEmail());
|
Assert.assertEquals(FailableHardcodedStorageProvider.email, user.getEmail());
|
||||||
keycloakRule.stopSession(session, true);
|
});
|
||||||
}
|
|
||||||
|
|
||||||
events.clear();
|
events.clear();
|
||||||
}
|
}
|
|
@ -28,8 +28,13 @@ import static org.junit.Assert.fail;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.keycloak.admin.client.resource.RealmResource;
|
||||||
import org.keycloak.admin.client.resource.UserResource;
|
import org.keycloak.admin.client.resource.UserResource;
|
||||||
import org.keycloak.common.util.MultivaluedHashMap;
|
import org.keycloak.common.util.MultivaluedHashMap;
|
||||||
|
import org.keycloak.component.ComponentModel;
|
||||||
|
import org.keycloak.credential.CredentialAuthentication;
|
||||||
|
import org.keycloak.credential.UserCredentialStoreManager;
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
import static org.keycloak.models.UserModel.RequiredAction.UPDATE_PROFILE;
|
import static org.keycloak.models.UserModel.RequiredAction.UPDATE_PROFILE;
|
||||||
|
@ -48,6 +53,7 @@ import static org.keycloak.storage.UserStorageProviderModel.EVICTION_MINUTE;
|
||||||
import static org.keycloak.storage.UserStorageProviderModel.MAX_LIFESPAN;
|
import static org.keycloak.storage.UserStorageProviderModel.MAX_LIFESPAN;
|
||||||
import org.keycloak.testsuite.AbstractAuthTest;
|
import org.keycloak.testsuite.AbstractAuthTest;
|
||||||
import org.keycloak.testsuite.admin.ApiUtil;
|
import org.keycloak.testsuite.admin.ApiUtil;
|
||||||
|
import org.keycloak.testsuite.arquillian.annotation.ModelTest;
|
||||||
import org.keycloak.testsuite.federation.UserMapStorage;
|
import org.keycloak.testsuite.federation.UserMapStorage;
|
||||||
import org.keycloak.testsuite.federation.UserMapStorageFactory;
|
import org.keycloak.testsuite.federation.UserMapStorageFactory;
|
||||||
import org.keycloak.testsuite.federation.UserPropertyFileStorageFactory;
|
import org.keycloak.testsuite.federation.UserPropertyFileStorageFactory;
|
||||||
|
@ -61,6 +67,8 @@ import java.util.Map;
|
||||||
import javax.mail.internet.MimeMessage;
|
import javax.mail.internet.MimeMessage;
|
||||||
import org.jboss.arquillian.graphene.page.Page;
|
import org.jboss.arquillian.graphene.page.Page;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
|
import org.keycloak.testsuite.util.TestCleanup;
|
||||||
|
|
||||||
import static org.keycloak.testsuite.actions.RequiredActionEmailVerificationTest.getPasswordResetEmailLink;
|
import static org.keycloak.testsuite.actions.RequiredActionEmailVerificationTest.getPasswordResetEmailLink;
|
||||||
import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlDoesntStartWith;
|
import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlDoesntStartWith;
|
||||||
import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
|
import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
|
||||||
|
@ -154,11 +162,15 @@ public class UserStorageTest extends AbstractAuthTest {
|
||||||
return propProviderRW;
|
return propProviderRW;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String addComponent(ComponentRepresentation component) {
|
private String addComponent(ComponentRepresentation component) {
|
||||||
Response resp = testRealmResource().components().add(component);
|
return addComponent(testRealmResource(), getCleanup(), component);
|
||||||
|
}
|
||||||
|
|
||||||
|
static String addComponent(RealmResource realmResource, TestCleanup testCleanup, ComponentRepresentation component) {
|
||||||
|
Response resp = realmResource.components().add(component);
|
||||||
resp.close();
|
resp.close();
|
||||||
String id = ApiUtil.getCreatedId(resp);
|
String id = ApiUtil.getCreatedId(resp);
|
||||||
getCleanup().addComponentId(id);
|
testCleanup.addComponentId(id);
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,6 +195,17 @@ public class UserStorageTest extends AbstractAuthTest {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* KEYCLOAK-4013
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
@ModelTest
|
||||||
|
public void testCast(KeycloakSession session) throws Exception {
|
||||||
|
List<CredentialAuthentication> list = UserCredentialStoreManager.getCredentialProviders(session, null, CredentialAuthentication.class);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLoginSuccess() {
|
public void testLoginSuccess() {
|
||||||
loginSuccessAndLogout("tbrady", "goat");
|
loginSuccessAndLogout("tbrady", "goat");
|
||||||
|
@ -416,13 +439,28 @@ public class UserStorageTest extends AbstractAuthTest {
|
||||||
Assert.assertTrue(usernames.contains("thor"));
|
Assert.assertTrue(usernames.contains("thor"));
|
||||||
|
|
||||||
// search by single attribute
|
// search by single attribute
|
||||||
// FIXME - no equivalent for model in REST
|
testingClient.server().run(session -> {
|
||||||
|
System.out.println("search by single attribute");
|
||||||
|
|
||||||
|
RealmModel realm = session.realms().getRealmByName("test");
|
||||||
|
UserModel userModel = session.users().getUserByUsername("thor", realm);
|
||||||
|
userModel.setSingleAttribute("weapon", "hammer");
|
||||||
|
|
||||||
|
List<UserModel> userModels = session.users().searchForUserByUserAttribute("weapon", "hammer", realm);
|
||||||
|
for (UserModel u : userModels) {
|
||||||
|
System.out.println(u.getUsername());
|
||||||
|
|
||||||
|
}
|
||||||
|
Assert.assertEquals(1, userModels.size());
|
||||||
|
Assert.assertEquals("thor", userModels.get(0).getUsername());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deployment
|
@Deployment
|
||||||
public static WebArchive deploy() {
|
public static WebArchive deploy() {
|
||||||
return RunOnServerDeployment.create(UserResource.class)
|
return RunOnServerDeployment.create(UserResource.class)
|
||||||
.addPackages(true, "org.keycloak.testsuite");
|
.addPackages(true, "org.keycloak.testsuite")
|
||||||
|
.addPackages(true, "org.keycloak.admin.client.resource");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setDailyEvictionTime(int hour, int minutes) {
|
private void setDailyEvictionTime(int hour, int minutes) {
|
||||||
|
@ -677,6 +715,26 @@ public class UserStorageTest extends AbstractAuthTest {
|
||||||
System.out.println("User class: " + user.getClass());
|
System.out.println("User class: " + user.getClass());
|
||||||
Assert.assertFalse(user instanceof CachedUserModel); // should be evicted
|
Assert.assertFalse(user instanceof CachedUserModel); // should be evicted
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
testingClient.server().run(session -> {
|
||||||
|
RealmModel realm = session.realms().getRealmByName("test");
|
||||||
|
UserModel thor2 = session.users().getUserByUsername("thor", realm);
|
||||||
|
Assert.assertFalse(thor2 instanceof CachedUserModel);
|
||||||
|
});
|
||||||
|
|
||||||
|
propProviderRW = testRealmResource().components().component(propProviderRWId).toRepresentation();
|
||||||
|
propProviderRW.getConfig().putSingle(CACHE_POLICY, CachePolicy.DEFAULT.name());
|
||||||
|
propProviderRW.getConfig().remove("evictionHour");
|
||||||
|
propProviderRW.getConfig().remove("evictionMinute");
|
||||||
|
propProviderRW.getConfig().remove("evictionDay");
|
||||||
|
testRealmResource().components().component(propProviderRWId).update(propProviderRW);
|
||||||
|
|
||||||
|
testingClient.server().run(session -> {
|
||||||
|
RealmModel realm = session.realms().getRealmByName("test");
|
||||||
|
UserModel thor = session.users().getUserByUsername("thor", realm);
|
||||||
|
System.out.println("Foo");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -0,0 +1,338 @@
|
||||||
|
/*
|
||||||
|
* 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.federation.sync;
|
||||||
|
|
||||||
|
import org.jboss.arquillian.container.test.api.Deployment;
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
import org.jboss.shrinkwrap.api.spec.WebArchive;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.FixMethodOrder;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runners.MethodSorters;
|
||||||
|
import org.keycloak.admin.client.resource.RealmResource;
|
||||||
|
import org.keycloak.component.ComponentModel;
|
||||||
|
import org.keycloak.models.KeycloakSessionFactory;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.services.managers.UserStorageSyncManager;
|
||||||
|
import org.keycloak.storage.UserStorageProvider;
|
||||||
|
import org.keycloak.storage.UserStorageProviderModel;
|
||||||
|
import org.keycloak.storage.user.SynchronizationResult;
|
||||||
|
import org.keycloak.testsuite.AbstractAuthTest;
|
||||||
|
import org.keycloak.testsuite.auth.page.AuthRealm;
|
||||||
|
import org.keycloak.testsuite.federation.DummyUserFederationProviderFactory;
|
||||||
|
import org.keycloak.testsuite.federation.storage.ComponentExportImportTest;
|
||||||
|
import org.keycloak.testsuite.runonserver.RunOnServerDeployment;
|
||||||
|
import org.keycloak.timer.TimerProvider;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test with Dummy providers
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||||
|
public class SyncFederationTest extends AbstractAuthTest {
|
||||||
|
|
||||||
|
private static final Logger log = Logger.getLogger(SyncFederationTest.class);
|
||||||
|
|
||||||
|
@Deployment
|
||||||
|
public static WebArchive deploy() {
|
||||||
|
return RunOnServerDeployment.create(ComponentExportImportTest.class, AbstractAuthTest.class, RealmResource.class)
|
||||||
|
.addPackages(true, "org.keycloak.testsuite");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that period sync is triggered when creating a synchronized User Storage Provider
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void test01PeriodicSyncOnCreate() {
|
||||||
|
|
||||||
|
final Map<String, Integer> state = testingClient.server().fetch(session -> {
|
||||||
|
KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
|
||||||
|
DummyUserFederationProviderFactory dummyFedFactory = (DummyUserFederationProviderFactory) sessionFactory.getProviderFactory(UserStorageProvider.class, DummyUserFederationProviderFactory.PROVIDER_NAME);
|
||||||
|
|
||||||
|
int full = dummyFedFactory.getFullSyncCounter();
|
||||||
|
int changed = dummyFedFactory.getChangedSyncCounter();
|
||||||
|
|
||||||
|
Map<String, Integer> state1 = new HashMap<>();
|
||||||
|
state1.put("full", full);
|
||||||
|
state1.put("changed", changed);
|
||||||
|
return state1;
|
||||||
|
|
||||||
|
}, Map.class);
|
||||||
|
|
||||||
|
// Enable timer for SyncDummyUserFederationProvider
|
||||||
|
testingClient.server().run(session -> {
|
||||||
|
RealmModel appRealm = session.realms().getRealmByName(AuthRealm.TEST);
|
||||||
|
|
||||||
|
UserStorageProviderModel model = new UserStorageProviderModel();
|
||||||
|
model.setProviderId(DummyUserFederationProviderFactory.PROVIDER_NAME);
|
||||||
|
model.setPriority(1);
|
||||||
|
model.setName("test-sync-dummy");
|
||||||
|
model.setFullSyncPeriod(-1);
|
||||||
|
model.setChangedSyncPeriod(1);
|
||||||
|
model.setLastSync(0);
|
||||||
|
ComponentModel dummyModel = new UserStorageProviderModel(appRealm.addComponentModel(model));
|
||||||
|
});
|
||||||
|
|
||||||
|
testingClient.server().run(session -> {
|
||||||
|
RealmModel appRealm = session.realms().getRealmByName(AuthRealm.TEST);
|
||||||
|
UserStorageProviderModel dummyModel = findDummyProviderModel(appRealm);
|
||||||
|
KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
|
||||||
|
DummyUserFederationProviderFactory dummyFedFactory = (DummyUserFederationProviderFactory) sessionFactory.getProviderFactory(UserStorageProvider.class, DummyUserFederationProviderFactory.PROVIDER_NAME);
|
||||||
|
|
||||||
|
// Assert that after some period was DummyUserFederationProvider triggered
|
||||||
|
UserStorageSyncManager usersSyncManager = new UserStorageSyncManager();
|
||||||
|
sleep(1800);
|
||||||
|
|
||||||
|
// Cancel timer
|
||||||
|
usersSyncManager.notifyToRefreshPeriodicSync(session, appRealm, dummyModel, true);
|
||||||
|
log.infof("Notified sync manager about cancel periodic sync");
|
||||||
|
|
||||||
|
// This sync is here just to ensure that we have lock (doublecheck that periodic sync, which was possibly triggered before canceling timer is finished too)
|
||||||
|
while (true) {
|
||||||
|
SynchronizationResult result = usersSyncManager.syncChangedUsers(session.getKeycloakSessionFactory(), appRealm.getId(), dummyModel);
|
||||||
|
if (result.isIgnored()) {
|
||||||
|
log.infof("Still waiting for lock before periodic sync is finished", result.toString());
|
||||||
|
sleep(1000);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int full = state.get("full");
|
||||||
|
int changed = state.get("changed");
|
||||||
|
|
||||||
|
// Assert that DummyUserFederationProviderFactory.syncChangedUsers was invoked at least 2 times (once periodically and once for us)
|
||||||
|
int newChanged = dummyFedFactory.getChangedSyncCounter();
|
||||||
|
Assert.assertEquals(full, dummyFedFactory.getFullSyncCounter());
|
||||||
|
Assert.assertTrue("Assertion failed. newChanged=" + newChanged + ", changed=" + changed, newChanged > (changed + 1));
|
||||||
|
|
||||||
|
// Assert that dummy provider won't be invoked anymore
|
||||||
|
sleep(1800);
|
||||||
|
Assert.assertEquals(full, dummyFedFactory.getFullSyncCounter());
|
||||||
|
int newestChanged = dummyFedFactory.getChangedSyncCounter();
|
||||||
|
Assert.assertEquals("Assertion failed. newChanged=" + newChanged + ", newestChanged=" + newestChanged, newChanged, newestChanged);
|
||||||
|
});
|
||||||
|
|
||||||
|
// remove dummyProvider
|
||||||
|
testingClient.server().run(session -> {
|
||||||
|
RealmModel appRealm = session.realms().getRealmByName(AuthRealm.TEST);
|
||||||
|
UserStorageProviderModel dummyModel = findDummyProviderModel(appRealm);
|
||||||
|
appRealm.removeComponent(dummyModel);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static final UserStorageProviderModel findDummyProviderModel(RealmModel realm) {
|
||||||
|
for (ComponentModel component : realm.getComponents()) {
|
||||||
|
if ("test-sync-dummy".equals(component.getName())) {
|
||||||
|
return new UserStorageProviderModel(component);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that period sync is triggered when updating a synchronized User Storage Provider to have a non-negative sync period
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void test02PeriodicSyncOnUpdate() {
|
||||||
|
|
||||||
|
final Map<String, Integer> state = testingClient.server().fetch(session -> {
|
||||||
|
|
||||||
|
KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
|
||||||
|
DummyUserFederationProviderFactory dummyFedFactory = (DummyUserFederationProviderFactory) sessionFactory.getProviderFactory(UserStorageProvider.class, DummyUserFederationProviderFactory.PROVIDER_NAME);
|
||||||
|
|
||||||
|
int full = dummyFedFactory.getFullSyncCounter();
|
||||||
|
int changed = dummyFedFactory.getChangedSyncCounter();
|
||||||
|
|
||||||
|
Map<String, Integer> state1 = new HashMap<>();
|
||||||
|
state1.put("full", full);
|
||||||
|
state1.put("changed", changed);
|
||||||
|
return state1;
|
||||||
|
|
||||||
|
}, Map.class);
|
||||||
|
|
||||||
|
|
||||||
|
// Configure sync without timer for SyncDummyUserFederationProvider
|
||||||
|
testingClient.server().run(session -> {
|
||||||
|
RealmModel appRealm = session.realms().getRealmByName(AuthRealm.TEST);
|
||||||
|
|
||||||
|
UserStorageProviderModel model = new UserStorageProviderModel();
|
||||||
|
model.setProviderId(DummyUserFederationProviderFactory.PROVIDER_NAME);
|
||||||
|
model.setPriority(1);
|
||||||
|
model.setName("test-sync-dummy");
|
||||||
|
model.setFullSyncPeriod(-1);
|
||||||
|
model.setChangedSyncPeriod(-1);
|
||||||
|
model.setLastSync(0);
|
||||||
|
ComponentModel dummyModel = new UserStorageProviderModel(appRealm.addComponentModel(model));
|
||||||
|
});
|
||||||
|
|
||||||
|
testingClient.server().run(session -> {
|
||||||
|
KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
|
||||||
|
DummyUserFederationProviderFactory dummyFedFactory = (DummyUserFederationProviderFactory) sessionFactory.getProviderFactory(UserStorageProvider.class, DummyUserFederationProviderFactory.PROVIDER_NAME);
|
||||||
|
|
||||||
|
// Assert that after some period was DummyUserFederationProvider triggered
|
||||||
|
UserStorageSyncManager usersSyncManager = new UserStorageSyncManager();
|
||||||
|
|
||||||
|
// Assert that dummy provider wasn't invoked anymore
|
||||||
|
sleep(1800);
|
||||||
|
|
||||||
|
int full = state.get("full");
|
||||||
|
int changed = state.get("changed");
|
||||||
|
|
||||||
|
Assert.assertEquals(full, dummyFedFactory.getFullSyncCounter());
|
||||||
|
int newChanged = dummyFedFactory.getChangedSyncCounter();
|
||||||
|
Assert.assertEquals("Assertion failed. changed=" + changed + ", newChanged=" + newChanged, changed, newChanged);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Re-enable periodic sync for changed users
|
||||||
|
testingClient.server().run(session -> {
|
||||||
|
RealmModel appRealm = session.realms().getRealmByName(AuthRealm.TEST);
|
||||||
|
UserStorageProviderModel dummyModel = findDummyProviderModel(appRealm);
|
||||||
|
|
||||||
|
dummyModel.setChangedSyncPeriod(1);
|
||||||
|
appRealm.updateComponent(dummyModel);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
testingClient.server().run(session -> {
|
||||||
|
RealmModel appRealm = session.realms().getRealmByName(AuthRealm.TEST);
|
||||||
|
UserStorageProviderModel dummyModel = findDummyProviderModel(appRealm);
|
||||||
|
KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
|
||||||
|
DummyUserFederationProviderFactory dummyFedFactory = (DummyUserFederationProviderFactory) sessionFactory.getProviderFactory(UserStorageProvider.class, DummyUserFederationProviderFactory.PROVIDER_NAME);
|
||||||
|
|
||||||
|
// Assert that after some period was DummyUserFederationProvider triggered
|
||||||
|
UserStorageSyncManager usersSyncManager = new UserStorageSyncManager();
|
||||||
|
sleep(1800);
|
||||||
|
|
||||||
|
// Cancel timer
|
||||||
|
usersSyncManager.notifyToRefreshPeriodicSync(session, appRealm, dummyModel, true);
|
||||||
|
log.infof("Notified sync manager about cancel periodic sync");
|
||||||
|
|
||||||
|
// This sync is here just to ensure that we have lock (doublecheck that periodic sync, which was possibly triggered before canceling timer is finished too)
|
||||||
|
while (true) {
|
||||||
|
SynchronizationResult result = usersSyncManager.syncChangedUsers(session.getKeycloakSessionFactory(), appRealm.getId(), dummyModel);
|
||||||
|
if (result.isIgnored()) {
|
||||||
|
log.infof("Still waiting for lock before periodic sync is finished", result.toString());
|
||||||
|
sleep(1000);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int full = state.get("full");
|
||||||
|
int changed = state.get("changed");
|
||||||
|
|
||||||
|
// Assert that DummyUserFederationProviderFactory.syncChangedUsers was invoked at least 1 time
|
||||||
|
int newChanged = dummyFedFactory.getChangedSyncCounter();
|
||||||
|
Assert.assertEquals(full, dummyFedFactory.getFullSyncCounter());
|
||||||
|
log.info("Asserting. newChanged=" + newChanged + " > changed=" + changed);
|
||||||
|
Assert.assertTrue("Assertion failed. newChanged=" + newChanged + ", changed=" + changed, newChanged > (changed + 1));
|
||||||
|
|
||||||
|
// Assert that dummy provider won't be invoked anymore
|
||||||
|
sleep(1800);
|
||||||
|
Assert.assertEquals(full, dummyFedFactory.getFullSyncCounter());
|
||||||
|
int newestChanged = dummyFedFactory.getChangedSyncCounter();
|
||||||
|
Assert.assertEquals("Assertion failed. newChanged=" + newChanged + ", newestChanged=" + newestChanged, newChanged, newestChanged);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// remove dummyProvider
|
||||||
|
testingClient.server().run(session -> {
|
||||||
|
RealmModel appRealm = session.realms().getRealmByName(AuthRealm.TEST);
|
||||||
|
UserStorageProviderModel dummyModel = findDummyProviderModel(appRealm);
|
||||||
|
appRealm.removeComponent(dummyModel);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test03ConcurrentSync() throws Exception {
|
||||||
|
// Enable timer for SyncDummyUserFederationProvider
|
||||||
|
testingClient.server().run(session -> {
|
||||||
|
SyncDummyUserFederationProviderFactory.restartLatches();
|
||||||
|
|
||||||
|
RealmModel appRealm = session.realms().getRealmByName(AuthRealm.TEST);
|
||||||
|
|
||||||
|
UserStorageProviderModel model = new UserStorageProviderModel();
|
||||||
|
model.setProviderId(SyncDummyUserFederationProviderFactory.SYNC_PROVIDER_ID);
|
||||||
|
model.setPriority(1);
|
||||||
|
model.setName("test-sync-dummy");
|
||||||
|
model.setFullSyncPeriod(-1);
|
||||||
|
model.setChangedSyncPeriod(1);
|
||||||
|
model.setLastSync(0);
|
||||||
|
model.getConfig().putSingle(SyncDummyUserFederationProviderFactory.WAIT_TIME, "2000");
|
||||||
|
ComponentModel dummyModel = new UserStorageProviderModel(appRealm.addComponentModel(model));
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
testingClient.server().run(session -> {
|
||||||
|
RealmModel appRealm = session.realms().getRealmByName(AuthRealm.TEST);
|
||||||
|
UserStorageProviderModel dummyModel = findDummyProviderModel(appRealm);
|
||||||
|
|
||||||
|
KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
|
||||||
|
|
||||||
|
// bootstrap periodic sync
|
||||||
|
UserStorageSyncManager usersSyncManager = new UserStorageSyncManager();
|
||||||
|
usersSyncManager.bootstrapPeriodic(sessionFactory, session.getProvider(TimerProvider.class));
|
||||||
|
|
||||||
|
// Wait and then trigger sync manually. Assert it will be ignored
|
||||||
|
sleep(1800);
|
||||||
|
SynchronizationResult syncResult = usersSyncManager.syncChangedUsers(sessionFactory, appRealm.getId(), dummyModel);
|
||||||
|
Assert.assertTrue(syncResult.isIgnored());
|
||||||
|
|
||||||
|
// Cancel timer
|
||||||
|
usersSyncManager.notifyToRefreshPeriodicSync(session, appRealm, dummyModel, true);
|
||||||
|
|
||||||
|
// Signal to factory to finish waiting
|
||||||
|
SyncDummyUserFederationProviderFactory.latch1.countDown();
|
||||||
|
|
||||||
|
try {
|
||||||
|
SyncDummyUserFederationProviderFactory.latch2.await(20000, TimeUnit.MILLISECONDS);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// remove provider
|
||||||
|
testingClient.server().run(session -> {
|
||||||
|
RealmModel appRealm = session.realms().getRealmByName(AuthRealm.TEST);
|
||||||
|
UserStorageProviderModel dummyModel = findDummyProviderModel(appRealm);
|
||||||
|
appRealm.removeComponent(dummyModel);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static void sleep(long ms) {
|
||||||
|
try {
|
||||||
|
log.infof("Sleeping for %d ms", ms);
|
||||||
|
Thread.sleep(ms);
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
throw new RuntimeException(ie);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,6 +13,8 @@
|
||||||
<module name="org.keycloak.keycloak-kerberos-federation"/>
|
<module name="org.keycloak.keycloak-kerberos-federation"/>
|
||||||
<module name="org.keycloak.keycloak-ldap-federation"/>
|
<module name="org.keycloak.keycloak-ldap-federation"/>
|
||||||
<module name="org.infinispan"/>
|
<module name="org.infinispan"/>
|
||||||
|
<module name="org.apache.commons.io"/>
|
||||||
|
<module name="org.apache.httpcomponents.core"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</deployment>
|
</deployment>
|
||||||
</jboss-deployment-structure>
|
</jboss-deployment-structure>
|
||||||
|
|
|
@ -1,140 +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.federation.storage;
|
|
||||||
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.ClassRule;
|
|
||||||
import org.junit.Rule;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.keycloak.OAuth2Constants;
|
|
||||||
import org.keycloak.admin.client.Keycloak;
|
|
||||||
import org.keycloak.admin.client.resource.RealmResource;
|
|
||||||
import org.keycloak.common.util.Time;
|
|
||||||
import org.keycloak.component.ComponentModel;
|
|
||||||
import org.keycloak.models.Constants;
|
|
||||||
import org.keycloak.models.GroupModel;
|
|
||||||
import org.keycloak.models.KeycloakSession;
|
|
||||||
import org.keycloak.models.RealmModel;
|
|
||||||
import org.keycloak.models.RoleModel;
|
|
||||||
import org.keycloak.models.UserCredentialModel;
|
|
||||||
import org.keycloak.models.UserModel;
|
|
||||||
import org.keycloak.models.cache.CachedUserModel;
|
|
||||||
import org.keycloak.models.cache.infinispan.UserAdapter;
|
|
||||||
import org.keycloak.models.jpa.RealmAdapter;
|
|
||||||
import org.keycloak.representations.idm.ComponentRepresentation;
|
|
||||||
import org.keycloak.services.managers.RealmManager;
|
|
||||||
import org.keycloak.storage.StorageId;
|
|
||||||
import org.keycloak.storage.UserStorageProvider;
|
|
||||||
import org.keycloak.storage.UserStorageProviderModel;
|
|
||||||
import org.keycloak.testsuite.ApplicationServlet;
|
|
||||||
import org.keycloak.testsuite.OAuthClient;
|
|
||||||
import org.keycloak.testsuite.pages.AppPage;
|
|
||||||
import org.keycloak.testsuite.pages.LoginPage;
|
|
||||||
import org.keycloak.testsuite.rule.KeycloakRule;
|
|
||||||
import org.keycloak.testsuite.rule.WebResource;
|
|
||||||
import org.keycloak.testsuite.rule.WebRule;
|
|
||||||
import org.openqa.selenium.WebDriver;
|
|
||||||
|
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* KEYCLOAK-3903 and KEYCLOAK-3620
|
|
||||||
*
|
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
|
||||||
* @version $Revision: 1 $
|
|
||||||
*/
|
|
||||||
public class BrokenUserStorageTest {
|
|
||||||
@ClassRule
|
|
||||||
public static KeycloakRule keycloakRule = new KeycloakRule();
|
|
||||||
|
|
||||||
@Rule
|
|
||||||
public WebRule webRule = new WebRule(this);
|
|
||||||
|
|
||||||
@WebResource
|
|
||||||
protected OAuthClient oauth;
|
|
||||||
|
|
||||||
@WebResource
|
|
||||||
protected WebDriver driver;
|
|
||||||
|
|
||||||
@WebResource
|
|
||||||
protected AppPage appPage;
|
|
||||||
|
|
||||||
@WebResource
|
|
||||||
protected LoginPage loginPage;
|
|
||||||
|
|
||||||
private void loginSuccessAndLogout(String username, String password) {
|
|
||||||
loginPage.open();
|
|
||||||
loginPage.login(username, password);
|
|
||||||
Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
|
||||||
Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
|
|
||||||
oauth.openLogout();
|
|
||||||
}
|
|
||||||
protected String AUTH_SERVER_URL = "http://localhost:8081/auth";
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testBootWithBadProviderId() throws Exception {
|
|
||||||
KeycloakSession session = keycloakRule.startSession();
|
|
||||||
// set this system property
|
|
||||||
System.setProperty(RealmAdapter.COMPONENT_PROVIDER_EXISTS_DISABLED, "true");
|
|
||||||
RealmModel realm = session.realms().getRealmByName("master");
|
|
||||||
String masterId = realm.getId();
|
|
||||||
UserStorageProviderModel model;
|
|
||||||
model = new UserStorageProviderModel();
|
|
||||||
model.setName("bad-provider-id");
|
|
||||||
model.setPriority(2);
|
|
||||||
model.setParentId(realm.getId());
|
|
||||||
model.setProviderId("error");
|
|
||||||
ComponentModel component = realm.importComponentModel(model);
|
|
||||||
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
|
|
||||||
keycloakRule.restartServer();
|
|
||||||
keycloakRule.deployServlet("app", "/app", ApplicationServlet.class);
|
|
||||||
|
|
||||||
loginSuccessAndLogout("test-user@localhost", "password");
|
|
||||||
|
|
||||||
// make sure we can list components and delete provider as this is an admin console operation
|
|
||||||
|
|
||||||
try (Keycloak keycloakAdmin = Keycloak.getInstance(AUTH_SERVER_URL, "master", "admin", "admin", Constants.ADMIN_CLI_CLIENT_ID)) {
|
|
||||||
RealmResource master = keycloakAdmin.realms().realm("master");
|
|
||||||
List<ComponentRepresentation> components = master.components().query(masterId, UserStorageProvider.class.getName());
|
|
||||||
boolean found = false;
|
|
||||||
for (ComponentRepresentation rep : components) {
|
|
||||||
if (rep.getName().equals("bad-provider-id")) {
|
|
||||||
found = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Assert.assertTrue(found);
|
|
||||||
|
|
||||||
master.components().component(component.getId()).remove();
|
|
||||||
|
|
||||||
List<ComponentRepresentation> components2 = master.components().query(masterId, UserStorageProvider.class.getName());
|
|
||||||
Assert.assertEquals(components.size() - 1, components2.size());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
|
||||||
public void resetTimeoffset() {
|
|
||||||
Time.setOffset(0);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,159 +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.federation.storage;
|
|
||||||
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.BeforeClass;
|
|
||||||
import org.junit.ClassRule;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.keycloak.component.ComponentModel;
|
|
||||||
import org.keycloak.exportimport.ExportImportConfig;
|
|
||||||
import org.keycloak.exportimport.ExportImportManager;
|
|
||||||
import org.keycloak.exportimport.singlefile.SingleFileExportProviderFactory;
|
|
||||||
import org.keycloak.models.KeycloakSession;
|
|
||||||
import org.keycloak.models.RealmModel;
|
|
||||||
import org.keycloak.services.managers.RealmManager;
|
|
||||||
import org.keycloak.storage.UserStorageProvider;
|
|
||||||
import org.keycloak.testsuite.rule.KeycloakRule;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Properties;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
|
||||||
* @version $Revision: 1 $
|
|
||||||
*/
|
|
||||||
public class ComponentExportImportTest {
|
|
||||||
@ClassRule
|
|
||||||
public static KeycloakRule keycloakRule = new KeycloakRule(new KeycloakRule.KeycloakSetup() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
public static String basePath = null;
|
|
||||||
|
|
||||||
@BeforeClass
|
|
||||||
public static void setDirs() {
|
|
||||||
basePath = new File(System.getProperty("project.build.directory", "target")).getAbsolutePath();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
|
||||||
public void cleanup() {
|
|
||||||
KeycloakSession session = keycloakRule.startSession();
|
|
||||||
RealmModel realm = session.realms().getRealmByName("exported-component");
|
|
||||||
if (realm != null) {
|
|
||||||
session.realms().removeRealm(realm.getId());
|
|
||||||
}
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSingleFile() throws Exception {
|
|
||||||
clearExportImportProperties();
|
|
||||||
KeycloakSession session = keycloakRule.startSession();
|
|
||||||
RealmModel realm = new RealmManager(session).createRealm("exported-component");
|
|
||||||
String realmId = realm.getId();
|
|
||||||
ComponentModel component = new ComponentModel();
|
|
||||||
component.setParentId(realm.getId());
|
|
||||||
component.setProviderId(UserMapStorageFactory.PROVIDER_ID);
|
|
||||||
component.setProviderType(UserStorageProvider.class.getName());
|
|
||||||
component.setName("parent");
|
|
||||||
component.setSubType("subtype");
|
|
||||||
component.put("attr", "value");
|
|
||||||
component = realm.addComponentModel(component);
|
|
||||||
ComponentModel subComponent = new ComponentModel();
|
|
||||||
subComponent.setParentId(component.getId());
|
|
||||||
subComponent.setProviderId(UserMapStorageFactory.PROVIDER_ID);
|
|
||||||
subComponent.setProviderType(UserStorageProvider.class.getName());
|
|
||||||
subComponent.setName("child");
|
|
||||||
subComponent.setSubType("subtype2");
|
|
||||||
subComponent.put("attr", "value2");
|
|
||||||
subComponent = realm.addComponentModel(subComponent);
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
String targetFilePath = basePath + File.separator + "singleFile-full.json";
|
|
||||||
System.out.println("export file: " + targetFilePath);
|
|
||||||
session = keycloakRule.startSession();
|
|
||||||
ExportImportConfig.setProvider(SingleFileExportProviderFactory.PROVIDER_ID);
|
|
||||||
ExportImportConfig.setFile(targetFilePath);
|
|
||||||
ExportImportConfig.setRealmName("exported-component");
|
|
||||||
ExportImportConfig.setAction(ExportImportConfig.ACTION_EXPORT);
|
|
||||||
new ExportImportManager(session).runExport();
|
|
||||||
session.realms().removeRealm(realmId);
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
|
|
||||||
session = keycloakRule.startSession();
|
|
||||||
Assert.assertNull(session.realms().getRealmByName("exported-component"));
|
|
||||||
ExportImportConfig.setAction(ExportImportConfig.ACTION_IMPORT);
|
|
||||||
new ExportImportManager(session).runImport();
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
|
|
||||||
session = keycloakRule.startSession();
|
|
||||||
realm = session.realms().getRealmByName("exported-component");
|
|
||||||
Assert.assertNotNull(realm);
|
|
||||||
component = realm.getComponent(component.getId());
|
|
||||||
Assert.assertNotNull(component);
|
|
||||||
Assert.assertEquals(component.getParentId(), realm.getId());
|
|
||||||
Assert.assertEquals(component.getName(), "parent");
|
|
||||||
Assert.assertEquals(component.getSubType(), "subtype");
|
|
||||||
Assert.assertEquals(component.getProviderId(), UserMapStorageFactory.PROVIDER_ID);
|
|
||||||
Assert.assertEquals(component.getProviderType(), UserStorageProvider.class.getName());
|
|
||||||
Assert.assertEquals(component.getConfig().getFirst("attr"), "value");
|
|
||||||
subComponent = realm.getComponents(component.getId()).get(0);
|
|
||||||
Assert.assertEquals(subComponent.getParentId(), component.getId());
|
|
||||||
Assert.assertEquals(subComponent.getName(), "child");
|
|
||||||
Assert.assertEquals(subComponent.getSubType(), "subtype2");
|
|
||||||
Assert.assertEquals(subComponent.getProviderId(), UserMapStorageFactory.PROVIDER_ID);
|
|
||||||
Assert.assertEquals(subComponent.getProviderType(), UserStorageProvider.class.getName());
|
|
||||||
Assert.assertEquals(subComponent.getConfig().getFirst("attr"), "value2");
|
|
||||||
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void clearExportImportProperties() {
|
|
||||||
// Clear export/import properties after test
|
|
||||||
Properties systemProps = System.getProperties();
|
|
||||||
Set<String> propsToRemove = new HashSet<String>();
|
|
||||||
|
|
||||||
for (Object key : systemProps.keySet()) {
|
|
||||||
if (key.toString().startsWith(ExportImportConfig.PREFIX)) {
|
|
||||||
propsToRemove.add(key.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (String propToRemove : propsToRemove) {
|
|
||||||
systemProps.remove(propToRemove);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,242 +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.federation.storage;
|
|
||||||
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.BeforeClass;
|
|
||||||
import org.junit.ClassRule;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.keycloak.common.util.MultivaluedHashMap;
|
|
||||||
import org.keycloak.credential.CredentialModel;
|
|
||||||
import org.keycloak.credential.hash.PasswordHashProvider;
|
|
||||||
import org.keycloak.exportimport.ExportImportConfig;
|
|
||||||
import org.keycloak.exportimport.ExportImportManager;
|
|
||||||
import org.keycloak.exportimport.dir.DirExportProviderFactory;
|
|
||||||
import org.keycloak.exportimport.singlefile.SingleFileExportProviderFactory;
|
|
||||||
import org.keycloak.models.GroupModel;
|
|
||||||
import org.keycloak.models.KeycloakSession;
|
|
||||||
import org.keycloak.models.PasswordPolicy;
|
|
||||||
import org.keycloak.models.RealmModel;
|
|
||||||
import org.keycloak.models.RoleModel;
|
|
||||||
import org.keycloak.policy.HashAlgorithmPasswordPolicyProviderFactory;
|
|
||||||
import org.keycloak.services.managers.RealmManager;
|
|
||||||
import org.keycloak.testsuite.rule.KeycloakRule;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Properties;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
|
||||||
* @version $Revision: 1 $
|
|
||||||
*/
|
|
||||||
public class FederatedStorageExportImportTest {
|
|
||||||
@ClassRule
|
|
||||||
public static KeycloakRule keycloakRule = new KeycloakRule(new KeycloakRule.KeycloakSetup() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
public static String basePath = null;
|
|
||||||
|
|
||||||
@BeforeClass
|
|
||||||
public static void setDirs() {
|
|
||||||
basePath = new File(System.getProperty("project.build.directory", "target")).getAbsolutePath();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
|
||||||
public void cleanup() {
|
|
||||||
KeycloakSession session = keycloakRule.startSession();
|
|
||||||
RealmModel realm = session.realms().getRealmByName("exported");
|
|
||||||
if (realm != null) {
|
|
||||||
session.realms().removeRealm(realm.getId());
|
|
||||||
}
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected PasswordHashProvider getHashProvider(KeycloakSession session, PasswordPolicy policy) {
|
|
||||||
PasswordHashProvider hash = session.getProvider(PasswordHashProvider.class, policy.getHashAlgorithm());
|
|
||||||
if (hash == null) {
|
|
||||||
return session.getProvider(PasswordHashProvider.class, PasswordPolicy.HASH_ALGORITHM_DEFAULT);
|
|
||||||
}
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSingleFile() throws Exception {
|
|
||||||
clearExportImportProperties();
|
|
||||||
KeycloakSession session = keycloakRule.startSession();
|
|
||||||
RealmModel realm = new RealmManager(session).createRealm("exported");
|
|
||||||
String realmId = realm.getId();
|
|
||||||
RoleModel role = realm.addRole("test-role");
|
|
||||||
GroupModel group = realm.createGroup("test-group");
|
|
||||||
String groupId = group.getId();
|
|
||||||
String userId = "f:1:path";
|
|
||||||
List<String> attrValues = new LinkedList<>();
|
|
||||||
attrValues.add("1");
|
|
||||||
attrValues.add("2");
|
|
||||||
session.userFederatedStorage().setSingleAttribute(realm, userId, "single1", "value1");
|
|
||||||
session.userFederatedStorage().setAttribute(realm, userId, "list1", attrValues);
|
|
||||||
session.userFederatedStorage().addRequiredAction(realm, userId, "UPDATE_PASSWORD");
|
|
||||||
CredentialModel credential = new CredentialModel();
|
|
||||||
getHashProvider(session, realm.getPasswordPolicy()).encode("password", realm.
|
|
||||||
getPasswordPolicy().getHashIterations(), credential);
|
|
||||||
session.userFederatedStorage().createCredential(realm, userId, credential);
|
|
||||||
session.userFederatedStorage().grantRole(realm, userId, role);
|
|
||||||
session.userFederatedStorage().joinGroup(realm, userId, group);
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
String targetFilePath = basePath + File.separator + "singleFile-full.json";
|
|
||||||
System.out.println("export file: " + targetFilePath);
|
|
||||||
session = keycloakRule.startSession();
|
|
||||||
ExportImportConfig.setProvider(SingleFileExportProviderFactory.PROVIDER_ID);
|
|
||||||
ExportImportConfig.setFile(targetFilePath);
|
|
||||||
ExportImportConfig.setRealmName("exported");
|
|
||||||
ExportImportConfig.setAction(ExportImportConfig.ACTION_EXPORT);
|
|
||||||
new ExportImportManager(session).runExport();
|
|
||||||
session.realms().removeRealm(realmId);
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
|
|
||||||
session = keycloakRule.startSession();
|
|
||||||
Assert.assertNull(session.realms().getRealmByName("exported"));
|
|
||||||
ExportImportConfig.setAction(ExportImportConfig.ACTION_IMPORT);
|
|
||||||
new ExportImportManager(session).runImport();
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
|
|
||||||
session = keycloakRule.startSession();
|
|
||||||
realm = session.realms().getRealmByName("exported");
|
|
||||||
Assert.assertNotNull(realm);
|
|
||||||
role = realm.getRole("test-role");
|
|
||||||
group = realm.getGroupById(groupId);
|
|
||||||
|
|
||||||
Assert.assertEquals(1, session.userFederatedStorage().getStoredUsersCount(realm));
|
|
||||||
MultivaluedHashMap<String, String> attributes = session.userFederatedStorage().getAttributes(realm, userId);
|
|
||||||
Assert.assertEquals(3, attributes.size());
|
|
||||||
Assert.assertEquals("value1", attributes.getFirst("single1"));
|
|
||||||
Assert.assertTrue(attributes.getList("list1").contains("1"));
|
|
||||||
Assert.assertTrue(attributes.getList("list1").contains("2"));
|
|
||||||
Assert.assertTrue(session.userFederatedStorage().getRequiredActions(realm, userId).contains("UPDATE_PASSWORD"));
|
|
||||||
Assert.assertTrue(session.userFederatedStorage().getRoleMappings(realm, userId).contains(role));
|
|
||||||
Assert.assertTrue(session.userFederatedStorage().getGroups(realm, userId).contains(group));
|
|
||||||
List<CredentialModel> creds = session.userFederatedStorage().getStoredCredentials(realm, userId);
|
|
||||||
Assert.assertEquals(1, creds.size());
|
|
||||||
Assert.assertTrue(getHashProvider(session, realm.getPasswordPolicy()).verify("password", creds.get(0)));
|
|
||||||
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testDir() throws Exception {
|
|
||||||
clearExportImportProperties();
|
|
||||||
KeycloakSession session = keycloakRule.startSession();
|
|
||||||
RealmModel realm = new RealmManager(session).createRealm("exported");
|
|
||||||
String realmId = realm.getId();
|
|
||||||
RoleModel role = realm.addRole("test-role");
|
|
||||||
GroupModel group = realm.createGroup("test-group");
|
|
||||||
String groupId = group.getId();
|
|
||||||
String userId = "f:1:path";
|
|
||||||
List<String> attrValues = new LinkedList<>();
|
|
||||||
attrValues.add("1");
|
|
||||||
attrValues.add("2");
|
|
||||||
session.userFederatedStorage().setSingleAttribute(realm, userId, "single1", "value1");
|
|
||||||
session.userFederatedStorage().setAttribute(realm, userId, "list1", attrValues);
|
|
||||||
session.userFederatedStorage().addRequiredAction(realm, userId, "UPDATE_PASSWORD");
|
|
||||||
CredentialModel credential = new CredentialModel();
|
|
||||||
getHashProvider(session, realm.getPasswordPolicy()).encode("password", realm.
|
|
||||||
getPasswordPolicy().getHashIterations(), credential);
|
|
||||||
session.userFederatedStorage().createCredential(realm, userId, credential);
|
|
||||||
session.userFederatedStorage().grantRole(realm, userId, role);
|
|
||||||
session.userFederatedStorage().joinGroup(realm, userId, group);
|
|
||||||
session.userFederatedStorage().setNotBeforeForUser(realm, userId, 50);
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
String targetFilePath = basePath + File.separator + "dirExport";
|
|
||||||
session = keycloakRule.startSession();
|
|
||||||
ExportImportConfig.setProvider(DirExportProviderFactory.PROVIDER_ID);
|
|
||||||
ExportImportConfig.setDir(targetFilePath);
|
|
||||||
ExportImportConfig.setRealmName("exported");
|
|
||||||
ExportImportConfig.setAction(ExportImportConfig.ACTION_EXPORT);
|
|
||||||
new ExportImportManager(session).runExport();
|
|
||||||
session.realms().removeRealm(realmId);
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
|
|
||||||
session = keycloakRule.startSession();
|
|
||||||
Assert.assertNull(session.realms().getRealmByName("exported"));
|
|
||||||
ExportImportConfig.setAction(ExportImportConfig.ACTION_IMPORT);
|
|
||||||
new ExportImportManager(session).runImport();
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
|
|
||||||
session = keycloakRule.startSession();
|
|
||||||
realm = session.realms().getRealmByName("exported");
|
|
||||||
Assert.assertNotNull(realm);
|
|
||||||
role = realm.getRole("test-role");
|
|
||||||
group = realm.getGroupById(groupId);
|
|
||||||
|
|
||||||
Assert.assertEquals(1, session.userFederatedStorage().getStoredUsersCount(realm));
|
|
||||||
MultivaluedHashMap<String, String> attributes = session.userFederatedStorage().getAttributes(realm, userId);
|
|
||||||
Assert.assertEquals(3, attributes.size());
|
|
||||||
Assert.assertEquals("value1", attributes.getFirst("single1"));
|
|
||||||
Assert.assertTrue(attributes.getList("list1").contains("1"));
|
|
||||||
Assert.assertTrue(attributes.getList("list1").contains("2"));
|
|
||||||
Assert.assertTrue(session.userFederatedStorage().getRequiredActions(realm, userId).contains("UPDATE_PASSWORD"));
|
|
||||||
Assert.assertTrue(session.userFederatedStorage().getRoleMappings(realm, userId).contains(role));
|
|
||||||
Assert.assertTrue(session.userFederatedStorage().getGroups(realm, userId).contains(group));
|
|
||||||
Assert.assertEquals(50, session.userFederatedStorage().getNotBeforeOfUser(realm, userId));
|
|
||||||
List<CredentialModel> creds = session.userFederatedStorage().getStoredCredentials(realm, userId);
|
|
||||||
Assert.assertEquals(1, creds.size());
|
|
||||||
Assert.assertTrue(getHashProvider(session, realm.getPasswordPolicy()).verify("password", creds.get(0)));
|
|
||||||
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clearExportImportProperties() {
|
|
||||||
// Clear export/import properties after test
|
|
||||||
Properties systemProps = System.getProperties();
|
|
||||||
Set<String> propsToRemove = new HashSet<String>();
|
|
||||||
|
|
||||||
for (Object key : systemProps.keySet()) {
|
|
||||||
if (key.toString().startsWith(ExportImportConfig.PREFIX)) {
|
|
||||||
propsToRemove.add(key.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (String propToRemove : propsToRemove) {
|
|
||||||
systemProps.remove(propToRemove);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
* Copyright 2017 Red Hat, Inc. and/or its affiliates
|
||||||
* and other contributors as indicated by the @author tags.
|
* and other contributors as indicated by the @author tags.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@ -16,6 +16,12 @@
|
||||||
*/
|
*/
|
||||||
package org.keycloak.testsuite.federation.storage;
|
package org.keycloak.testsuite.federation.storage;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
import org.keycloak.component.ComponentModel;
|
import org.keycloak.component.ComponentModel;
|
||||||
import org.keycloak.credential.CredentialInput;
|
import org.keycloak.credential.CredentialInput;
|
||||||
import org.keycloak.credential.CredentialInputUpdater;
|
import org.keycloak.credential.CredentialInputUpdater;
|
||||||
|
@ -33,23 +39,23 @@ import org.keycloak.storage.adapter.AbstractUserAdapterFederatedStorage;
|
||||||
import org.keycloak.storage.user.UserLookupProvider;
|
import org.keycloak.storage.user.UserLookupProvider;
|
||||||
import org.keycloak.storage.user.UserRegistrationProvider;
|
import org.keycloak.storage.user.UserRegistrationProvider;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public class UserMapStorage implements UserLookupProvider, UserStorageProvider, UserRegistrationProvider, CredentialInputUpdater, CredentialInputValidator {
|
public class UserMapStorage implements UserLookupProvider, UserStorageProvider, UserRegistrationProvider, CredentialInputUpdater, CredentialInputValidator {
|
||||||
|
|
||||||
|
private static final Logger log = Logger.getLogger(UserMapStorage.class);
|
||||||
|
|
||||||
protected Map<String, String> userPasswords;
|
protected Map<String, String> userPasswords;
|
||||||
protected ComponentModel model;
|
protected ComponentModel model;
|
||||||
protected KeycloakSession session;
|
protected KeycloakSession session;
|
||||||
|
|
||||||
public static final AtomicInteger allocations = new AtomicInteger(0);
|
public static final AtomicInteger allocations = new AtomicInteger(0);
|
||||||
public static final AtomicInteger closings = new AtomicInteger(0);
|
public static final AtomicInteger closings = new AtomicInteger(0);
|
||||||
|
public static final AtomicInteger realmRemovals = new AtomicInteger(0);
|
||||||
|
public static final AtomicInteger groupRemovals = new AtomicInteger(0);
|
||||||
|
public static final AtomicInteger roleRemovals = new AtomicInteger(0);
|
||||||
|
|
||||||
public UserMapStorage(KeycloakSession session, ComponentModel model, Map<String, String> userPasswords) {
|
public UserMapStorage(KeycloakSession session, ComponentModel model, Map<String, String> userPasswords) {
|
||||||
this.session = session;
|
this.session = session;
|
||||||
|
@ -58,12 +64,13 @@ public class UserMapStorage implements UserLookupProvider, UserStorageProvider,
|
||||||
allocations.incrementAndGet();
|
allocations.incrementAndGet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UserModel getUserById(String id, RealmModel realm) {
|
public UserModel getUserById(String id, RealmModel realm) {
|
||||||
StorageId storageId = new StorageId(id);
|
StorageId storageId = new StorageId(id);
|
||||||
final String username = storageId.getExternalId();
|
final String username = storageId.getExternalId();
|
||||||
if (!userPasswords.containsKey(username)) return null;
|
if (!userPasswords.containsKey(username)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return createUser(realm, username);
|
return createUser(realm, username);
|
||||||
}
|
}
|
||||||
|
@ -90,7 +97,9 @@ public class UserMapStorage implements UserLookupProvider, UserStorageProvider,
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean updateCredential(RealmModel realm, UserModel user, CredentialInput input) {
|
public boolean updateCredential(RealmModel realm, UserModel user, CredentialInput input) {
|
||||||
if (!(input instanceof UserCredentialModel)) return false;
|
if (!(input instanceof UserCredentialModel)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (input.getType().equals(UserCredentialModel.PASSWORD)) {
|
if (input.getType().equals(UserCredentialModel.PASSWORD)) {
|
||||||
userPasswords.put(user.getUsername(), ((UserCredentialModel) input).getValue());
|
userPasswords.put(user.getUsername(), ((UserCredentialModel) input).getValue());
|
||||||
return true;
|
return true;
|
||||||
|
@ -117,7 +126,9 @@ public class UserMapStorage implements UserLookupProvider, UserStorageProvider,
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isValid(RealmModel realm, UserModel user, CredentialInput input) {
|
public boolean isValid(RealmModel realm, UserModel user, CredentialInput input) {
|
||||||
if (!(input instanceof UserCredentialModel)) return false;
|
if (!(input instanceof UserCredentialModel)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (input.getType().equals(UserCredentialModel.PASSWORD)) {
|
if (input.getType().equals(UserCredentialModel.PASSWORD)) {
|
||||||
String pw = userPasswords.get(user.getUsername());
|
String pw = userPasswords.get(user.getUsername());
|
||||||
return pw != null && pw.equals(((UserCredentialModel) input).getValue());
|
return pw != null && pw.equals(((UserCredentialModel) input).getValue());
|
||||||
|
@ -128,7 +139,9 @@ public class UserMapStorage implements UserLookupProvider, UserStorageProvider,
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UserModel getUserByUsername(String username, RealmModel realm) {
|
public UserModel getUserByUsername(String username, RealmModel realm) {
|
||||||
if (!userPasswords.containsKey(username)) return null;
|
if (!userPasswords.containsKey(username)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return createUser(realm, username);
|
return createUser(realm, username);
|
||||||
}
|
}
|
||||||
|
@ -151,22 +164,25 @@ public class UserMapStorage implements UserLookupProvider, UserStorageProvider,
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void preRemove(RealmModel realm) {
|
public void preRemove(RealmModel realm) {
|
||||||
|
log.infof("preRemove: realm=%s", realm.getName());
|
||||||
|
realmRemovals.incrementAndGet();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void preRemove(RealmModel realm, GroupModel group) {
|
public void preRemove(RealmModel realm, GroupModel group) {
|
||||||
|
log.infof("preRemove: realm=%s, group=%s", realm.getName(), group.getName());
|
||||||
|
groupRemovals.incrementAndGet();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void preRemove(RealmModel realm, RoleModel role) {
|
public void preRemove(RealmModel realm, RoleModel role) {
|
||||||
|
log.infof("preRemove: realm=%s, role=%s", realm.getName(), role.getName());
|
||||||
|
roleRemovals.incrementAndGet();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
closings.incrementAndGet();
|
closings.incrementAndGet();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
* Copyright 2017 Red Hat, Inc. and/or its affiliates
|
||||||
* and other contributors as indicated by the @author tags.
|
* and other contributors as indicated by the @author tags.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@ -16,15 +16,18 @@
|
||||||
*/
|
*/
|
||||||
package org.keycloak.testsuite.federation.storage;
|
package org.keycloak.testsuite.federation.storage;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.keycloak.Config;
|
import org.keycloak.Config;
|
||||||
import org.keycloak.component.ComponentModel;
|
import org.keycloak.component.ComponentModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.KeycloakSessionFactory;
|
import org.keycloak.models.KeycloakSessionFactory;
|
||||||
|
import org.keycloak.provider.ProviderConfigProperty;
|
||||||
import org.keycloak.storage.UserStorageProviderFactory;
|
import org.keycloak.storage.UserStorageProviderFactory;
|
||||||
|
|
||||||
import java.util.Hashtable;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
|
@ -32,9 +35,23 @@ import java.util.Map;
|
||||||
public class UserMapStorageFactory implements UserStorageProviderFactory<UserMapStorage> {
|
public class UserMapStorageFactory implements UserStorageProviderFactory<UserMapStorage> {
|
||||||
|
|
||||||
|
|
||||||
public static final String PROVIDER_ID = "user-password-map";
|
public static final String PROVIDER_ID = "user-password-map-arq";
|
||||||
|
|
||||||
protected Map<String, String> userPasswords = new Hashtable<>();
|
protected static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
ProviderConfigProperty attr = new ProviderConfigProperty("attr", "attr",
|
||||||
|
"This is some attribute",
|
||||||
|
ProviderConfigProperty.STRING_TYPE, null);
|
||||||
|
configProperties.add(attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Map<String, String> userPasswords = new HashMap<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ProviderConfigProperty> getConfigProperties() {
|
||||||
|
return configProperties;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UserMapStorage create(KeycloakSession session, ComponentModel model) {
|
public UserMapStorage create(KeycloakSession session, ComponentModel model) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
* Copyright 2017 Red Hat, Inc. and/or its affiliates
|
||||||
* and other contributors as indicated by the @author tags.
|
* and other contributors as indicated by the @author tags.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@ -16,6 +16,12 @@
|
||||||
*/
|
*/
|
||||||
package org.keycloak.testsuite.federation.storage;
|
package org.keycloak.testsuite.federation.storage;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
import org.keycloak.component.ComponentModel;
|
import org.keycloak.component.ComponentModel;
|
||||||
import org.keycloak.credential.CredentialInput;
|
import org.keycloak.credential.CredentialInput;
|
||||||
import org.keycloak.credential.CredentialInputValidator;
|
import org.keycloak.credential.CredentialInputValidator;
|
||||||
|
@ -32,12 +38,6 @@ import org.keycloak.storage.adapter.AbstractUserAdapterFederatedStorage;
|
||||||
import org.keycloak.storage.user.UserLookupProvider;
|
import org.keycloak.storage.user.UserLookupProvider;
|
||||||
import org.keycloak.storage.user.UserQueryProvider;
|
import org.keycloak.storage.user.UserQueryProvider;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Properties;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
|
@ -137,7 +137,6 @@ public class UserPropertyFileStorage implements UserLookupProvider, UserStorageP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getUsersCount(RealmModel realm) {
|
public int getUsersCount(RealmModel realm) {
|
||||||
return userPasswords.size();
|
return userPasswords.size();
|
||||||
|
@ -191,7 +190,6 @@ public class UserPropertyFileStorage implements UserLookupProvider, UserStorageP
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<UserModel> searchForUser(Map<String, String> attributes, RealmModel realm, int firstResult, int maxResults) {
|
public List<UserModel> searchForUser(Map<String, String> attributes, RealmModel realm, int firstResult, int maxResults) {
|
||||||
if (attributes.size() != 1) return Collections.EMPTY_LIST;
|
|
||||||
String username = attributes.get(UserModel.USERNAME);
|
String username = attributes.get(UserModel.USERNAME);
|
||||||
if (username == null) return Collections.EMPTY_LIST;
|
if (username == null) return Collections.EMPTY_LIST;
|
||||||
return searchForUser(username, realm, firstResult, maxResults);
|
return searchForUser(username, realm, firstResult, maxResults);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
* Copyright 2017 Red Hat, Inc. and/or its affiliates
|
||||||
* and other contributors as indicated by the @author tags.
|
* and other contributors as indicated by the @author tags.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@ -16,39 +16,85 @@
|
||||||
*/
|
*/
|
||||||
package org.keycloak.testsuite.federation.storage;
|
package org.keycloak.testsuite.federation.storage;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
import org.keycloak.Config;
|
import org.keycloak.Config;
|
||||||
|
import org.keycloak.common.util.EnvUtil;
|
||||||
import org.keycloak.component.ComponentModel;
|
import org.keycloak.component.ComponentModel;
|
||||||
|
import org.keycloak.component.ComponentValidationException;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.KeycloakSessionFactory;
|
import org.keycloak.models.KeycloakSessionFactory;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.provider.ProviderConfigProperty;
|
import org.keycloak.provider.ProviderConfigProperty;
|
||||||
|
import org.keycloak.provider.ProviderConfigurationBuilder;
|
||||||
import org.keycloak.storage.UserStorageProviderFactory;
|
import org.keycloak.storage.UserStorageProviderFactory;
|
||||||
import org.keycloak.storage.UserStorageProviderModel;
|
import org.keycloak.storage.UserStorageProviderModel;
|
||||||
import org.keycloak.storage.user.ImportSynchronization;
|
import org.keycloak.storage.user.ImportSynchronization;
|
||||||
import org.keycloak.storage.user.SynchronizationResult;
|
import org.keycloak.storage.user.SynchronizationResult;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Properties;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public class UserPropertyFileStorageFactory implements UserStorageProviderFactory<UserPropertyFileStorage>, ImportSynchronization {
|
public class UserPropertyFileStorageFactory implements UserStorageProviderFactory<UserPropertyFileStorage>, ImportSynchronization {
|
||||||
|
|
||||||
|
public static final String PROVIDER_ID = "user-password-props-arq";
|
||||||
|
public static final String PROPERTY_FILE = "propertyFile";
|
||||||
|
|
||||||
public static final String PROVIDER_ID = "user-password-props";
|
public static final String VALIDATION_PROP_FILE_NOT_CONFIGURED = "user property file is not configured";
|
||||||
|
public static final String VALIDATION_PROP_FILE_DOESNT_EXIST = "user property file does not exist";
|
||||||
|
|
||||||
|
protected static final List<ProviderConfigProperty> CONFIG_PROPERTIES;
|
||||||
|
|
||||||
|
static {
|
||||||
|
CONFIG_PROPERTIES = ProviderConfigurationBuilder.create()
|
||||||
|
.property().name(PROPERTY_FILE)
|
||||||
|
.type(ProviderConfigProperty.STRING_TYPE)
|
||||||
|
.label("Property File")
|
||||||
|
.helpText("File that contains name value pairs")
|
||||||
|
.defaultValue(null)
|
||||||
|
.add()
|
||||||
|
.property().name("federatedStorage")
|
||||||
|
.type(ProviderConfigProperty.BOOLEAN_TYPE)
|
||||||
|
.label("User Federated Storage")
|
||||||
|
.helpText("User Federated Storage")
|
||||||
|
.defaultValue(null)
|
||||||
|
.add()
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void validateConfiguration(KeycloakSession session, RealmModel realm, ComponentModel config) throws ComponentValidationException {
|
||||||
|
String fp = config.getConfig().getFirst(PROPERTY_FILE);
|
||||||
|
if (fp == null) {
|
||||||
|
throw new ComponentValidationException(VALIDATION_PROP_FILE_NOT_CONFIGURED);
|
||||||
|
}
|
||||||
|
fp = EnvUtil.replace(fp);
|
||||||
|
File file = new File(fp);
|
||||||
|
if (!file.exists()) {
|
||||||
|
throw new ComponentValidationException(VALIDATION_PROP_FILE_DOESNT_EXIST);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UserPropertyFileStorage create(KeycloakSession session, ComponentModel model) {
|
public UserPropertyFileStorage create(KeycloakSession session, ComponentModel model) {
|
||||||
|
String path = model.getConfig().getFirst(PROPERTY_FILE);
|
||||||
|
path = EnvUtil.replace(path);
|
||||||
|
|
||||||
Properties props = new Properties();
|
Properties props = new Properties();
|
||||||
try {
|
try (InputStream is = new FileInputStream(path)) {
|
||||||
props.load(getClass().getResourceAsStream(model.getConfig().getFirst("propertyFile")));
|
props.load(is);
|
||||||
|
is.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new UserPropertyFileStorage(session, model, props);
|
return new UserPropertyFileStorage(session, model, props);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,17 +103,9 @@ public class UserPropertyFileStorageFactory implements UserStorageProviderFactor
|
||||||
return PROVIDER_ID;
|
return PROVIDER_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
static List<ProviderConfigProperty> OPTIONS = new LinkedList<>();
|
|
||||||
static {
|
|
||||||
ProviderConfigProperty prop = new ProviderConfigProperty("propertyFile", "Property File", "file that contains name value pairs", ProviderConfigProperty.STRING_TYPE, null);
|
|
||||||
OPTIONS.add(prop);
|
|
||||||
prop = new ProviderConfigProperty("federatedStorage", "User Federated Storage", "use federated storage?", ProviderConfigProperty.BOOLEAN_TYPE, null);
|
|
||||||
OPTIONS.add(prop);
|
|
||||||
|
|
||||||
}
|
|
||||||
@Override
|
@Override
|
||||||
public List<ProviderConfigProperty> getConfigProperties() {
|
public List<ProviderConfigProperty> getConfigProperties() {
|
||||||
return OPTIONS;
|
return CONFIG_PROPERTIES;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -94,4 +132,5 @@ public class UserPropertyFileStorageFactory implements UserStorageProviderFactor
|
||||||
public SynchronizationResult syncSince(Date lastSync, KeycloakSessionFactory sessionFactory, String realmId, UserStorageProviderModel model) {
|
public SynchronizationResult syncSince(Date lastSync, KeycloakSessionFactory sessionFactory, String realmId, UserStorageProviderModel model) {
|
||||||
return SynchronizationResult.ignored();
|
return SynchronizationResult.ignored();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,570 +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.federation.storage;
|
|
||||||
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.ClassRule;
|
|
||||||
import org.junit.Rule;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.keycloak.OAuth2Constants;
|
|
||||||
import org.keycloak.common.util.Time;
|
|
||||||
import org.keycloak.component.ComponentModel;
|
|
||||||
import org.keycloak.credential.CredentialAuthentication;
|
|
||||||
import org.keycloak.credential.UserCredentialStoreManager;
|
|
||||||
import org.keycloak.models.GroupModel;
|
|
||||||
import org.keycloak.models.KeycloakSession;
|
|
||||||
import org.keycloak.models.RealmModel;
|
|
||||||
import org.keycloak.models.RoleModel;
|
|
||||||
import org.keycloak.models.UserCredentialModel;
|
|
||||||
import org.keycloak.models.UserModel;
|
|
||||||
import org.keycloak.models.cache.CachedUserModel;
|
|
||||||
import org.keycloak.models.cache.infinispan.UserAdapter;
|
|
||||||
import org.keycloak.services.managers.RealmManager;
|
|
||||||
import org.keycloak.storage.StorageId;
|
|
||||||
import org.keycloak.storage.UserStorageProviderModel;
|
|
||||||
import org.keycloak.testsuite.OAuthClient;
|
|
||||||
import org.keycloak.testsuite.pages.AppPage;
|
|
||||||
import org.keycloak.testsuite.pages.LoginPage;
|
|
||||||
import org.keycloak.testsuite.rule.KeycloakRule;
|
|
||||||
import org.keycloak.testsuite.rule.WebResource;
|
|
||||||
import org.keycloak.testsuite.rule.WebRule;
|
|
||||||
import org.openqa.selenium.WebDriver;
|
|
||||||
|
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
|
||||||
* @version $Revision: 1 $
|
|
||||||
*/
|
|
||||||
public class UserStorageTest {
|
|
||||||
public static ComponentModel memoryProvider = null;
|
|
||||||
public static ComponentModel writableProvider = null;
|
|
||||||
@ClassRule
|
|
||||||
public static KeycloakRule keycloakRule = new KeycloakRule(new KeycloakRule.KeycloakSetup() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
|
||||||
UserStorageProviderModel model = new UserStorageProviderModel();
|
|
||||||
model.setName("memory");
|
|
||||||
model.setPriority(0);
|
|
||||||
model.setProviderId(UserMapStorageFactory.PROVIDER_ID);
|
|
||||||
model.setParentId(appRealm.getId());
|
|
||||||
memoryProvider = appRealm.addComponentModel(model);
|
|
||||||
|
|
||||||
model = new UserStorageProviderModel();
|
|
||||||
model.setName("read-only-user-props");
|
|
||||||
model.setPriority(1);
|
|
||||||
model.setProviderId(UserPropertyFileStorageFactory.PROVIDER_ID);
|
|
||||||
model.setParentId(appRealm.getId());
|
|
||||||
model.getConfig().putSingle("propertyFile", "/storage-test/read-only-user-password.properties");
|
|
||||||
appRealm.addComponentModel(model);
|
|
||||||
createUserPropModel(appRealm);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
private static void createUserPropModel(RealmModel appRealm) {
|
|
||||||
UserStorageProviderModel model;
|
|
||||||
model = new UserStorageProviderModel();
|
|
||||||
model.setName("user-props");
|
|
||||||
model.setPriority(2);
|
|
||||||
model.setParentId(appRealm.getId());
|
|
||||||
model.setProviderId(UserPropertyFileStorageFactory.PROVIDER_ID);
|
|
||||||
model.getConfig().putSingle("propertyFile", "/storage-test/user-password.properties");
|
|
||||||
model.getConfig().putSingle("federatedStorage", "true");
|
|
||||||
writableProvider = appRealm.addComponentModel(model);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Rule
|
|
||||||
public WebRule webRule = new WebRule(this);
|
|
||||||
|
|
||||||
@WebResource
|
|
||||||
protected OAuthClient oauth;
|
|
||||||
|
|
||||||
@WebResource
|
|
||||||
protected WebDriver driver;
|
|
||||||
|
|
||||||
@WebResource
|
|
||||||
protected AppPage appPage;
|
|
||||||
|
|
||||||
@WebResource
|
|
||||||
protected LoginPage loginPage;
|
|
||||||
|
|
||||||
private void loginSuccessAndLogout(String username, String password) {
|
|
||||||
loginPage.open();
|
|
||||||
loginPage.login(username, password);
|
|
||||||
Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
|
||||||
Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
|
|
||||||
oauth.openLogout();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void loginBadPassword(String username) {
|
|
||||||
loginPage.open();
|
|
||||||
loginPage.login("username", "badpassword");
|
|
||||||
Assert.assertEquals("Invalid username or password.", loginPage.getError());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testLoginSuccess() {
|
|
||||||
loginSuccessAndLogout("tbrady", "goat");
|
|
||||||
loginSuccessAndLogout("thor", "hammer");
|
|
||||||
loginBadPassword("tbrady");
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
|
||||||
public void resetTimeoffset() {
|
|
||||||
Time.setOffset(0);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//@Test
|
|
||||||
public void testIDE() throws Exception {
|
|
||||||
Thread.sleep(100000000);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* KEYCLOAK-4013
|
|
||||||
*
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testCast() throws Exception {
|
|
||||||
KeycloakSession session = keycloakRule.startSession();
|
|
||||||
List<CredentialAuthentication> list = UserCredentialStoreManager.getCredentialProviders(session, null, CredentialAuthentication.class);
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testDailyEviction() {
|
|
||||||
Calendar cal = Calendar.getInstance();
|
|
||||||
cal.add(Calendar.HOUR, 1);
|
|
||||||
int hour = cal.get(Calendar.HOUR_OF_DAY);
|
|
||||||
int min = cal.get(Calendar.MINUTE);
|
|
||||||
|
|
||||||
UserStorageProviderModel model = new UserStorageProviderModel(writableProvider);
|
|
||||||
model.setCachePolicy(UserStorageProviderModel.CachePolicy.EVICT_DAILY);
|
|
||||||
model.setEvictionHour(cal.get(Calendar.HOUR_OF_DAY));
|
|
||||||
model.setEvictionMinute(cal.get(Calendar.MINUTE));
|
|
||||||
|
|
||||||
KeycloakSession session = keycloakRule.startSession();
|
|
||||||
RealmModel realm = session.realms().getRealmByName("test");
|
|
||||||
CachedUserModel thor = (CachedUserModel)session.users().getUserByUsername("thor", realm);
|
|
||||||
long lastTimestamp = thor.getCacheTimestamp();
|
|
||||||
realm.updateComponent(model);
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
|
|
||||||
session = keycloakRule.startSession();
|
|
||||||
realm = session.realms().getRealmByName("test");
|
|
||||||
thor = (CachedUserModel)session.users().getUserByUsername("thor", realm);
|
|
||||||
lastTimestamp = thor.getCacheTimestamp();
|
|
||||||
realm.updateComponent(model);
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
|
|
||||||
// test is cached
|
|
||||||
session = keycloakRule.startSession();
|
|
||||||
realm = session.realms().getRealmByName("test");
|
|
||||||
thor = (CachedUserModel)session.users().getUserByUsername("thor", realm);
|
|
||||||
// thor should be evicted because we changed the model
|
|
||||||
Assert.assertTrue(thor.getCacheTimestamp() > lastTimestamp);
|
|
||||||
lastTimestamp = thor.getCacheTimestamp();
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
|
|
||||||
|
|
||||||
Time.setOffset(60 * 2 * 60); // 2 hours
|
|
||||||
|
|
||||||
session = keycloakRule.startSession();
|
|
||||||
realm = session.realms().getRealmByName("test");
|
|
||||||
UserModel thor2 = session.users().getUserByUsername("thor", realm);
|
|
||||||
// thor should be evicted because we put it 2 hours in the future
|
|
||||||
if (thor2 instanceof CachedUserModel) {
|
|
||||||
Assert.assertTrue(((CachedUserModel)thor2).getCacheTimestamp() > lastTimestamp);
|
|
||||||
}
|
|
||||||
model.getConfig().remove("cachePolicy");
|
|
||||||
model.getConfig().remove("evictionHour");
|
|
||||||
model.getConfig().remove("evictionMinute");
|
|
||||||
realm.updateComponent(model);
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testWeeklyEviction() {
|
|
||||||
Calendar cal = Calendar.getInstance();
|
|
||||||
|
|
||||||
// sets day of the week to 4 days from now
|
|
||||||
cal.add(Calendar.HOUR, 4 * 24);
|
|
||||||
|
|
||||||
UserStorageProviderModel model = new UserStorageProviderModel(writableProvider);
|
|
||||||
model.setCachePolicy(UserStorageProviderModel.CachePolicy.EVICT_WEEKLY);
|
|
||||||
model.setEvictionDay(cal.get(Calendar.DAY_OF_WEEK));
|
|
||||||
model.setEvictionHour(cal.get(Calendar.HOUR_OF_DAY));
|
|
||||||
model.setEvictionMinute(cal.get(Calendar.MINUTE));
|
|
||||||
|
|
||||||
KeycloakSession session = keycloakRule.startSession();
|
|
||||||
RealmModel realm = session.realms().getRealmByName("test");
|
|
||||||
realm.updateComponent(model);
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
|
|
||||||
session = keycloakRule.startSession();
|
|
||||||
realm = session.realms().getRealmByName("test");
|
|
||||||
CachedUserModel thor = (CachedUserModel)session.users().getUserByUsername("thor", realm);
|
|
||||||
long lastTimestamp = thor.getCacheTimestamp();
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
|
|
||||||
session = keycloakRule.startSession();
|
|
||||||
realm = session.realms().getRealmByName("test");
|
|
||||||
thor = (CachedUserModel)session.users().getUserByUsername("thor", realm);
|
|
||||||
lastTimestamp = thor.getCacheTimestamp();
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
|
|
||||||
session = keycloakRule.startSession();
|
|
||||||
realm = session.realms().getRealmByName("test");
|
|
||||||
thor = (CachedUserModel)session.users().getUserByUsername("thor", realm);
|
|
||||||
lastTimestamp = thor.getCacheTimestamp();
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
|
|
||||||
Time.setOffset(60 * 60 * 24 * 2); // 2 days in future, should be cached still
|
|
||||||
|
|
||||||
session = keycloakRule.startSession();
|
|
||||||
realm = session.realms().getRealmByName("test");
|
|
||||||
// test still
|
|
||||||
thor = (CachedUserModel)session.users().getUserByUsername("thor", realm);
|
|
||||||
Assert.assertEquals(thor.getCacheTimestamp(), lastTimestamp);
|
|
||||||
lastTimestamp = thor.getCacheTimestamp();
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
|
|
||||||
Time.setOffset(Time.getOffset() + 60 * 60 * 24 * 3); // 3 days into future, cache will be invalidated
|
|
||||||
|
|
||||||
session = keycloakRule.startSession();
|
|
||||||
realm = session.realms().getRealmByName("test");
|
|
||||||
UserModel thor2 = session.users().getUserByUsername("thor", realm);
|
|
||||||
// thor should be evicted because we put it 2 hours in the future
|
|
||||||
if (thor2 instanceof CachedUserModel) {
|
|
||||||
Assert.assertTrue(((CachedUserModel)thor2).getCacheTimestamp() > lastTimestamp);
|
|
||||||
}
|
|
||||||
model.getConfig().remove("cachePolicy");
|
|
||||||
model.getConfig().remove("evictionHour");
|
|
||||||
model.getConfig().remove("evictionMinute");
|
|
||||||
model.getConfig().remove("evictionDay");
|
|
||||||
realm.updateComponent(model);
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testMaxLifespanEviction() {
|
|
||||||
UserStorageProviderModel model = new UserStorageProviderModel(writableProvider);
|
|
||||||
model.setCachePolicy(UserStorageProviderModel.CachePolicy.MAX_LIFESPAN);
|
|
||||||
model.setMaxLifespan(600000); // Lifetime is 10 minutes
|
|
||||||
|
|
||||||
KeycloakSession session = keycloakRule.startSession();
|
|
||||||
RealmModel realm = session.realms().getRealmByName("test");
|
|
||||||
realm.updateComponent(model);
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
|
|
||||||
session = keycloakRule.startSession();
|
|
||||||
realm = session.realms().getRealmByName("test");
|
|
||||||
CachedUserModel thor = (CachedUserModel)session.users().getUserByUsername("thor", realm);
|
|
||||||
long lastTimestamp = thor.getCacheTimestamp();
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
|
|
||||||
|
|
||||||
session = keycloakRule.startSession();
|
|
||||||
realm = session.realms().getRealmByName("test");
|
|
||||||
thor = (CachedUserModel)session.users().getUserByUsername("thor", realm);
|
|
||||||
lastTimestamp = thor.getCacheTimestamp();
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
|
|
||||||
|
|
||||||
Time.setOffset(60 * 5); // 5 minutes in future, should be cached still
|
|
||||||
session = keycloakRule.startSession();
|
|
||||||
realm = session.realms().getRealmByName("test");
|
|
||||||
thor = (CachedUserModel)session.users().getUserByUsername("thor", realm);
|
|
||||||
Assert.assertEquals(thor.getCacheTimestamp(), lastTimestamp);
|
|
||||||
lastTimestamp = thor.getCacheTimestamp();
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
|
|
||||||
Time.setOffset(60 * 20); // 20 minutes into future, cache will be invalidated
|
|
||||||
|
|
||||||
session = keycloakRule.startSession();
|
|
||||||
realm = session.realms().getRealmByName("test");
|
|
||||||
UserModel thor2 = session.users().getUserByUsername("thor", realm);
|
|
||||||
// thor should be evicted because we put it 2 hours in the future
|
|
||||||
if (thor2 instanceof CachedUserModel) {
|
|
||||||
Assert.assertTrue(((CachedUserModel)thor2).getCacheTimestamp() > lastTimestamp);
|
|
||||||
}
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
|
|
||||||
session = keycloakRule.startSession();
|
|
||||||
realm = session.realms().getRealmByName("test");
|
|
||||||
model.getConfig().remove("cachePolicy");
|
|
||||||
model.getConfig().remove("maxLifespan");
|
|
||||||
realm.updateComponent(model);
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testNoCache() {
|
|
||||||
UserStorageProviderModel model = new UserStorageProviderModel(writableProvider);
|
|
||||||
model.setCachePolicy(UserStorageProviderModel.CachePolicy.NO_CACHE);
|
|
||||||
KeycloakSession session = keycloakRule.startSession();
|
|
||||||
RealmModel realm = session.realms().getRealmByName("test");
|
|
||||||
CachedUserModel thor = (CachedUserModel)session.users().getUserByUsername("thor", realm);
|
|
||||||
realm.updateComponent(model);
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
|
|
||||||
|
|
||||||
session = keycloakRule.startSession();
|
|
||||||
realm = session.realms().getRealmByName("test");
|
|
||||||
// test still
|
|
||||||
UserModel thor2 = session.users().getUserByUsername("thor", realm);
|
|
||||||
Assert.assertFalse(thor2 instanceof CachedUserModel);
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
|
|
||||||
session = keycloakRule.startSession();
|
|
||||||
realm = session.realms().getRealmByName("test");
|
|
||||||
thor2 = session.users().getUserByUsername("thor", realm);
|
|
||||||
Assert.assertFalse(thor2 instanceof CachedUserModel);
|
|
||||||
model.getConfig().remove("cachePolicy");
|
|
||||||
model.getConfig().remove("evictionHour");
|
|
||||||
model.getConfig().remove("evictionMinute");
|
|
||||||
model.getConfig().remove("evictionDay");
|
|
||||||
realm.updateComponent(model);
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
|
|
||||||
session = keycloakRule.startSession();
|
|
||||||
realm = session.realms().getRealmByName("test");
|
|
||||||
thor = (CachedUserModel)session.users().getUserByUsername("thor", realm);
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testUpdate() {
|
|
||||||
KeycloakSession session = keycloakRule.startSession();
|
|
||||||
RealmModel realm = session.realms().getRealmByName("test");
|
|
||||||
UserModel thor = session.users().getUserByUsername("thor", realm);
|
|
||||||
thor.setFirstName("Stian");
|
|
||||||
thor.setLastName("Thorgersen");
|
|
||||||
thor.setEmailVerified(true);
|
|
||||||
long thorCreated = System.currentTimeMillis() - 100;
|
|
||||||
thor.setCreatedTimestamp(thorCreated);
|
|
||||||
thor.setEmail("thor@hammer.com");
|
|
||||||
thor.setSingleAttribute("test-attribute", "value");
|
|
||||||
RoleModel role = realm.addRole("foo-role");
|
|
||||||
thor.grantRole(role);
|
|
||||||
GroupModel group = realm.createGroup("my-group");
|
|
||||||
thor.joinGroup(group);
|
|
||||||
thor.addRequiredAction("POOP");
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
|
|
||||||
session = keycloakRule.startSession();
|
|
||||||
realm = session.realms().getRealmByName("test");
|
|
||||||
thor = session.users().getUserByUsername("thor", realm);
|
|
||||||
Assert.assertEquals("Stian", thor.getFirstName());
|
|
||||||
Assert.assertEquals("Thorgersen", thor.getLastName());
|
|
||||||
Assert.assertEquals("thor@hammer.com", thor.getEmail());
|
|
||||||
Assert.assertEquals("value", thor.getFirstAttribute("test-attribute"));
|
|
||||||
Assert.assertTrue(thor.isEmailVerified());
|
|
||||||
Assert.assertTrue(thor instanceof UserAdapter);
|
|
||||||
Set<RoleModel> roles = thor.getRoleMappings();
|
|
||||||
System.out.println("num roles " + roles.size());
|
|
||||||
Assert.assertTrue(roles.size() > 1);
|
|
||||||
role = realm.getRole("foo-role");
|
|
||||||
Assert.assertTrue(thor.hasRole(role));
|
|
||||||
|
|
||||||
Set<GroupModel> groups = thor.getGroups();
|
|
||||||
boolean foundGroup = false;
|
|
||||||
for (GroupModel g : groups) {
|
|
||||||
if (g.getName().equals("my-group")) foundGroup = true;
|
|
||||||
|
|
||||||
}
|
|
||||||
Assert.assertTrue(foundGroup);
|
|
||||||
System.out.println("num groups " + groups.size());
|
|
||||||
Assert.assertTrue(thor.getRequiredActions().iterator().next().equals("POOP"));
|
|
||||||
thor.removeRequiredAction("POOP");
|
|
||||||
session.userCredentialManager().updateCredential(realm, thor, UserCredentialModel.password("lightning"));
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
loginSuccessAndLogout("thor", "lightning");
|
|
||||||
|
|
||||||
// test removal of provider
|
|
||||||
session = keycloakRule.startSession();
|
|
||||||
realm = session.realms().getRealmByName("test");
|
|
||||||
realm.removeComponent(writableProvider);
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
session = keycloakRule.startSession();
|
|
||||||
realm = session.realms().getRealmByName("test");
|
|
||||||
createUserPropModel(realm);
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
|
|
||||||
loginSuccessAndLogout("thor", "hammer");
|
|
||||||
|
|
||||||
session = keycloakRule.startSession();
|
|
||||||
realm = session.realms().getRealmByName("test");
|
|
||||||
|
|
||||||
thor = session.users().getUserByUsername("thor", realm);
|
|
||||||
Assert.assertNull(thor.getFirstName());
|
|
||||||
Assert.assertNull(thor.getLastName());
|
|
||||||
Assert.assertNull(thor.getEmail());
|
|
||||||
Assert.assertNull(thor.getFirstAttribute("test-attribute"));
|
|
||||||
Assert.assertFalse(thor.isEmailVerified());
|
|
||||||
role = realm.getRole("foo-role");
|
|
||||||
Assert.assertFalse(thor.hasRole(role));
|
|
||||||
|
|
||||||
groups = thor.getGroups();
|
|
||||||
foundGroup = false;
|
|
||||||
for (GroupModel g : groups) {
|
|
||||||
if (g.getName().equals("my-group")) foundGroup = true;
|
|
||||||
|
|
||||||
}
|
|
||||||
Assert.assertFalse(foundGroup);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testQuery() {
|
|
||||||
KeycloakSession session = keycloakRule.startSession();
|
|
||||||
RealmModel realm = session.realms().getRealmByName("test");
|
|
||||||
|
|
||||||
// Test paging
|
|
||||||
List<UserModel> localUsers = session.userLocalStorage().getUsers(realm, false);
|
|
||||||
Set<UserModel> queried = new HashSet<>();
|
|
||||||
// tests assumes that local storage is queried first
|
|
||||||
int first = localUsers.size();
|
|
||||||
while (queried.size() < 8) {
|
|
||||||
List<UserModel> results = session.users().getUsers(realm, first, 3);
|
|
||||||
if (results.size() == 0) break;
|
|
||||||
first += results.size();
|
|
||||||
queried.addAll(results);
|
|
||||||
|
|
||||||
}
|
|
||||||
Set<String> usernames = new HashSet<>();
|
|
||||||
for (UserModel user : queried) {
|
|
||||||
usernames.add(user.getUsername());
|
|
||||||
System.out.println(user.getUsername());
|
|
||||||
|
|
||||||
}
|
|
||||||
Assert.assertEquals(8, queried.size());
|
|
||||||
Assert.assertTrue(usernames.contains("thor"));
|
|
||||||
Assert.assertTrue(usernames.contains("zeus"));
|
|
||||||
Assert.assertTrue(usernames.contains("apollo"));
|
|
||||||
Assert.assertTrue(usernames.contains("perseus"));
|
|
||||||
Assert.assertTrue(usernames.contains("tbrady"));
|
|
||||||
Assert.assertTrue(usernames.contains("rob"));
|
|
||||||
Assert.assertTrue(usernames.contains("jules"));
|
|
||||||
Assert.assertTrue(usernames.contains("danny"));
|
|
||||||
|
|
||||||
// test searchForUser
|
|
||||||
List<UserModel> users = session.users().searchForUser("tbrady", realm);
|
|
||||||
Assert.assertTrue(users.size() == 1);
|
|
||||||
Assert.assertTrue(users.get(0).getUsername().equals("tbrady"));
|
|
||||||
|
|
||||||
// test getGroupMembers()
|
|
||||||
GroupModel gods = realm.createGroup("gods");
|
|
||||||
UserModel user = null;
|
|
||||||
user = session.users().getUserByUsername("apollo", realm);
|
|
||||||
user.joinGroup(gods);
|
|
||||||
user = session.users().getUserByUsername("zeus", realm);
|
|
||||||
user.joinGroup(gods);
|
|
||||||
user = session.users().getUserByUsername("thor", realm);
|
|
||||||
user.joinGroup(gods);
|
|
||||||
queried.clear();
|
|
||||||
usernames.clear();
|
|
||||||
|
|
||||||
first = 0;
|
|
||||||
while (queried.size() < 8) {
|
|
||||||
List<UserModel> results = session.users().getGroupMembers(realm, gods, first, 1);
|
|
||||||
if (results.size() == 0) break;
|
|
||||||
first += results.size();
|
|
||||||
queried.addAll(results);
|
|
||||||
|
|
||||||
}
|
|
||||||
for (UserModel u : queried) {
|
|
||||||
usernames.add(u.getUsername());
|
|
||||||
System.out.println(u.getUsername());
|
|
||||||
|
|
||||||
}
|
|
||||||
Assert.assertEquals(3, queried.size());
|
|
||||||
Assert.assertTrue(usernames.contains("apollo"));
|
|
||||||
Assert.assertTrue(usernames.contains("zeus"));
|
|
||||||
Assert.assertTrue(usernames.contains("thor"));
|
|
||||||
|
|
||||||
// search by single attribute
|
|
||||||
System.out.println("search by single attribute");
|
|
||||||
user = session.users().getUserByUsername("thor", realm);
|
|
||||||
user.setSingleAttribute("weapon", "hammer");
|
|
||||||
|
|
||||||
users = session.users().searchForUserByUserAttribute("weapon", "hammer", realm);
|
|
||||||
for (UserModel u : users) {
|
|
||||||
System.out.println(u.getUsername());
|
|
||||||
|
|
||||||
}
|
|
||||||
Assert.assertEquals(1, users.size());
|
|
||||||
Assert.assertEquals("thor", users.get(0).getUsername());
|
|
||||||
|
|
||||||
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRegistration() {
|
|
||||||
KeycloakSession session = keycloakRule.startSession();
|
|
||||||
RealmModel realm = session.realms().getRealmByName("test");
|
|
||||||
UserModel user = session.users().addUser(realm, "memuser");
|
|
||||||
session.userCredentialManager().updateCredential(realm, user, UserCredentialModel.password("password"));
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
loginSuccessAndLogout("memuser", "password");
|
|
||||||
loginSuccessAndLogout("memuser", "password");
|
|
||||||
loginSuccessAndLogout("memuser", "password");
|
|
||||||
|
|
||||||
session = keycloakRule.startSession();
|
|
||||||
realm = session.realms().getRealmByName("test");
|
|
||||||
user = session.users().getUserByUsername("memuser", realm);
|
|
||||||
Assert.assertEquals(memoryProvider.getId(), StorageId.resolveProviderId(user));
|
|
||||||
session.users().removeUser(realm, user);
|
|
||||||
Assert.assertNull(session.users().getUserByUsername("memuser", realm));
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testLifecycle() {
|
|
||||||
UserMapStorage.allocations.set(0);
|
|
||||||
UserMapStorage.closings.set(0);
|
|
||||||
KeycloakSession session = keycloakRule.startSession();
|
|
||||||
RealmModel realm = session.realms().getRealmByName("test");
|
|
||||||
UserModel user = session.users().addUser(realm, "memuser");
|
|
||||||
Assert.assertNotNull(user);
|
|
||||||
user = session.users().getUserByUsername("nonexistent", realm);
|
|
||||||
Assert.assertNull(user);
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
Assert.assertEquals(1, UserMapStorage.allocations.get());
|
|
||||||
Assert.assertEquals(1, UserMapStorage.closings.get());
|
|
||||||
|
|
||||||
session = keycloakRule.startSession();
|
|
||||||
realm = session.realms().getRealmByName("test");
|
|
||||||
user = session.users().getUserByUsername("memuser", realm);
|
|
||||||
session.users().removeUser(realm, user);
|
|
||||||
Assert.assertNull(session.users().getUserByUsername("memuser", realm));
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,314 +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.federation.sync;
|
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.ClassRule;
|
|
||||||
import org.junit.FixMethodOrder;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runners.MethodSorters;
|
|
||||||
import org.keycloak.common.util.Time;
|
|
||||||
import org.keycloak.models.KeycloakSession;
|
|
||||||
import org.keycloak.models.KeycloakSessionFactory;
|
|
||||||
import org.keycloak.models.RealmModel;
|
|
||||||
import org.keycloak.services.managers.RealmManager;
|
|
||||||
import org.keycloak.services.managers.UserStorageSyncManager;
|
|
||||||
import org.keycloak.storage.UserStorageProvider;
|
|
||||||
import org.keycloak.storage.UserStorageProviderModel;
|
|
||||||
import org.keycloak.storage.user.SynchronizationResult;
|
|
||||||
import org.keycloak.testsuite.federation.DummyUserFederationProviderFactory;
|
|
||||||
import org.keycloak.testsuite.rule.KeycloakRule;
|
|
||||||
import org.keycloak.timer.TimerProvider;
|
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test with Dummy providers
|
|
||||||
*
|
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
|
||||||
*/
|
|
||||||
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
|
||||||
public class SyncFederationTest {
|
|
||||||
|
|
||||||
private static final Logger log = Logger.getLogger(SyncFederationTest.class);
|
|
||||||
|
|
||||||
private static UserStorageProviderModel dummyModel = null;
|
|
||||||
|
|
||||||
@ClassRule
|
|
||||||
public static KeycloakRule keycloakRule = new KeycloakRule(new KeycloakRule.KeycloakSetup() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
|
||||||
// Other tests may left Time offset uncleared, which could cause issues
|
|
||||||
Time.setOffset(0);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test that period sync is triggered when creating a synchronized User Storage Provider
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void test01PeriodicSyncOnCreate() {
|
|
||||||
|
|
||||||
KeycloakSession session = keycloakRule.startSession();
|
|
||||||
KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
|
|
||||||
DummyUserFederationProviderFactory dummyFedFactory = (DummyUserFederationProviderFactory) sessionFactory.getProviderFactory(UserStorageProvider.class, DummyUserFederationProviderFactory.PROVIDER_NAME);
|
|
||||||
int full = dummyFedFactory.getFullSyncCounter();
|
|
||||||
int changed = dummyFedFactory.getChangedSyncCounter();
|
|
||||||
keycloakRule.stopSession(session, false);
|
|
||||||
// Enable timer for SyncDummyUserFederationProvider
|
|
||||||
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
|
||||||
UserStorageProviderModel model = new UserStorageProviderModel();
|
|
||||||
model.setProviderId(DummyUserFederationProviderFactory.PROVIDER_NAME);
|
|
||||||
model.setPriority(1);
|
|
||||||
model.setName("test-sync-dummy");
|
|
||||||
model.setFullSyncPeriod(-1);
|
|
||||||
model.setChangedSyncPeriod(1);
|
|
||||||
model.setLastSync(0);
|
|
||||||
dummyModel = new UserStorageProviderModel(appRealm.addComponentModel(model));
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
session = keycloakRule.startSession();
|
|
||||||
try {
|
|
||||||
|
|
||||||
// Assert that after some period was DummyUserFederationProvider triggered
|
|
||||||
UserStorageSyncManager usersSyncManager = new UserStorageSyncManager();
|
|
||||||
sleep(1800);
|
|
||||||
|
|
||||||
// Cancel timer
|
|
||||||
RealmModel appRealm = session.realms().getRealmByName("test");
|
|
||||||
usersSyncManager.notifyToRefreshPeriodicSync(session, appRealm, dummyModel, true);
|
|
||||||
log.infof("Notified sync manager about cancel periodic sync");
|
|
||||||
|
|
||||||
// This sync is here just to ensure that we have lock (doublecheck that periodic sync, which was possibly triggered before canceling timer is finished too)
|
|
||||||
while (true) {
|
|
||||||
SynchronizationResult result = usersSyncManager.syncChangedUsers(session.getKeycloakSessionFactory(), appRealm.getId(), dummyModel);
|
|
||||||
if (result.isIgnored()) {
|
|
||||||
log.infof("Still waiting for lock before periodic sync is finished", result.toString());
|
|
||||||
sleep(1000);
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assert that DummyUserFederationProviderFactory.syncChangedUsers was invoked at least 2 times (once periodically and once for us)
|
|
||||||
int newChanged = dummyFedFactory.getChangedSyncCounter();
|
|
||||||
Assert.assertEquals(full, dummyFedFactory.getFullSyncCounter());
|
|
||||||
Assert.assertTrue("Assertion failed. newChanged=" + newChanged + ", changed=" + changed, newChanged > (changed + 1));
|
|
||||||
|
|
||||||
// Assert that dummy provider won't be invoked anymore
|
|
||||||
sleep(1800);
|
|
||||||
Assert.assertEquals(full, dummyFedFactory.getFullSyncCounter());
|
|
||||||
int newestChanged = dummyFedFactory.getChangedSyncCounter();
|
|
||||||
Assert.assertEquals("Assertion failed. newChanged=" + newChanged + ", newestChanged=" + newestChanged, newChanged, newestChanged);
|
|
||||||
} finally {
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove dummyProvider
|
|
||||||
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
|
||||||
appRealm.removeComponent(dummyModel);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test that period sync is triggered when updating a synchronized User Storage Provider to have a non-negative sync period
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void test02PeriodicSyncOnUpdate() {
|
|
||||||
|
|
||||||
KeycloakSession session = keycloakRule.startSession();
|
|
||||||
KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
|
|
||||||
DummyUserFederationProviderFactory dummyFedFactory = (DummyUserFederationProviderFactory) sessionFactory.getProviderFactory(UserStorageProvider.class, DummyUserFederationProviderFactory.PROVIDER_NAME);
|
|
||||||
int full = dummyFedFactory.getFullSyncCounter();
|
|
||||||
int changed = dummyFedFactory.getChangedSyncCounter();
|
|
||||||
keycloakRule.stopSession(session, false);
|
|
||||||
// Enable timer for SyncDummyUserFederationProvider
|
|
||||||
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
|
||||||
UserStorageProviderModel model = new UserStorageProviderModel();
|
|
||||||
model.setProviderId(DummyUserFederationProviderFactory.PROVIDER_NAME);
|
|
||||||
model.setPriority(1);
|
|
||||||
model.setName("test-sync-dummy");
|
|
||||||
model.setFullSyncPeriod(-1);
|
|
||||||
model.setChangedSyncPeriod(-1);
|
|
||||||
model.setLastSync(0);
|
|
||||||
dummyModel = new UserStorageProviderModel(appRealm.addComponentModel(model));
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
session = keycloakRule.startSession();
|
|
||||||
try {
|
|
||||||
|
|
||||||
// Assert that after some period was DummyUserFederationProvider triggered
|
|
||||||
UserStorageSyncManager usersSyncManager = new UserStorageSyncManager();
|
|
||||||
// Assert that dummy provider won't be invoked anymore
|
|
||||||
sleep(1800);
|
|
||||||
Assert.assertEquals(full, dummyFedFactory.getFullSyncCounter());
|
|
||||||
int newestChanged = dummyFedFactory.getChangedSyncCounter();
|
|
||||||
Assert.assertEquals("Assertion failed. newChanged=" + changed + ", newestChanged=" + newestChanged, changed, newestChanged);
|
|
||||||
} finally {
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
|
||||||
dummyModel.setChangedSyncPeriod(1);
|
|
||||||
appRealm.updateComponent(dummyModel);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
session = keycloakRule.startSession();
|
|
||||||
try {
|
|
||||||
|
|
||||||
// Assert that after some period was DummyUserFederationProvider triggered
|
|
||||||
UserStorageSyncManager usersSyncManager = new UserStorageSyncManager();
|
|
||||||
sleep(1800);
|
|
||||||
|
|
||||||
// Cancel timer
|
|
||||||
RealmModel appRealm = session.realms().getRealmByName("test");
|
|
||||||
usersSyncManager.notifyToRefreshPeriodicSync(session, appRealm, dummyModel, true);
|
|
||||||
log.infof("Notified sync manager about cancel periodic sync");
|
|
||||||
|
|
||||||
// This sync is here just to ensure that we have lock (doublecheck that periodic sync, which was possibly triggered before canceling timer is finished too)
|
|
||||||
while (true) {
|
|
||||||
SynchronizationResult result = usersSyncManager.syncChangedUsers(session.getKeycloakSessionFactory(), appRealm.getId(), dummyModel);
|
|
||||||
if (result.isIgnored()) {
|
|
||||||
log.infof("Still waiting for lock before periodic sync is finished", result.toString());
|
|
||||||
sleep(1000);
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assert that DummyUserFederationProviderFactory.syncChangedUsers was invoked at least 2 times (once periodically and once for us)
|
|
||||||
int newChanged = dummyFedFactory.getChangedSyncCounter();
|
|
||||||
Assert.assertEquals(full, dummyFedFactory.getFullSyncCounter());
|
|
||||||
log.info("Asserting. newChanged=" + newChanged + " > changed=" + changed);
|
|
||||||
Assert.assertTrue("Assertion failed. newChanged=" + newChanged + ", changed=" + changed, newChanged > (changed + 1));
|
|
||||||
|
|
||||||
// Assert that dummy provider won't be invoked anymore
|
|
||||||
sleep(1800);
|
|
||||||
Assert.assertEquals(full, dummyFedFactory.getFullSyncCounter());
|
|
||||||
int newestChanged = dummyFedFactory.getChangedSyncCounter();
|
|
||||||
Assert.assertEquals("Assertion failed. newChanged=" + newChanged + ", newestChanged=" + newestChanged, newChanged, newestChanged);
|
|
||||||
} finally {
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// remove dummyProvider
|
|
||||||
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
|
||||||
appRealm.removeComponent(dummyModel);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void test03ConcurrentSync() throws Exception {
|
|
||||||
SyncDummyUserFederationProviderFactory.restartLatches();
|
|
||||||
|
|
||||||
// Enable timer for SyncDummyUserFederationProvider
|
|
||||||
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
|
||||||
UserStorageProviderModel model = new UserStorageProviderModel();
|
|
||||||
model.setProviderId(SyncDummyUserFederationProviderFactory.SYNC_PROVIDER_ID);
|
|
||||||
model.setPriority(1);
|
|
||||||
model.setName("test-sync-dummy");
|
|
||||||
model.setFullSyncPeriod(-1);
|
|
||||||
model.setChangedSyncPeriod(1);
|
|
||||||
model.setLastSync(0);
|
|
||||||
model.getConfig().putSingle(SyncDummyUserFederationProviderFactory.WAIT_TIME, "2000");
|
|
||||||
dummyModel = new UserStorageProviderModel(appRealm.addComponentModel(model));
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
KeycloakSession session = keycloakRule.startSession();
|
|
||||||
try {
|
|
||||||
KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
|
|
||||||
|
|
||||||
// bootstrap periodic sync
|
|
||||||
UserStorageSyncManager usersSyncManager = new UserStorageSyncManager();
|
|
||||||
usersSyncManager.bootstrapPeriodic(sessionFactory, session.getProvider(TimerProvider.class));
|
|
||||||
|
|
||||||
// Wait and then trigger sync manually. Assert it will be ignored
|
|
||||||
sleep(1800);
|
|
||||||
RealmModel realm = session.realms().getRealm("test");
|
|
||||||
SynchronizationResult syncResult = usersSyncManager.syncChangedUsers(sessionFactory, realm.getId(), dummyModel);
|
|
||||||
Assert.assertTrue(syncResult.isIgnored());
|
|
||||||
|
|
||||||
// Cancel timer
|
|
||||||
usersSyncManager.notifyToRefreshPeriodicSync(session, realm, dummyModel, true);
|
|
||||||
|
|
||||||
// Signal to factory to finish waiting
|
|
||||||
SyncDummyUserFederationProviderFactory.latch1.countDown();
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
keycloakRule.stopSession(session, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
SyncDummyUserFederationProviderFactory.latch2.await(20000, TimeUnit.MILLISECONDS);
|
|
||||||
|
|
||||||
// remove provider
|
|
||||||
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
|
||||||
appRealm.removeComponent(dummyModel);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sleep(int time) {
|
|
||||||
try {
|
|
||||||
Thread.sleep(time);
|
|
||||||
} catch (InterruptedException ie) {
|
|
||||||
throw new RuntimeException(ie);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,4 +0,0 @@
|
||||||
org.keycloak.testsuite.federation.sync.SyncDummyUserFederationProviderFactory
|
|
||||||
org.keycloak.testsuite.federation.storage.UserPropertyFileStorageFactory
|
|
||||||
org.keycloak.testsuite.federation.storage.UserMapStorageFactory
|
|
||||||
org.keycloak.testsuite.federation.storage.FailableHardcodedStorageProviderFactory
|
|
|
@ -1,4 +0,0 @@
|
||||||
tbrady=goat
|
|
||||||
rob=pw
|
|
||||||
jules=pw
|
|
||||||
danny=pw
|
|
|
@ -1,4 +0,0 @@
|
||||||
thor=hammer
|
|
||||||
zeus=pw
|
|
||||||
apollo=pw
|
|
||||||
perseus=pw
|
|
Loading…
Reference in a new issue