/*
* 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.exportimport;
import org.jboss.arquillian.container.spi.client.container.LifecycleException;
import org.junit.After;
import org.junit.Test;
import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.exportimport.ExportImportConfig;
import org.keycloak.exportimport.dir.DirExportProvider;
import org.keycloak.exportimport.dir.DirExportProviderFactory;
import org.keycloak.exportimport.singlefile.SingleFileExportProviderFactory;
import org.keycloak.representations.idm.ComponentRepresentation;
import org.keycloak.representations.idm.KeysMetadataRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.testsuite.AbstractKeycloakTest;
import org.keycloak.testsuite.Assert;
import org.keycloak.testsuite.util.UserBuilder;
import java.io.File;
import java.net.URL;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import static org.junit.Assert.assertEquals;
import static org.keycloak.testsuite.admin.AbstractAdminTest.loadJson;
/**
*
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
* @author Stan Silvert ssilvert@redhat.com (C) 2016 Red Hat Inc.
*/
public class ExportImportTest extends AbstractKeycloakTest {
@Override
public void addTestRealms(List<RealmRepresentation> testRealms) {
RealmRepresentation testRealm1 = loadJson(getClass().getResourceAsStream("/testrealm.json"), RealmRepresentation.class);
testRealm1.getUsers().add(makeUser("user1"));
testRealm1.getUsers().add(makeUser("user2"));
testRealm1.getUsers().add(makeUser("user3"));
testRealms.add(testRealm1);
RealmRepresentation testRealm2 = loadJson(getClass().getResourceAsStream("/model/testrealm.json"), RealmRepresentation.class);
testRealm2.setId("test-realm");
testRealms.add(testRealm2);
}
private UserRepresentation makeUser(String userName) {
return UserBuilder.create()
.username(userName)
.email(userName + "@test.com")
.password("password")
.build();
}
@After
public void clearExportImportProps() throws LifecycleException {
clearExportImportProperties();
}
@Test
public void testDirFullExportImport() throws Throwable {
testingClient.testing().exportImport().setProvider(DirExportProviderFactory.PROVIDER_ID);
String targetDirPath = testingClient.testing().exportImport().getExportImportTestDirectory()+ File.separator + "dirExport";
DirExportProvider.recursiveDeleteDir(new File(targetDirPath));
testingClient.testing().exportImport().setDir(targetDirPath);
testingClient.testing().exportImport().setUsersPerFile(ExportImportConfig.DEFAULT_USERS_PER_FILE);
testFullExportImport();
// There should be 6 files in target directory (3 realm, 3 user)
assertEquals(6, new File(targetDirPath).listFiles().length);
}
@Test
public void testDirRealmExportImport() throws Throwable {
testingClient.testing()
.exportImport()
.setProvider(DirExportProviderFactory.PROVIDER_ID);
String targetDirPath = testingClient.testing().exportImport().getExportImportTestDirectory() + File.separator + "dirRealmExport";
DirExportProvider.recursiveDeleteDir(new File(targetDirPath));
testingClient.testing().exportImport().setDir(targetDirPath);
testingClient.testing().exportImport().setUsersPerFile(3);
testRealmExportImport();
// There should be 3 files in target directory (1 realm, 4 user)
File[] files = new File(targetDirPath).listFiles();
assertEquals(5, files.length);
}
@Test
public void testSingleFileFullExportImport() throws Throwable {
testingClient.testing().exportImport().setProvider(SingleFileExportProviderFactory.PROVIDER_ID);
String targetFilePath = testingClient.testing().exportImport().getExportImportTestDirectory() + File.separator + "singleFile-full.json";
testingClient.testing().exportImport().setFile(targetFilePath);
testFullExportImport();
}
@Test
public void testSingleFileRealmExportImport() throws Throwable {
testingClient.testing().exportImport().setProvider(SingleFileExportProviderFactory.PROVIDER_ID);
String targetFilePath = testingClient.testing().exportImport().getExportImportTestDirectory() + File.separator + "singleFile-realm.json";
testingClient.testing().exportImport().setFile(targetFilePath);
testRealmExportImport();
}
@Test
public void testSingleFileRealmWithoutBuiltinsImport() throws Throwable {
// Remove test realm
removeRealm("test-realm");
// Set the realm, which doesn't have builtin clients/roles inside JSON
testingClient.testing().exportImport().setProvider(SingleFileExportProviderFactory.PROVIDER_ID);
URL url = ExportImportTest.class.getResource("/model/testrealm.json");
String targetFilePath = new File(url.getFile()).getAbsolutePath();
testingClient.testing().exportImport().setFile(targetFilePath);
testingClient.testing().exportImport().setAction(ExportImportConfig.ACTION_IMPORT);
testingClient.testing().exportImport().runImport();
RealmResource testRealmRealm = adminClient.realm("test-realm");
ExportImportUtil.assertDataImportedInRealm(adminClient, testingClient, testRealmRealm.toRepresentation());
}
private void testFullExportImport() throws LifecycleException {
testingClient.testing().exportImport().setAction(ExportImportConfig.ACTION_EXPORT);
testingClient.testing().exportImport().setRealmName("");
testingClient.testing().exportImport().runExport();
removeRealm("test");
removeRealm("test-realm");
Assert.assertNames(adminClient.realms().findAll(), "master");
assertNotAuthenticated("test", "test-user@localhost", "password");
assertNotAuthenticated("test", "user1", "password");
assertNotAuthenticated("test", "user2", "password");
assertNotAuthenticated("test", "user3", "password");
// Configure import
testingClient.testing().exportImport().setAction(ExportImportConfig.ACTION_IMPORT);
testingClient.testing().exportImport().runImport();
// Ensure data are imported back
Assert.assertNames(adminClient.realms().findAll(), "master", "test", "test-realm");
assertAuthenticated("test", "test-user@localhost", "password");
assertAuthenticated("test", "user1", "password");
assertAuthenticated("test", "user2", "password");
assertAuthenticated("test", "user3", "password");
}
private void testRealmExportImport() throws LifecycleException {
testingClient.testing().exportImport().setAction(ExportImportConfig.ACTION_EXPORT);
testingClient.testing().exportImport().setRealmName("test");
testingClient.testing().exportImport().runExport();
List<ComponentRepresentation> components = adminClient.realm("test").components().query();
KeysMetadataRepresentation keyMetadata = adminClient.realm("test").keys().getKeyMetadata();
String sampleRealmRoleId = adminClient.realm("test").roles().get("sample-realm-role").toRepresentation().getId();
String testAppId = adminClient.realm("test").clients().findByClientId("test-app").get(0).getId();
String sampleClientRoleId = adminClient.realm("test").clients().get(testAppId).roles().get("sample-client-role").toRepresentation().getId();
// Delete some realm (and some data in admin realm)
adminClient.realm("test").remove();
Assert.assertNames(adminClient.realms().findAll(), "test-realm", "master");
assertNotAuthenticated("test", "test-user@localhost", "password");
assertNotAuthenticated("test", "user1", "password");
assertNotAuthenticated("test", "user2", "password");
assertNotAuthenticated("test", "user3", "password");
// Configure import
testingClient.testing().exportImport().setAction(ExportImportConfig.ACTION_IMPORT);
testingClient.testing().exportImport().runImport();
// Ensure data are imported back, but just for "test" realm
Assert.assertNames(adminClient.realms().findAll(), "master", "test", "test-realm");
assertAuthenticated("test", "test-user@localhost", "password");
assertAuthenticated("test", "user1", "password");
assertAuthenticated("test", "user2", "password");
assertAuthenticated("test", "user3", "password");
List<ComponentRepresentation> componentsImported = adminClient.realm("test").components().query();
assertComponents(components, componentsImported);
KeysMetadataRepresentation keyMetadataImported = adminClient.realm("test").keys().getKeyMetadata();
assertEquals(keyMetadata.getActive(), keyMetadataImported.getActive());
String importedSampleRealmRoleId = adminClient.realm("test").roles().get("sample-realm-role").toRepresentation().getId();
assertEquals(sampleRealmRoleId, importedSampleRealmRoleId);
String importedSampleClientRoleId = adminClient.realm("test").clients().get(testAppId).roles().get("sample-client-role").toRepresentation().getId();
assertEquals(sampleClientRoleId, importedSampleClientRoleId);
}
private void assertAuthenticated(String realmName, String username, String password) {
assertAuth(true, realmName, username, password);
}
private void assertNotAuthenticated(String realmName, String username, String password) {
assertAuth(false, realmName, username, password);
}
private void assertAuth(boolean expectedResult, String realmName, String username, String password) {
assertEquals(expectedResult, testingClient.testing().validCredentials(realmName, username, password));
}
private void assertComponents(List<ComponentRepresentation> expected, List<ComponentRepresentation> actual) {
expected.sort((o1, o2) -> o1.getId().compareTo(o2.getId()));
actual.sort((o1, o2) -> o1.getId().compareTo(o2.getId()));
assertEquals(expected.size(), actual.size());
for (int i = 0 ; i < expected.size(); i++) {
ComponentRepresentation e = expected.get(i);
ComponentRepresentation a = actual.get(i);
assertEquals(e.getId(), a.getId());
assertEquals(e.getName(), a.getName());
assertEquals(e.getProviderId(), a.getProviderId());
assertEquals(e.getProviderType(), a.getProviderType());
assertEquals(e.getParentId(), a.getParentId());
assertEquals(e.getSubType(), a.getSubType());
Assert.assertNames(e.getConfig().keySet(), a.getConfig().keySet().toArray(new String[] {}));
// Compare config values without take order into account
for (Map.Entry<String, List<String>> entry : e.getConfig().entrySet()) {
List<String> eList = entry.getValue();
List<String> aList = a.getConfig().getList(entry.getKey());
Assert.assertNames(eList, aList.toArray(new String[] {}));
}
}
}
private 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);
}
}
}