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> <requireProperty>
<property>keycloak.connectionsJpa.password</property> <property>keycloak.connectionsJpa.password</property>
</requireProperty> </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> </rules>
</configuration> </configuration>
</execution> </execution>

View file

@ -75,6 +75,18 @@
<requireProperty> <requireProperty>
<property>keycloak.connectionsJpa.password</property> <property>keycloak.connectionsJpa.password</property>
</requireProperty> </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> </rules>
</configuration> </configuration>
</execution> </execution>

View file

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

View file

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

View file

@ -27,7 +27,7 @@ import java.lang.reflect.Method;
*/ */
public class MigrationTestExecutionDecider implements TestExecutionDecider { 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 @Override
public ExecutionDecision decide(Method method) { 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.ClientRepresentation;
import org.keycloak.representations.idm.ConfigPropertyRepresentation; import org.keycloak.representations.idm.ConfigPropertyRepresentation;
import org.keycloak.representations.idm.GroupRepresentation;
import org.keycloak.representations.idm.IdentityProviderRepresentation; import org.keycloak.representations.idm.IdentityProviderRepresentation;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.RoleRepresentation; import org.keycloak.representations.idm.RoleRepresentation;
@ -72,6 +73,8 @@ public class Assert extends org.junit.Assert {
return ((UserRepresentation) o1).getUsername(); return ((UserRepresentation) o1).getUsername();
} else if (o1 instanceof UserFederationProviderFactoryRepresentation) { } else if (o1 instanceof UserFederationProviderFactoryRepresentation) {
return ((UserFederationProviderFactoryRepresentation) o1).getId(); return ((UserFederationProviderFactoryRepresentation) o1).getId();
} else if (o1 instanceof GroupRepresentation) {
return ((GroupRepresentation) o1).getName();
} }
throw new IllegalArgumentException(); throw new IllegalArgumentException();

View file

@ -16,22 +16,39 @@
*/ */
package org.keycloak.testsuite.migration; package org.keycloak.testsuite.migration;
import org.junit.Before; import java.util.HashSet;
import org.junit.Test; import org.junit.Test;
import org.keycloak.admin.client.resource.RealmResource; import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.testsuite.AbstractKeycloakTest; import org.keycloak.testsuite.AbstractKeycloakTest;
import org.keycloak.testsuite.Assert;
import org.keycloak.testsuite.arquillian.migration.Migration; import org.keycloak.testsuite.arquillian.migration.Migration;
import java.util.List; 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> * @author <a href="mailto:vramik@redhat.com">Vlastislav Ramik</a>
*/ */
public class MigrationTest extends AbstractKeycloakTest { public class MigrationTest extends AbstractKeycloakTest {
private final String migrationRealmName = "Migration"; private final String MIGRATION = "Migration";
@Override @Override
public void addTestRealms(List<RealmRepresentation> testRealms) { public void addTestRealms(List<RealmRepresentation> testRealms) {
@ -40,31 +57,116 @@ public class MigrationTest extends AbstractKeycloakTest {
@Before @Before
public void beforeMigrationTest() { public void beforeMigrationTest() {
//add migration realm to testRealmReps to make the migration removed after test
testRealmReps.add(adminClient.realms().realm(MIGRATION).toRepresentation());
} }
@Test @Test
@Migration(versionFrom = "1.9.8.Final") @Migration(versionFrom = "1.9.8.Final")
public void migration198Test() { public void migration198Test() {
//test migrated data RealmResource migrationRealm = adminClient.realms().realm(MIGRATION);
test198(); RealmResource masterRealm = adminClient.realms().realm(MASTER);
//import realm from previous version and test imported data testMigratedMasterData(masterRealm);
MigrationUtil.executeImport(testingClient); testMigratedMigrationData(migrationRealm);
test198();
// 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() { @Test
RealmResource realmResource = adminClient.realms().realm(migrationRealmName); @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"); testMigratedMasterData(masterRealm);
Assert.assertNames(realmResource.clients().findAll(), "admin-cli", "realm-management", "security-admin-console", "broker", "account"); testMigratedMigrationData(migrationRealm);
//TODO - add more asserts // so far nothing else
}
//cleanup
RealmRepresentation realmRep = realmResource.toRepresentation(); private void testMigratedMasterData(RealmResource master) {
log.info("removing '" + realmRep.getRealm() + "' realm"); assertNames(master.roles().list(), "offline_access", "uma_authorization", "create-realm", "master-test-realm-role", "admin");
removeRealm(realmRep); 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.socket.binding.port-offset=${auth.server.port.offset}
-Djboss.bind.address=0.0.0.0 -Djboss.bind.address=0.0.0.0
${adapter.test.props} ${adapter.test.props}
${migration.import.properties}
</property> </property>
<property name="javaVmArguments"> <property name="javaVmArguments">
${auth.server.memory.settings} ${auth.server.memory.settings}
@ -158,12 +159,8 @@
<property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property> <property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
<property name="jbossHome">${keycloak.migration.home}</property> <property name="jbossHome">${keycloak.migration.home}</property>
<property name="javaVmArguments"> <property name="javaVmArguments">
-Dkeycloak.migration.action=import -Djboss.socket.binding.port-offset=${auth.server.port.offset}
-Dkeycloak.migration.provider=singleFile ${migration.import.props.previous}
-Dkeycloak.migration.file=${keycloak.migration.file}
-Dkeycloak.migration.strategy=OVERWRITE_EXISTING
-Dkeycloak.migration.realmName=Migration
-Djboss.socket.binding.port-offset=${auth.server.port.offset}
${auth.server.memory.settings} ${auth.server.memory.settings}
</property> </property>
<property name="managementPort">${auth.server.management.port}</property> <property name="managementPort">${auth.server.management.port}</property>

View file

@ -65,6 +65,7 @@
<auth.server.remote>false</auth.server.remote> <auth.server.remote>false</auth.server.remote>
<adapter.test.props/> <adapter.test.props/>
<migration.import.properties/>
<examples.home>${project.build.directory}/examples</examples.home> <examples.home>${project.build.directory}/examples</examples.home>
<browser>phantomjs</browser> <browser>phantomjs</browser>
@ -168,6 +169,7 @@
<auth.server.remote>${auth.server.remote}</auth.server.remote> <auth.server.remote>${auth.server.remote}</auth.server.remote>
<adapter.test.props>${adapter.test.props}</adapter.test.props> <adapter.test.props>${adapter.test.props}</adapter.test.props>
<migration.import.properties>${migration.import.properties}</migration.import.properties>
<testsuite.constants>${testsuite.constants}</testsuite.constants> <testsuite.constants>${testsuite.constants}</testsuite.constants>
@ -406,14 +408,41 @@
<!-- Profile for migration tests--> <!-- Profile for migration tests-->
<profile> <profile>
<id>migration</id> <id>migration-auto</id>
<activation> <activation>
<property> <property>
<name>migrated.auth.server.version</name> <name>migration.mode</name>
<value>auto</value>
</property> </property>
</activation> </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> <build>
<plugins> <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> <plugin>
<artifactId>maven-dependency-plugin</artifactId> <artifactId>maven-dependency-plugin</artifactId>
<executions> <executions>
@ -445,13 +474,62 @@
<migrated.auth.server.version>${migrated.auth.server.version}</migrated.auth.server.version> <migrated.auth.server.version>${migrated.auth.server.version}</migrated.auth.server.version>
<auth.server.jboss.migration>true</auth.server.jboss.migration> <auth.server.jboss.migration>true</auth.server.jboss.migration>
<keycloak.migration.home>${containers.home}/keycloak-${migrated.auth.server.version}</keycloak.migration.home> <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> </systemPropertyVariables>
</configuration> </configuration>
</plugin> </plugin>
</plugins> </plugins>
</build> </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> <profile>
<id>no-account</id> <id>no-account</id>