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.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
@ -14,7 +14,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.keycloak.testsuite.federation.storage;
|
||||
package org.keycloak.testsuite.federation;
|
||||
|
||||
import org.keycloak.common.util.MultivaluedHashMap;
|
||||
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.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
@ -14,7 +14,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.keycloak.testsuite.federation.storage;
|
||||
package org.keycloak.testsuite.federation;
|
||||
|
||||
import org.keycloak.component.ComponentModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
|
@ -16,13 +16,16 @@
|
|||
*/
|
||||
package org.keycloak.testsuite.federation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.component.ComponentModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.provider.ProviderConfigProperty;
|
||||
import org.keycloak.storage.UserStorageProviderFactory;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
|
@ -34,8 +37,22 @@ public class UserMapStorageFactory implements UserStorageProviderFactory<UserMap
|
|||
|
||||
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<>();
|
||||
|
||||
@Override
|
||||
public List<ProviderConfigProperty> getConfigProperties() {
|
||||
return configProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserMapStorage create(KeycloakSession session, ComponentModel model) {
|
||||
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.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
@ -41,10 +41,10 @@ import java.util.concurrent.TimeUnit;
|
|||
public class SyncDummyUserFederationProviderFactory extends DummyUserFederationProviderFactory {
|
||||
|
||||
// Used during SyncFederationTest
|
||||
static volatile CountDownLatch latch1 = new CountDownLatch(1);
|
||||
static volatile CountDownLatch latch2 = new CountDownLatch(1);
|
||||
public static volatile CountDownLatch latch1 = new CountDownLatch(1);
|
||||
public static volatile CountDownLatch latch2 = new CountDownLatch(1);
|
||||
|
||||
static void restartLatches() {
|
||||
public static void restartLatches() {
|
||||
latch1 = new CountDownLatch(1);
|
||||
latch2 = new CountDownLatch(1);
|
||||
}
|
|
@ -1,4 +1,6 @@
|
|||
org.keycloak.testsuite.federation.DummyUserFederationProviderFactory
|
||||
org.keycloak.testsuite.federation.FailableHardcodedStorageProviderFactory
|
||||
org.keycloak.testsuite.federation.UserMapStorageFactory
|
||||
org.keycloak.testsuite.federation.UserPropertyFileStorageFactory
|
||||
org.keycloak.testsuite.federation.PassThroughFederatedUserStorageProviderFactory
|
||||
org.keycloak.testsuite.federation.sync.SyncDummyUserFederationProviderFactory
|
||||
|
|
|
@ -171,7 +171,7 @@ public final class TestContext {
|
|||
public TestCleanup getOrCreateCleanup(String realmName) {
|
||||
TestCleanup cleanup = cleanups.get(realmName);
|
||||
if (cleanup == null) {
|
||||
cleanup = new TestCleanup(adminClient, realmName);
|
||||
cleanup = new TestCleanup(this, realmName);
|
||||
TestCleanup existing = cleanups.putIfAbsent(realmName, cleanup);
|
||||
|
||||
if (existing != null) {
|
||||
|
|
|
@ -24,6 +24,7 @@ import javax.ws.rs.NotFoundException;
|
|||
import org.keycloak.admin.client.Keycloak;
|
||||
import org.keycloak.admin.client.resource.RealmResource;
|
||||
import org.keycloak.common.util.ConcurrentMultivaluedHashMap;
|
||||
import org.keycloak.testsuite.arquillian.TestContext;
|
||||
|
||||
/**
|
||||
* 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_CONFIG_IDS = "AUTH_CONFIG_IDS";
|
||||
|
||||
private final Keycloak adminClient;
|
||||
private final TestContext testContext;
|
||||
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
|
||||
private ConcurrentMultivaluedHashMap<String, String> entities = new ConcurrentMultivaluedHashMap<>();
|
||||
|
||||
|
||||
public TestCleanup(Keycloak adminClient, String realmName) {
|
||||
this.adminClient = adminClient;
|
||||
public TestCleanup(TestContext testContext, String realmName) {
|
||||
this.testContext = testContext;
|
||||
this.realmName = realmName;
|
||||
}
|
||||
|
||||
|
@ -101,7 +102,7 @@ public class TestCleanup {
|
|||
|
||||
|
||||
public void executeCleanup() {
|
||||
RealmResource realm = adminClient.realm(realmName);
|
||||
RealmResource realm = getAdminClient().realm(realmName);
|
||||
|
||||
List<String> userIds = entities.get(USER_IDS);
|
||||
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.ExportImportManager;
|
||||
import org.keycloak.exportimport.singlefile.SingleFileExportProviderFactory;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.representations.idm.ComponentRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.storage.UserStorageProvider;
|
||||
import org.keycloak.testsuite.AbstractAuthTest;
|
||||
import org.keycloak.testsuite.admin.ApiUtil;
|
||||
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.runonserver.RunOnServerDeployment;
|
||||
import org.keycloak.testsuite.util.RealmBuilder;
|
||||
|
||||
/**
|
||||
*
|
||||
* @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;
|
||||
|
||||
|
@ -44,9 +51,25 @@ public class ComponentExportImportTest extends AbstractAuthTest implements Seria
|
|||
public void setDirs() {
|
||||
exportFile = new File (new File(System.getProperty("auth.server.config.dir", "target")), "singleFile-full.json");
|
||||
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
|
||||
Properties systemProps = System.getProperties();
|
||||
Set<String> propsToRemove = new HashSet<>();
|
||||
|
@ -60,19 +83,23 @@ public class ComponentExportImportTest extends AbstractAuthTest implements Seria
|
|||
for (String propToRemove : propsToRemove) {
|
||||
systemProps.remove(propToRemove);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
protected String addComponent(ComponentRepresentation component) {
|
||||
return ApiUtil.getCreatedId(testRealmResource().components().add(component));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testSingleFile() {
|
||||
clearExportImportProperties();
|
||||
clearExportImportProperties(testingClient);
|
||||
|
||||
RealmRepresentation realmRep = RealmBuilder.create()
|
||||
.name(REALM_NAME)
|
||||
.build();
|
||||
adminClient.realms().create(realmRep);
|
||||
String realmId = testRealmResource().toRepresentation().getId();
|
||||
String realmName = testRealmResource().toRepresentation().getRealm();
|
||||
|
||||
ComponentRepresentation parentComponent = new ComponentRepresentation();
|
||||
parentComponent.setParentId(realmId);
|
||||
|
@ -96,23 +123,36 @@ public class ComponentExportImportTest extends AbstractAuthTest implements Seria
|
|||
subcomponent.getConfig().putSingle("attr", "value2");
|
||||
String subcomponentId = addComponent(subcomponent);
|
||||
|
||||
final String exportFilePath = exportFile.getAbsolutePath();
|
||||
|
||||
// export
|
||||
testingClient.server().run(session -> {
|
||||
ExportImportConfig.setProvider(SingleFileExportProviderFactory.PROVIDER_ID);
|
||||
ExportImportConfig.setFile(exportFile.getAbsolutePath());
|
||||
ExportImportConfig.setRealmName(realmName);
|
||||
ExportImportConfig.setFile(exportFilePath);
|
||||
ExportImportConfig.setRealmName(REALM_NAME);
|
||||
ExportImportConfig.setAction(ExportImportConfig.ACTION_EXPORT);
|
||||
new ExportImportManager(session).runExport();
|
||||
});
|
||||
|
||||
testRealmResource().remove();
|
||||
|
||||
try {
|
||||
testRealmResource().toRepresentation();
|
||||
Assert.fail("Realm wasn't expected to be found");
|
||||
} catch (NotFoundException nfe) {
|
||||
// Expected
|
||||
}
|
||||
|
||||
// import
|
||||
testingClient.server().run(session -> {
|
||||
Assert.assertNull(session.realms().getRealmByName(TEST));
|
||||
Assert.assertNull(session.realms().getRealmByName(REALM_NAME));
|
||||
ExportImportConfig.setAction(ExportImportConfig.ACTION_IMPORT);
|
||||
new ExportImportManager(session).runImport();
|
||||
Assert.assertNotNull(session.realms().getRealmByName(TEST));
|
||||
});
|
||||
|
||||
// Assert realm was imported
|
||||
Assert.assertNotNull(testRealmResource().toRepresentation());
|
||||
|
||||
try {
|
||||
parentComponent = testRealmResource().components().component(parentComponentId).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.getConfig().getFirst("attr"), "value");
|
||||
|
||||
Assert.assertEquals(subcomponent.getParentId(), realmId);
|
||||
Assert.assertEquals(subcomponent.getParentId(), parentComponent.getId());
|
||||
Assert.assertEquals(subcomponent.getName(), "child");
|
||||
Assert.assertEquals(subcomponent.getSubType(), "subtype2");
|
||||
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.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
@ -16,17 +16,22 @@
|
|||
*/
|
||||
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.ClassRule;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.OAuth2Constants;
|
||||
import org.keycloak.admin.client.resource.RealmResource;
|
||||
import org.keycloak.common.constants.ServiceAccountConstants;
|
||||
import org.keycloak.common.util.MultivaluedHashMap;
|
||||
import org.keycloak.component.ComponentModel;
|
||||
import org.keycloak.events.Details;
|
||||
import org.keycloak.events.Event;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
|
@ -34,19 +39,27 @@ import org.keycloak.models.cache.CachedUserModel;
|
|||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
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.storage.UserStorageProvider;
|
||||
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.Constants;
|
||||
import org.keycloak.testsuite.OAuthClient;
|
||||
import org.keycloak.testsuite.auth.page.AuthRealm;
|
||||
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.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 org.keycloak.testsuite.runonserver.RunOnServerDeployment;
|
||||
import org.keycloak.testsuite.util.Matchers;
|
||||
import org.keycloak.testsuite.util.OAuthClient;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
@ -56,22 +69,52 @@ import java.util.Map;
|
|||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class UserStorageFailureTest {
|
||||
public static ComponentModel memoryProvider = null;
|
||||
public static String realmName;
|
||||
public static final String LOCAL_USER = "localUser";
|
||||
@ClassRule
|
||||
public static KeycloakRule keycloakRule = new KeycloakRule(new KeycloakRule.KeycloakSetup() {
|
||||
public class UserStorageFailureTest extends AbstractTestRealmKeycloakTest {
|
||||
|
||||
private static boolean initialized = false;
|
||||
|
||||
@Deployment
|
||||
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
|
||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
||||
UserStorageProviderModel model = new UserStorageProviderModel();
|
||||
model.setName("failure");
|
||||
model.setPriority(0);
|
||||
model.setProviderId(FailableHardcodedStorageProviderFactory.PROVIDER_ID);
|
||||
model.setParentId(appRealm.getId());
|
||||
memoryProvider = appRealm.addComponentModel(model);
|
||||
realmName = appRealm.getName();
|
||||
public void configureTestRealm(RealmRepresentation testRealm) {
|
||||
}
|
||||
|
||||
|
||||
@Before
|
||||
public void addProvidersBeforeTest() throws URISyntaxException, IOException {
|
||||
ComponentRepresentation memProvider = new ComponentRepresentation();
|
||||
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");
|
||||
offlineClient.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
|
||||
|
@ -79,7 +122,7 @@ public class UserStorageFailureTest {
|
|||
offlineClient.setDirectAccessGrantsEnabled(true);
|
||||
offlineClient.setSecret("secret");
|
||||
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.setServiceAccountsEnabled(true);
|
||||
offlineClient.setFullScopeAllowed(true);
|
||||
|
@ -93,29 +136,19 @@ public class UserStorageFailureTest {
|
|||
|
||||
UserModel localUser = manager.getSession().userLocalStorage().addUser(appRealm, LOCAL_USER);
|
||||
localUser.setEnabled(true);
|
||||
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
@Rule
|
||||
public WebRule webRule = new WebRule(this);
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
@WebResource
|
||||
protected OAuthClient oauth;
|
||||
|
||||
@WebResource
|
||||
protected WebDriver driver;
|
||||
|
||||
@WebResource
|
||||
protected AppPage appPage;
|
||||
|
||||
@WebResource
|
||||
protected LoginPage loginPage;
|
||||
|
||||
@Rule
|
||||
public AssertEvents events = new AssertEvents(keycloakRule);
|
||||
public RealmResource testRealmResource() {
|
||||
return adminClient.realm(AuthRealm.TEST);
|
||||
}
|
||||
|
||||
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.
|
||||
// see related JIRA - KEYCLOAK-5350 and corresponding test
|
||||
|
@ -124,16 +157,17 @@ public class UserStorageFailureTest {
|
|||
* KEYCLOAK-5350
|
||||
*/
|
||||
@Test
|
||||
public void testKeycloak5350() {
|
||||
public void testKeycloak5350() throws Exception {
|
||||
oauth.scope(OAuth2Constants.OFFLINE_ACCESS);
|
||||
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");
|
||||
|
||||
Event loginEvent = events.expectLogin()
|
||||
EventRepresentation loginEvent = events.expectLogin()
|
||||
.user(AssertEvents.isUUID())
|
||||
.client("offline-client")
|
||||
.detail(Details.REDIRECT_URI, Constants.AUTH_SERVER_ROOT + "/offline-client")
|
||||
.event();
|
||||
.detail(Details.REDIRECT_URI, OAuthClient.AUTH_SERVER_ROOT + "/offline-client")
|
||||
.assertEvent();
|
||||
|
||||
final String sessionId = loginEvent.getSessionId();
|
||||
String codeId = loginEvent.getDetails().get(Details.CODE_ID);
|
||||
|
@ -148,27 +182,23 @@ public class UserStorageFailureTest {
|
|||
|
||||
evictUser(FailableHardcodedStorageProvider.username);
|
||||
|
||||
KeycloakSession session;
|
||||
RealmModel realm;
|
||||
UserModel user;
|
||||
|
||||
toggleForceFail(true);
|
||||
|
||||
// make sure failure is turned on
|
||||
session = keycloakRule.startSession();
|
||||
realm = session.realms().getRealmByName(realmName);
|
||||
testingClient.server().run(session -> {
|
||||
RealmModel realm = session.realms().getRealmByName(AuthRealm.TEST);
|
||||
try {
|
||||
user = session.users().getUserByUsername(FailableHardcodedStorageProvider.username, realm);
|
||||
UserModel user = session.users().getUserByUsername(FailableHardcodedStorageProvider.username, realm);
|
||||
Assert.fail();
|
||||
} catch (Exception e) {
|
||||
Assert.assertEquals("FORCED FAILURE", e.getMessage());
|
||||
|
||||
}
|
||||
keycloakRule.stopSession(session, false);
|
||||
});
|
||||
|
||||
// restart server to make sure we can still boot if user storage is down
|
||||
keycloakRule.restartServer();
|
||||
keycloakRule.deployServlet("app", "/app", ApplicationServlet.class);
|
||||
controller.stop(suiteContext.getAuthServerInfo().getQualifier());
|
||||
controller.start(suiteContext.getAuthServerInfo().getQualifier());
|
||||
reconnectAdminClient();
|
||||
|
||||
toggleForceFail(false);
|
||||
|
||||
|
@ -184,33 +214,35 @@ public class UserStorageFailureTest {
|
|||
|
||||
}
|
||||
|
||||
protected void evictUser(String username) {
|
||||
KeycloakSession session = keycloakRule.startSession();
|
||||
RealmModel realm = session.realms().getRealmByName(realmName);
|
||||
protected void evictUser(final String username) {
|
||||
testingClient.server().run(session -> {
|
||||
RealmModel realm = session.realms().getRealmByName(AuthRealm.TEST);
|
||||
UserModel user = session.users().getUserByUsername(username, realm);
|
||||
session.userCache().evict(realm, user);
|
||||
keycloakRule.stopSession(session, true);
|
||||
});
|
||||
}
|
||||
|
||||
protected void toggleForceFail(boolean toggle) {
|
||||
KeycloakSession session;
|
||||
RealmModel realm;
|
||||
session = keycloakRule.startSession();
|
||||
protected void toggleForceFail(final boolean toggle) {
|
||||
final String failureProviderId = this.failureProviderId;
|
||||
|
||||
testingClient.server().run(session -> {
|
||||
RealmModel realm = session.realms().getRealmByName(AuthRealm.TEST);
|
||||
ComponentModel memoryProvider = realm.getComponent(failureProviderId);
|
||||
memoryProvider.getConfig().putSingle("fail", Boolean.toString(toggle));
|
||||
realm = session.realms().getRealmByName(realmName);
|
||||
realm.updateComponent(memoryProvider);
|
||||
keycloakRule.stopSession(session, true);
|
||||
});
|
||||
}
|
||||
|
||||
protected void toggleProviderEnabled(boolean toggle) {
|
||||
KeycloakSession session;
|
||||
RealmModel realm;
|
||||
session = keycloakRule.startSession();
|
||||
protected void toggleProviderEnabled(final boolean toggle) {
|
||||
final String failureProviderId = this.failureProviderId;
|
||||
|
||||
testingClient.server().run(session -> {
|
||||
RealmModel realm = session.realms().getRealmByName(AuthRealm.TEST);
|
||||
ComponentModel memoryProvider = realm.getComponent(failureProviderId);
|
||||
UserStorageProviderModel model = new UserStorageProviderModel(memoryProvider);
|
||||
model.setEnabled(toggle);
|
||||
realm = session.realms().getRealmByName(realmName);
|
||||
realm.updateComponent(model);
|
||||
keycloakRule.stopSession(session, true);
|
||||
});
|
||||
}
|
||||
|
||||
private void loginSuccessAndLogout(String username, String password) {
|
||||
|
@ -226,37 +258,37 @@ public class UserStorageFailureTest {
|
|||
|
||||
@Test
|
||||
public void testKeycloak5926() {
|
||||
oauth.clientId("test-app");
|
||||
oauth.redirectUri(OAuthClient.APP_AUTH_ROOT);
|
||||
|
||||
// make sure local copy is deleted
|
||||
{
|
||||
KeycloakSession session = keycloakRule.startSession();
|
||||
RealmModel realm = session.realms().getRealmByName(realmName);
|
||||
testingClient.server().run(session -> {
|
||||
RealmModel realm = session.realms().getRealmByName(AuthRealm.TEST);
|
||||
|
||||
UserModel user = session.userLocalStorage().getUserByUsername(FailableHardcodedStorageProvider.username, realm);
|
||||
if (user != null) {
|
||||
session.userLocalStorage().removeUser(realm, user);
|
||||
}
|
||||
keycloakRule.stopSession(session, true);
|
||||
}
|
||||
});
|
||||
|
||||
// query user to make sure its imported
|
||||
{
|
||||
KeycloakSession session = keycloakRule.startSession();
|
||||
RealmModel realm = session.realms().getRealmByName(realmName);
|
||||
testingClient.server().run(session -> {
|
||||
RealmModel realm = session.realms().getRealmByName(AuthRealm.TEST);
|
||||
|
||||
UserModel user = session.users().getUserByUsername(FailableHardcodedStorageProvider.username, realm);
|
||||
Assert.assertNotNull(user);
|
||||
keycloakRule.stopSession(session, true);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
evictUser(FailableHardcodedStorageProvider.username);
|
||||
evictUser(LOCAL_USER);
|
||||
|
||||
toggleForceFail(true);
|
||||
{
|
||||
KeycloakSession session = keycloakRule.startSession();
|
||||
// make sure we can still query local users
|
||||
RealmModel realm = session.realms().getRealmByName(realmName);
|
||||
|
||||
testingClient.server().run(session -> {
|
||||
RealmModel realm = session.realms().getRealmByName(AuthRealm.TEST);
|
||||
|
||||
UserModel local = session.users().getUserByUsername(LOCAL_USER, realm);
|
||||
Assert.assertNotNull(local);
|
||||
// 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
|
||||
loginSuccessAndLogout("test-user@localhost", "password");
|
||||
|
||||
toggleProviderEnabled(false);
|
||||
{
|
||||
KeycloakSession session = keycloakRule.startSession();
|
||||
// make sure we can still query local users
|
||||
RealmModel realm = session.realms().getRealmByName(realmName);
|
||||
|
||||
testingClient.server().run(session -> {
|
||||
RealmModel realm = session.realms().getRealmByName(AuthRealm.TEST);
|
||||
|
||||
UserModel local = session.users().getUserByUsername(LOCAL_USER, realm);
|
||||
Assert.assertNotNull(local);
|
||||
List<UserModel> result;
|
||||
|
@ -319,29 +351,27 @@ public class UserStorageFailureTest {
|
|||
} catch (Exception ex) {
|
||||
|
||||
}
|
||||
keycloakRule.stopSession(session, true);
|
||||
}
|
||||
});
|
||||
|
||||
// make sure user isn't cached as provider is disabled
|
||||
{
|
||||
KeycloakSession session = keycloakRule.startSession();
|
||||
RealmModel realm = session.realms().getRealmByName(realmName);
|
||||
testingClient.server().run(session -> {
|
||||
RealmModel realm = session.realms().getRealmByName(AuthRealm.TEST);
|
||||
|
||||
UserModel user = session.users().getUserByUsername(FailableHardcodedStorageProvider.username, realm);
|
||||
Assert.assertFalse(user instanceof CachedUserModel);
|
||||
Assert.assertEquals(FailableHardcodedStorageProvider.username, user.getUsername());
|
||||
Assert.assertEquals(FailableHardcodedStorageProvider.email, user.getEmail());
|
||||
keycloakRule.stopSession(session, true);
|
||||
}
|
||||
});
|
||||
|
||||
// make ABSOLUTELY sure user isn't cached as provider is disabled
|
||||
{
|
||||
KeycloakSession session = keycloakRule.startSession();
|
||||
RealmModel realm = session.realms().getRealmByName(realmName);
|
||||
testingClient.server().run(session -> {
|
||||
RealmModel realm = session.realms().getRealmByName(AuthRealm.TEST);
|
||||
|
||||
UserModel user = session.users().getUserByUsername(FailableHardcodedStorageProvider.username, realm);
|
||||
Assert.assertFalse(user instanceof CachedUserModel);
|
||||
Assert.assertEquals(FailableHardcodedStorageProvider.username, user.getUsername());
|
||||
Assert.assertEquals(FailableHardcodedStorageProvider.email, user.getEmail());
|
||||
keycloakRule.stopSession(session, true);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
@ -349,15 +379,14 @@ public class UserStorageFailureTest {
|
|||
toggleForceFail(false);
|
||||
|
||||
// user should be cachable now
|
||||
{
|
||||
KeycloakSession session = keycloakRule.startSession();
|
||||
RealmModel realm = session.realms().getRealmByName(realmName);
|
||||
testingClient.server().run(session -> {
|
||||
RealmModel realm = session.realms().getRealmByName(AuthRealm.TEST);
|
||||
|
||||
UserModel user = session.users().getUserByUsername(FailableHardcodedStorageProvider.username, realm);
|
||||
Assert.assertTrue(user instanceof CachedUserModel);
|
||||
Assert.assertEquals(FailableHardcodedStorageProvider.username, user.getUsername());
|
||||
Assert.assertEquals(FailableHardcodedStorageProvider.email, user.getEmail());
|
||||
keycloakRule.stopSession(session, true);
|
||||
}
|
||||
});
|
||||
|
||||
events.clear();
|
||||
}
|
|
@ -28,8 +28,13 @@ import static org.junit.Assert.fail;
|
|||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.admin.client.resource.RealmResource;
|
||||
import org.keycloak.admin.client.resource.UserResource;
|
||||
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.UserModel;
|
||||
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 org.keycloak.testsuite.AbstractAuthTest;
|
||||
import org.keycloak.testsuite.admin.ApiUtil;
|
||||
import org.keycloak.testsuite.arquillian.annotation.ModelTest;
|
||||
import org.keycloak.testsuite.federation.UserMapStorage;
|
||||
import org.keycloak.testsuite.federation.UserMapStorageFactory;
|
||||
import org.keycloak.testsuite.federation.UserPropertyFileStorageFactory;
|
||||
|
@ -61,6 +67,8 @@ import java.util.Map;
|
|||
import javax.mail.internet.MimeMessage;
|
||||
import org.jboss.arquillian.graphene.page.Page;
|
||||
import org.junit.Rule;
|
||||
import org.keycloak.testsuite.util.TestCleanup;
|
||||
|
||||
import static org.keycloak.testsuite.actions.RequiredActionEmailVerificationTest.getPasswordResetEmailLink;
|
||||
import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlDoesntStartWith;
|
||||
import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
|
||||
|
@ -154,11 +162,15 @@ public class UserStorageTest extends AbstractAuthTest {
|
|||
return propProviderRW;
|
||||
}
|
||||
|
||||
protected String addComponent(ComponentRepresentation component) {
|
||||
Response resp = testRealmResource().components().add(component);
|
||||
private String addComponent(ComponentRepresentation component) {
|
||||
return addComponent(testRealmResource(), getCleanup(), component);
|
||||
}
|
||||
|
||||
static String addComponent(RealmResource realmResource, TestCleanup testCleanup, ComponentRepresentation component) {
|
||||
Response resp = realmResource.components().add(component);
|
||||
resp.close();
|
||||
String id = ApiUtil.getCreatedId(resp);
|
||||
getCleanup().addComponentId(id);
|
||||
testCleanup.addComponentId(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
|
||||
public void testLoginSuccess() {
|
||||
loginSuccessAndLogout("tbrady", "goat");
|
||||
|
@ -416,13 +439,28 @@ public class UserStorageTest extends AbstractAuthTest {
|
|||
Assert.assertTrue(usernames.contains("thor"));
|
||||
|
||||
// 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
|
||||
public static WebArchive deploy() {
|
||||
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) {
|
||||
|
@ -677,6 +715,26 @@ public class UserStorageTest extends AbstractAuthTest {
|
|||
System.out.println("User class: " + user.getClass());
|
||||
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
|
||||
|
|
|
@ -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-ldap-federation"/>
|
||||
<module name="org.infinispan"/>
|
||||
<module name="org.apache.commons.io"/>
|
||||
<module name="org.apache.httpcomponents.core"/>
|
||||
</dependencies>
|
||||
</deployment>
|
||||
</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.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
@ -16,6 +16,12 @@
|
|||
*/
|
||||
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.credential.CredentialInput;
|
||||
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.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>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class UserMapStorage implements UserLookupProvider, UserStorageProvider, UserRegistrationProvider, CredentialInputUpdater, CredentialInputValidator {
|
||||
|
||||
private static final Logger log = Logger.getLogger(UserMapStorage.class);
|
||||
|
||||
protected Map<String, String> userPasswords;
|
||||
protected ComponentModel model;
|
||||
protected KeycloakSession session;
|
||||
|
||||
public static final AtomicInteger allocations = 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) {
|
||||
this.session = session;
|
||||
|
@ -58,12 +64,13 @@ public class UserMapStorage implements UserLookupProvider, UserStorageProvider,
|
|||
allocations.incrementAndGet();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public UserModel getUserById(String id, RealmModel realm) {
|
||||
StorageId storageId = new StorageId(id);
|
||||
final String username = storageId.getExternalId();
|
||||
if (!userPasswords.containsKey(username)) return null;
|
||||
if (!userPasswords.containsKey(username)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return createUser(realm, username);
|
||||
}
|
||||
|
@ -90,7 +97,9 @@ public class UserMapStorage implements UserLookupProvider, UserStorageProvider,
|
|||
|
||||
@Override
|
||||
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)) {
|
||||
userPasswords.put(user.getUsername(), ((UserCredentialModel) input).getValue());
|
||||
return true;
|
||||
|
@ -117,7 +126,9 @@ public class UserMapStorage implements UserLookupProvider, UserStorageProvider,
|
|||
|
||||
@Override
|
||||
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)) {
|
||||
String pw = userPasswords.get(user.getUsername());
|
||||
return pw != null && pw.equals(((UserCredentialModel) input).getValue());
|
||||
|
@ -128,7 +139,9 @@ public class UserMapStorage implements UserLookupProvider, UserStorageProvider,
|
|||
|
||||
@Override
|
||||
public UserModel getUserByUsername(String username, RealmModel realm) {
|
||||
if (!userPasswords.containsKey(username)) return null;
|
||||
if (!userPasswords.containsKey(username)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return createUser(realm, username);
|
||||
}
|
||||
|
@ -151,22 +164,25 @@ public class UserMapStorage implements UserLookupProvider, UserStorageProvider,
|
|||
|
||||
@Override
|
||||
public void preRemove(RealmModel realm) {
|
||||
|
||||
log.infof("preRemove: realm=%s", realm.getName());
|
||||
realmRemovals.incrementAndGet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preRemove(RealmModel realm, GroupModel group) {
|
||||
|
||||
log.infof("preRemove: realm=%s, group=%s", realm.getName(), group.getName());
|
||||
groupRemovals.incrementAndGet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preRemove(RealmModel realm, RoleModel role) {
|
||||
|
||||
log.infof("preRemove: realm=%s, role=%s", realm.getName(), role.getName());
|
||||
roleRemovals.incrementAndGet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
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.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
@ -16,15 +16,18 @@
|
|||
*/
|
||||
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.component.ComponentModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.provider.ProviderConfigProperty;
|
||||
import org.keycloak.storage.UserStorageProviderFactory;
|
||||
|
||||
import java.util.Hashtable;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
|
@ -32,9 +35,23 @@ import java.util.Map;
|
|||
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
|
||||
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.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
@ -16,6 +16,12 @@
|
|||
*/
|
||||
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.credential.CredentialInput;
|
||||
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.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>
|
||||
* @version $Revision: 1 $
|
||||
|
@ -137,7 +137,6 @@ public class UserPropertyFileStorage implements UserLookupProvider, UserStorageP
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getUsersCount(RealmModel realm) {
|
||||
return userPasswords.size();
|
||||
|
@ -191,7 +190,6 @@ public class UserPropertyFileStorage implements UserLookupProvider, UserStorageP
|
|||
|
||||
@Override
|
||||
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);
|
||||
if (username == null) return Collections.EMPTY_LIST;
|
||||
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.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
@ -16,39 +16,85 @@
|
|||
*/
|
||||
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.common.util.EnvUtil;
|
||||
import org.keycloak.component.ComponentModel;
|
||||
import org.keycloak.component.ComponentValidationException;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.provider.ProviderConfigProperty;
|
||||
import org.keycloak.provider.ProviderConfigurationBuilder;
|
||||
import org.keycloak.storage.UserStorageProviderFactory;
|
||||
import org.keycloak.storage.UserStorageProviderModel;
|
||||
import org.keycloak.storage.user.ImportSynchronization;
|
||||
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>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
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
|
||||
public UserPropertyFileStorage create(KeycloakSession session, ComponentModel model) {
|
||||
String path = model.getConfig().getFirst(PROPERTY_FILE);
|
||||
path = EnvUtil.replace(path);
|
||||
|
||||
Properties props = new Properties();
|
||||
try {
|
||||
props.load(getClass().getResourceAsStream(model.getConfig().getFirst("propertyFile")));
|
||||
try (InputStream is = new FileInputStream(path)) {
|
||||
props.load(is);
|
||||
is.close();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
return new UserPropertyFileStorage(session, model, props);
|
||||
}
|
||||
|
||||
|
@ -57,17 +103,9 @@ public class UserPropertyFileStorageFactory implements UserStorageProviderFactor
|
|||
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
|
||||
public List<ProviderConfigProperty> getConfigProperties() {
|
||||
return OPTIONS;
|
||||
return CONFIG_PROPERTIES;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -94,4 +132,5 @@ public class UserPropertyFileStorageFactory implements UserStorageProviderFactor
|
|||
public SynchronizationResult syncSince(Date lastSync, KeycloakSessionFactory sessionFactory, String realmId, UserStorageProviderModel model) {
|
||||
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