Merge pull request #3309 from vramik/migration

KEYCLOAK-3489 KEYCLOAK-3609
This commit is contained in:
Pavel Drozd 2016-10-12 14:35:24 +02:00 committed by GitHub
commit 455db1add4
12 changed files with 4831 additions and 403 deletions

View file

@ -437,6 +437,18 @@
<requireProperty>
<property>keycloak.connectionsJpa.password</property>
</requireProperty>
<requireProperty>
<property>keycloak.connectionsJpa.url</property>
</requireProperty>
<requireProperty>
<property>db.hostname</property>
</requireProperty>
<requireProperty>
<property>db.name</property>
</requireProperty>
<requireProperty>
<property>db.port</property>
</requireProperty>
</rules>
</configuration>
</execution>

View file

@ -75,6 +75,18 @@
<requireProperty>
<property>keycloak.connectionsJpa.password</property>
</requireProperty>
<requireProperty>
<property>keycloak.connectionsJpa.url</property>
</requireProperty>
<requireProperty>
<property>db.hostname</property>
</requireProperty>
<requireProperty>
<property>db.name</property>
</requireProperty>
<requireProperty>
<property>db.port</property>
</requireProperty>
</rules>
</configuration>
</execution>

View file

@ -88,7 +88,7 @@
<xsl:if test="$driver != 'h2'">
<driver name="{$driver}" module="com.{$driver}">
<xa-datasource-class>
<xsl:value-of select="$xa.datasource.class"/>
<xsl:value-of select="$datasource.class.xa"/>
</xa-datasource-class>
</driver>
</xsl:if>

View file

@ -64,8 +64,7 @@ public class AuthServerTestEnricher {
private static final String AUTH_SERVER_CLUSTER_PROPERTY = "auth.server.cluster";
public static final boolean AUTH_SERVER_CLUSTER = Boolean.parseBoolean(System.getProperty(AUTH_SERVER_CLUSTER_PROPERTY, "false"));
private static final String MIGRATION_PROPERTY = "auth.server.jboss.migration";
private static final Boolean MIGRATION_ENABLED = Boolean.parseBoolean(System.getProperty(MIGRATION_PROPERTY));
private static final Boolean AUTO_MIGRATION_ENABLED = "auto".equals(System.getProperty("migration.mode"));
@Inject
@SuiteScoped
@ -131,7 +130,7 @@ public class AuthServerTestEnricher {
throw new RuntimeException(String.format("No auth server container matching '%sN' found in arquillian.xml.", authServerBackend));
}
if (MIGRATION_ENABLED) {
if (AUTO_MIGRATION_ENABLED) {
// init migratedAuthServerInfo
for (ContainerInfo container : suiteContext.getContainers()) {
// migrated auth server
@ -166,7 +165,7 @@ public class AuthServerTestEnricher {
public void startMigratedContainer(@Observes(precedence = 2) StartSuiteContainers event) {
if (suiteContext.isAuthServerMigrationEnabled()) {
log.info("\n\n### Starting keycloak " + System.getProperty("version", "- previous") + " ###\n");
log.info("\n\n### Starting keycloak " + System.getProperty("migrated.auth.server.version", "- previous") + " ###\n\n");
startContainerEvent.fire(new StartContainer(suiteContext.getMigratedAuthServerInfo().getArquillianContainer()));
}
}

View file

@ -27,7 +27,7 @@ import java.lang.reflect.Method;
*/
public class MigrationTestExecutionDecider implements TestExecutionDecider {
public static final String MIGRATED_AUTH_SERVER_VERSION_PROPERTY = "migrated.auth.server.version";
private static final String MIGRATED_AUTH_SERVER_VERSION_PROPERTY = "migrated.auth.server.version";
@Override
public ExecutionDecision decide(Method method) {

View file

@ -19,6 +19,7 @@ package org.keycloak.testsuite;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.ConfigPropertyRepresentation;
import org.keycloak.representations.idm.GroupRepresentation;
import org.keycloak.representations.idm.IdentityProviderRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.RoleRepresentation;
@ -72,6 +73,8 @@ public class Assert extends org.junit.Assert {
return ((UserRepresentation) o1).getUsername();
} else if (o1 instanceof UserFederationProviderFactoryRepresentation) {
return ((UserFederationProviderFactoryRepresentation) o1).getId();
} else if (o1 instanceof GroupRepresentation) {
return ((GroupRepresentation) o1).getName();
}
throw new IllegalArgumentException();

View file

@ -16,22 +16,39 @@
*/
package org.keycloak.testsuite.migration;
import org.junit.Before;
import java.util.HashSet;
import org.junit.Test;
import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.testsuite.AbstractKeycloakTest;
import org.keycloak.testsuite.Assert;
import org.keycloak.testsuite.arquillian.migration.Migration;
import java.util.List;
import java.util.Set;
import org.junit.Before;
import org.keycloak.admin.client.resource.ClientResource;
import org.keycloak.admin.client.resource.RoleResource;
import org.keycloak.models.AdminRoles;
import org.keycloak.models.AuthenticationExecutionModel;
import org.keycloak.models.Constants;
import org.keycloak.models.UserModel;
import org.keycloak.models.utils.DefaultAuthenticationFlows;
import org.keycloak.representations.idm.AuthenticationExecutionExportRepresentation;
import org.keycloak.representations.idm.AuthenticationFlowRepresentation;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.GroupRepresentation;
import org.keycloak.representations.idm.RequiredActionProviderRepresentation;
import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import static org.keycloak.testsuite.Assert.*;
import static org.keycloak.testsuite.auth.page.AuthRealm.MASTER;
/**
* @author <a href="mailto:vramik@redhat.com">Vlastislav Ramik</a>
*/
public class MigrationTest extends AbstractKeycloakTest {
private final String migrationRealmName = "Migration";
private final String MIGRATION = "Migration";
@Override
public void addTestRealms(List<RealmRepresentation> testRealms) {
@ -40,31 +57,116 @@ public class MigrationTest extends AbstractKeycloakTest {
@Before
public void beforeMigrationTest() {
//add migration realm to testRealmReps to make the migration removed after test
testRealmReps.add(adminClient.realms().realm(MIGRATION).toRepresentation());
}
@Test
@Migration(versionFrom = "1.9.8.Final")
public void migration198Test() {
//test migrated data
test198();
RealmResource migrationRealm = adminClient.realms().realm(MIGRATION);
RealmResource masterRealm = adminClient.realms().realm(MASTER);
//import realm from previous version and test imported data
MigrationUtil.executeImport(testingClient);
test198();
testMigratedMasterData(masterRealm);
testMigratedMigrationData(migrationRealm);
// 2.0.0 - org.keycloak.migration.migrators.MigrateTo2_0_0
testAuthorizationServices(masterRealm, migrationRealm);
// 2.1.0 - org.keycloak.migration.migrators.MigrateTo2_1_0
testNameOfOTPRequiredAction(masterRealm, migrationRealm);
//there is no migration of RolePolicies (MigrateTo2_1_0#migrateRolePolicies) between 1.9.8 to current version (2.3.0-SNAPSHOT)
// 2.2.0 - org.keycloak.migration.migrators.MigrateTo2_2_0
testIdentityProviderAuthenticator(masterRealm, migrationRealm);
}
private void test198() {
RealmResource realmResource = adminClient.realms().realm(migrationRealmName);
@Test
@Migration(versionFrom = "2.2.1.Final")
public void migration221Test() {
RealmResource migrationRealm = adminClient.realms().realm(MIGRATION);
RealmResource masterRealm = adminClient.realms().realm(MASTER);
Assert.assertNames(realmResource.roles().list(), "offline_access", "uma_authorization");
Assert.assertNames(realmResource.clients().findAll(), "admin-cli", "realm-management", "security-admin-console", "broker", "account");
testMigratedMasterData(masterRealm);
testMigratedMigrationData(migrationRealm);
//TODO - add more asserts
//cleanup
RealmRepresentation realmRep = realmResource.toRepresentation();
log.info("removing '" + realmRep.getRealm() + "' realm");
removeRealm(realmRep);
// so far nothing else
}
private void testMigratedMasterData(RealmResource master) {
assertNames(master.roles().list(), "offline_access", "uma_authorization", "create-realm", "master-test-realm-role", "admin");
assertNames(master.clients().findAll(), "admin-cli", "security-admin-console", "broker", "account",
"master-realm", "master-test-client", "Migration-realm");
String id = master.clients().findByClientId("master-test-client").get(0).getId();
assertNames(master.clients().get(id).roles().list(), "master-test-client-role");
assertNames(master.users().search("", 0, 5), "admin", "master-test-user");
assertNames(master.groups().groups(), "master-test-group");
}
private void testMigratedMigrationData(RealmResource migration) {
assertNames(migration.roles().list(), "offline_access", "uma_authorization", "migration-test-realm-role");
assertNames(migration.clients().findAll(), "account", "admin-cli", "broker", "migration-test-client", "realm-management", "security-admin-console");
String id = migration.clients().findByClientId("migration-test-client").get(0).getId();
assertNames(migration.clients().get(id).roles().list(), "migration-test-client-role");
assertNames(migration.users().search("", 0, 5), "migration-test-user");
assertNames(migration.groups().groups(), "migration-test-group");
}
private void testAuthorizationServices(RealmResource... realms) {
for (RealmResource realm : realms) {
//test setup of authorization services
for (String roleName : Constants.AUTHZ_DEFAULT_AUTHORIZATION_ROLES) {
RoleResource role = realm.roles().get(roleName); //throw javax.ws.rs.NotFoundException
assertFalse("Role's scopeParamRequired should be false.", role.toRepresentation().isScopeParamRequired());
assertFalse("Role shouldn't be composite should be false.", role.toRepresentation().isComposite());
assertTrue("role should be added to default roles for new users", realm.toRepresentation().getDefaultRoles().contains(roleName));
}
//test admin roles - master admin client
List<ClientRepresentation> clients = realm.clients().findByClientId(realm.toRepresentation().getRealm() + "-realm");
if (!clients.isEmpty()) {
ClientResource masterAdminClient = realm.clients().get(clients.get(0).getId());
masterAdminClient.roles().get(AdminRoles.VIEW_AUTHORIZATION).toRepresentation();
masterAdminClient.roles().get(AdminRoles.MANAGE_AUTHORIZATION).toRepresentation();
//test admin roles - admin role composite
Set<String> roleNames = new HashSet<>();
for (RoleRepresentation role : realm.roles().get(AdminRoles.ADMIN).getRoleComposites()) {
roleNames.add(role.getName());
}
assertTrue(AdminRoles.VIEW_AUTHORIZATION + " should be composite role of " + AdminRoles.ADMIN, roleNames.contains(AdminRoles.VIEW_AUTHORIZATION));
assertTrue(AdminRoles.MANAGE_AUTHORIZATION + " should be composite role of " + AdminRoles.ADMIN, roleNames.contains(AdminRoles.MANAGE_AUTHORIZATION));
}
}
}
private void testNameOfOTPRequiredAction(RealmResource... realms) {
for (RealmResource realm : realms) {
RequiredActionProviderRepresentation otpAction = realm.flows().getRequiredAction(UserModel.RequiredAction.CONFIGURE_TOTP.name());
assertEquals("The name of CONFIGURE_TOTP required action should be 'Configure OTP'.", "Configure OTP", otpAction.getName());
}
}
private void testIdentityProviderAuthenticator(RealmResource... realms) {
for (RealmResource realm : realms) {
boolean success = false;
for (AuthenticationFlowRepresentation flow : realm.flows().getFlows()) {
if (flow.getAlias().equals(DefaultAuthenticationFlows.BROWSER_FLOW)) {
for (AuthenticationExecutionExportRepresentation execution : flow.getAuthenticationExecutions()) {
if ("identity-provider-redirector".equals(execution.getAuthenticator())) {
assertEquals("Requirement should be ALTERNATIVE.", AuthenticationExecutionModel.Requirement.ALTERNATIVE.name(), execution.getRequirement());
assertTrue("Priority should be 25.", execution.getPriority() == 25);
success = true;
}
}
}
}
if (!success) {
fail("BROWSER_FLOW should contain execution: 'identity-provider-redirector' authenticator.");
}
}
}
}

View file

@ -1,55 +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.migration;
import org.keycloak.exportimport.ExportImportConfig;
import org.keycloak.exportimport.singlefile.SingleFileExportProviderFactory;
import org.keycloak.testsuite.client.KeycloakTestingClient;
import java.io.File;
import static org.keycloak.testsuite.arquillian.migration.MigrationTestExecutionDecider.MIGRATED_AUTH_SERVER_VERSION_PROPERTY;
/**
* @author <a href="mailto:vramik@redhat.com">Vlastislav Ramik</a>
*/
public class MigrationUtil {
private static final String migratedAuthServerVersion = System.getProperty(MIGRATED_AUTH_SERVER_VERSION_PROPERTY);
static void executeImport(KeycloakTestingClient testingClient) {
String realmJsonName = "migration-realm-" + migratedAuthServerVersion + ".json";
File file = getRealmFilePath(realmJsonName, "src", "test", "resources", "migration-test");
testingClient.testing().exportImport().setProvider(SingleFileExportProviderFactory.PROVIDER_ID);
testingClient.testing().exportImport().setFile(file.getAbsolutePath());
// Configure import
testingClient.testing().exportImport().setAction(ExportImportConfig.ACTION_IMPORT);
testingClient.testing().exportImport().runImport();
}
private static File getRealmFilePath(String fileName, String... path) {
StringBuilder builder = new StringBuilder();
for (String dir : path) {
builder.append(dir).append(File.separator);
}
builder.append(fileName);
return new File(builder.toString());
}
}

View file

@ -66,6 +66,7 @@
-Djboss.socket.binding.port-offset=${auth.server.port.offset}
-Djboss.bind.address=0.0.0.0
${adapter.test.props}
${migration.import.properties}
</property>
<property name="javaVmArguments">
${auth.server.memory.settings}
@ -158,12 +159,8 @@
<property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
<property name="jbossHome">${keycloak.migration.home}</property>
<property name="javaVmArguments">
-Dkeycloak.migration.action=import
-Dkeycloak.migration.provider=singleFile
-Dkeycloak.migration.file=${keycloak.migration.file}
-Dkeycloak.migration.strategy=OVERWRITE_EXISTING
-Dkeycloak.migration.realmName=Migration
-Djboss.socket.binding.port-offset=${auth.server.port.offset}
-Djboss.socket.binding.port-offset=${auth.server.port.offset}
${migration.import.props.previous}
${auth.server.memory.settings}
</property>
<property name="managementPort">${auth.server.management.port}</property>

View file

@ -65,6 +65,7 @@
<auth.server.remote>false</auth.server.remote>
<adapter.test.props/>
<migration.import.properties/>
<examples.home>${project.build.directory}/examples</examples.home>
<browser>phantomjs</browser>
@ -168,6 +169,7 @@
<auth.server.remote>${auth.server.remote}</auth.server.remote>
<adapter.test.props>${adapter.test.props}</adapter.test.props>
<migration.import.properties>${migration.import.properties}</migration.import.properties>
<testsuite.constants>${testsuite.constants}</testsuite.constants>
@ -406,14 +408,41 @@
<!-- Profile for migration tests-->
<profile>
<id>migration</id>
<id>migration-auto</id>
<activation>
<property>
<name>migrated.auth.server.version</name>
<name>migration.mode</name>
<value>auto</value>
</property>
</activation>
<properties>
<migration.import.props.previous>
-Dkeycloak.migration.action=import
-Dkeycloak.migration.provider=singleFile
-Dkeycloak.migration.file=src/test/resources/migration-test/migration-realm-${migrated.auth.server.version}.json
-Dkeycloak.migration.strategy=OVERWRITE_EXISTING
</migration.import.props.previous>
<skip.add.user.json>true</skip.add.user.json>
</properties>
<build>
<plugins>
<plugin>
<artifactId>maven-enforcer-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<requireProperty>
<property>migrated.auth.server.version</property>
</requireProperty>
</rules>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
@ -445,13 +474,62 @@
<migrated.auth.server.version>${migrated.auth.server.version}</migrated.auth.server.version>
<auth.server.jboss.migration>true</auth.server.jboss.migration>
<keycloak.migration.home>${containers.home}/keycloak-${migrated.auth.server.version}</keycloak.migration.home>
<keycloak.migration.file>src/test/resources/migration-test/migration-realm-${migrated.auth.server.version}.json</keycloak.migration.file>
<migration.import.props.previous>${migration.import.props.previous}</migration.import.props.previous>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profile>
<profile>
<id>migration-import</id>
<activation>
<property>
<name>migration.mode</name>
<value>import</value>
</property>
</activation>
<properties>
<migration.import.properties>
-Dkeycloak.migration.action=import
-Dkeycloak.migration.provider=singleFile
-Dkeycloak.migration.file=src/test/resources/migration-test/migration-realm-${migrated.auth.server.version}.json
-Dkeycloak.migration.strategy=OVERWRITE_EXISTING
</migration.import.properties>
<skip.add.user.json>true</skip.add.user.json>
</properties>
<build>
<plugins>
<plugin>
<artifactId>maven-enforcer-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<requireProperty>
<property>migrated.auth.server.version</property>
</requireProperty>
</rules>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<systemPropertyVariables>
<migrated.auth.server.version>${migrated.auth.server.version}</migrated.auth.server.version>
<migration.import.properties>${migration.import.properties}</migration.import.properties>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>no-account</id>