keycloak-aplcache

Changes

Details

diff --git a/server-spi/src/main/java/org/keycloak/models/PasswordPolicy.java b/server-spi/src/main/java/org/keycloak/models/PasswordPolicy.java
index f3367af..10d59d9 100755
--- a/server-spi/src/main/java/org/keycloak/models/PasswordPolicy.java
+++ b/server-spi/src/main/java/org/keycloak/models/PasswordPolicy.java
@@ -22,6 +22,7 @@ import org.keycloak.policy.PasswordPolicyProvider;
 
 import java.io.Serializable;
 import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Set;
 
@@ -32,62 +33,33 @@ public class PasswordPolicy implements Serializable {
 
     public static final String HASH_ALGORITHM_ID = "hashAlgorithm";
 
-    public static final String HASH_ALGORITHM_DEFAULT = "pbkdf2";
+    public static final String HASH_ALGORITHM_DEFAULT = "pbkdf2-sha256";
 
     public static final String HASH_ITERATIONS_ID = "hashIterations";
 
-    public static final int HASH_ITERATIONS_DEFAULT = 20000;
+    public static final int HASH_ITERATIONS_DEFAULT = 27500;
 
     public static final String PASSWORD_HISTORY_ID = "passwordHistory";
 
     public static final String FORCE_EXPIRED_ID = "forceExpiredPasswordChange";
 
-    private String policyString;
     private Map<String, Object> policyConfig;
+    private Builder builder;
 
     public static PasswordPolicy empty() {
         return new PasswordPolicy(null, new HashMap<>());
     }
 
-    public static PasswordPolicy parse(KeycloakSession session, String policyString) {
-        Map<String, Object> policyConfig = new HashMap<>();
-
-        if (policyString != null && !policyString.trim().isEmpty()) {
-            for (String policy : policyString.split(" and ")) {
-                policy = policy.trim();
-
-                String key;
-                String config = null;
-
-                int i = policy.indexOf('(');
-                if (i == -1) {
-                    key = policy.trim();
-                } else {
-                    key = policy.substring(0, i).trim();
-                    config = policy.substring(i + 1, policy.length() - 1);
-                }
-
-                PasswordPolicyProvider provider = session.getProvider(PasswordPolicyProvider.class, key);
-                if (provider == null) {
-                    throw new PasswordPolicyConfigException("Password policy not found");
-                }
-
-                Object o;
-                try {
-                    o = provider.parseConfig(config);
-                } catch (PasswordPolicyConfigException e) {
-                    throw new ModelException("Invalid config for " + key + ": " + e.getMessage());
-                }
-
-                policyConfig.put(key, o);
-            }
-        }
+    public static Builder build() {
+        return new Builder();
+    }
 
-        return new PasswordPolicy(policyString, policyConfig);
+    public static PasswordPolicy parse(KeycloakSession session, String policyString) {
+        return new Builder(policyString).build(session);
     }
 
-    private PasswordPolicy(String policyString, Map<String, Object> policyConfig) {
-        this.policyString = policyString;
+    private PasswordPolicy(Builder builder, Map<String, Object> policyConfig) {
+        this.builder = builder;
         this.policyConfig = policyConfig;
     }
 
@@ -111,7 +83,7 @@ public class PasswordPolicy implements Serializable {
         if (policyConfig.containsKey(HASH_ITERATIONS_ID)) {
             return getPolicyConfig(HASH_ITERATIONS_ID);
         } else {
-            return HASH_ITERATIONS_DEFAULT;
+            return -1;
         }
     }
 
@@ -133,7 +105,117 @@ public class PasswordPolicy implements Serializable {
 
     @Override
     public String toString() {
-        return policyString;
+        return builder.asString();
+    }
+
+    public Builder toBuilder() {
+        return builder.clone();
+    }
+
+    public static class Builder {
+
+        private LinkedHashMap<String, String> map;
+
+        private Builder() {
+            this.map = new LinkedHashMap<>();
+        }
+
+        private Builder(LinkedHashMap<String, String> map) {
+            this.map = map;
+        }
+
+        private Builder(String policyString) {
+            map = new LinkedHashMap<>();
+
+            if (policyString != null && !policyString.trim().isEmpty()) {
+                for (String policy : policyString.split(" and ")) {
+                    policy = policy.trim();
+
+                    String key;
+                    String config = null;
+
+                    int i = policy.indexOf('(');
+                    if (i == -1) {
+                        key = policy.trim();
+                    } else {
+                        key = policy.substring(0, i).trim();
+                        config = policy.substring(i + 1, policy.length() - 1);
+                    }
+
+                    map.put(key, config);
+                }
+            }
+        }
+
+        public boolean contains(String key) {
+            return map.containsKey(key);
+        }
+
+        public String get(String key) {
+            return map.get(key);
+        }
+
+        public Builder put(String key, String value) {
+            map.put(key, value);
+            return this;
+        }
+
+        public Builder remove(String key) {
+            map.remove(key);
+            return this;
+        }
+
+        public PasswordPolicy build(KeycloakSession session) {
+            Map<String, Object> config = new HashMap<>();
+            for (Map.Entry<String, String> e : map.entrySet()) {
+
+                PasswordPolicyProvider provider = session.getProvider(PasswordPolicyProvider.class, e.getKey());
+                if (provider == null) {
+                    throw new PasswordPolicyConfigException("Password policy not found");
+                }
+
+                Object o;
+                try {
+                    o = provider.parseConfig(e.getValue());
+                } catch (PasswordPolicyConfigException ex) {
+                    throw new ModelException("Invalid config for " + e.getKey() + ": " + ex.getMessage());
+                }
+
+                config.put(e.getKey(), o);
+            }
+            return new PasswordPolicy(this, config);
+        }
+
+        public String asString() {
+            if (map.isEmpty()) {
+                return null;
+            }
+
+            StringBuilder sb = new StringBuilder();
+            boolean first = true;
+            for (Map.Entry<String, String> e : map.entrySet()) {
+                if (first) {
+                    first = false;
+                } else {
+                    sb.append(" and ");
+                }
+
+                sb.append(e.getKey());
+
+                String c = e.getValue();
+                if (c != null && !c.trim().isEmpty()) {
+                    sb.append("(");
+                    sb.append(c);
+                    sb.append(")");
+                }
+            }
+            return sb.toString();
+        }
+
+        public Builder clone() {
+            return new Builder((LinkedHashMap<String, String>) map.clone());
+        }
+
     }
 
 }
diff --git a/server-spi-private/src/main/java/org/keycloak/credential/hash/Pbkdf2PasswordHashProvider.java b/server-spi-private/src/main/java/org/keycloak/credential/hash/Pbkdf2PasswordHashProvider.java
index 6c170e1..6a6c1ff 100644
--- a/server-spi-private/src/main/java/org/keycloak/credential/hash/Pbkdf2PasswordHashProvider.java
+++ b/server-spi-private/src/main/java/org/keycloak/credential/hash/Pbkdf2PasswordHashProvider.java
@@ -37,12 +37,14 @@ public class Pbkdf2PasswordHashProvider implements PasswordHashProvider {
     private final String providerId;
 
     private final String pbkdf2Algorithm;
+    private int defaultIterations;
 
     public static final int DERIVED_KEY_SIZE = 512;
 
-    public Pbkdf2PasswordHashProvider(String providerId, String pbkdf2Algorithm) {
+    public Pbkdf2PasswordHashProvider(String providerId, String pbkdf2Algorithm, int defaultIterations) {
         this.providerId = providerId;
         this.pbkdf2Algorithm = pbkdf2Algorithm;
+        this.defaultIterations = defaultIterations;
     }
 
     @Override
@@ -52,6 +54,10 @@ public class Pbkdf2PasswordHashProvider implements PasswordHashProvider {
 
     @Override
     public void encode(String rawPassword, int iterations, CredentialModel credential) {
+        if (iterations == -1) {
+            iterations = defaultIterations;
+        }
+
         byte[] salt = getSalt();
         String encodedPassword = encode(rawPassword, iterations, salt);
 
diff --git a/server-spi-private/src/main/java/org/keycloak/credential/hash/Pbkdf2PasswordHashProviderFactory.java b/server-spi-private/src/main/java/org/keycloak/credential/hash/Pbkdf2PasswordHashProviderFactory.java
index ecd917d..44e0e12 100644
--- a/server-spi-private/src/main/java/org/keycloak/credential/hash/Pbkdf2PasswordHashProviderFactory.java
+++ b/server-spi-private/src/main/java/org/keycloak/credential/hash/Pbkdf2PasswordHashProviderFactory.java
@@ -30,9 +30,11 @@ public class Pbkdf2PasswordHashProviderFactory implements PasswordHashProviderFa
 
     public static final String PBKDF2_ALGORITHM = "PBKDF2WithHmacSHA1";
 
+    public static final int DEFAULT_ITERATIONS = 20000;
+
     @Override
     public PasswordHashProvider create(KeycloakSession session) {
-        return new Pbkdf2PasswordHashProvider(ID, PBKDF2_ALGORITHM);
+        return new Pbkdf2PasswordHashProvider(ID, PBKDF2_ALGORITHM, 20000);
     }
 
     @Override
diff --git a/server-spi-private/src/main/java/org/keycloak/credential/hash/Pbkdf2Sha256PasswordHashProviderFactory.java b/server-spi-private/src/main/java/org/keycloak/credential/hash/Pbkdf2Sha256PasswordHashProviderFactory.java
index c6453d1..040879f 100644
--- a/server-spi-private/src/main/java/org/keycloak/credential/hash/Pbkdf2Sha256PasswordHashProviderFactory.java
+++ b/server-spi-private/src/main/java/org/keycloak/credential/hash/Pbkdf2Sha256PasswordHashProviderFactory.java
@@ -15,9 +15,11 @@ public class Pbkdf2Sha256PasswordHashProviderFactory implements PasswordHashProv
 
     public static final String PBKDF2_ALGORITHM = "PBKDF2WithHmacSHA256";
 
+    public static final int DEFAULT_ITERATIONS = 27500;
+
     @Override
     public PasswordHashProvider create(KeycloakSession session) {
-        return new Pbkdf2PasswordHashProvider(ID, PBKDF2_ALGORITHM);
+        return new Pbkdf2PasswordHashProvider(ID, PBKDF2_ALGORITHM, DEFAULT_ITERATIONS);
     }
 
     @Override
diff --git a/server-spi-private/src/main/java/org/keycloak/credential/hash/Pbkdf2Sha512PasswordHashProviderFactory.java b/server-spi-private/src/main/java/org/keycloak/credential/hash/Pbkdf2Sha512PasswordHashProviderFactory.java
index 5f838a1..2e0700d 100644
--- a/server-spi-private/src/main/java/org/keycloak/credential/hash/Pbkdf2Sha512PasswordHashProviderFactory.java
+++ b/server-spi-private/src/main/java/org/keycloak/credential/hash/Pbkdf2Sha512PasswordHashProviderFactory.java
@@ -15,9 +15,11 @@ public class Pbkdf2Sha512PasswordHashProviderFactory implements PasswordHashProv
 
     public static final String PBKDF2_ALGORITHM = "PBKDF2WithHmacSHA512";
 
+    public static final int DEFAULT_ITERATIONS = 30000;
+
     @Override
     public PasswordHashProvider create(KeycloakSession session) {
-        return new Pbkdf2PasswordHashProvider(ID, PBKDF2_ALGORITHM);
+        return new Pbkdf2PasswordHashProvider(ID, PBKDF2_ALGORITHM, DEFAULT_ITERATIONS);
     }
 
     @Override
diff --git a/server-spi-private/src/main/java/org/keycloak/migration/MigrationModelManager.java b/server-spi-private/src/main/java/org/keycloak/migration/MigrationModelManager.java
index 1a36d7a..4b620bc 100755
--- a/server-spi-private/src/main/java/org/keycloak/migration/MigrationModelManager.java
+++ b/server-spi-private/src/main/java/org/keycloak/migration/MigrationModelManager.java
@@ -34,6 +34,7 @@ import org.keycloak.migration.migrators.MigrateTo2_3_0;
 import org.keycloak.migration.migrators.MigrateTo2_5_0;
 import org.keycloak.migration.migrators.MigrateTo3_0_0;
 import org.keycloak.migration.migrators.MigrateTo3_1_0;
+import org.keycloak.migration.migrators.MigrateTo3_2_0;
 import org.keycloak.migration.migrators.Migration;
 import org.keycloak.models.KeycloakSession;
 
@@ -60,7 +61,8 @@ public class MigrationModelManager {
             new MigrateTo2_3_0(),
             new MigrateTo2_5_0(),
             new MigrateTo3_0_0(),
-            new MigrateTo3_1_0()
+            new MigrateTo3_1_0(),
+            new MigrateTo3_2_0()
     };
 
     public static void migrate(KeycloakSession session) {
diff --git a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo3_2_0.java b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo3_2_0.java
new file mode 100644
index 0000000..85f2296
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo3_2_0.java
@@ -0,0 +1,45 @@
+/*
+ * 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.migration.migrators;
+
+
+import org.keycloak.migration.ModelVersion;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.PasswordPolicy;
+import org.keycloak.models.RealmModel;
+
+public class MigrateTo3_2_0 implements Migration {
+
+    public static final ModelVersion VERSION = new ModelVersion("3.1.0");
+
+    @Override
+    public void migrate(KeycloakSession session) {
+        for (RealmModel realm : session.realms().getRealms()) {
+            PasswordPolicy.Builder builder = realm.getPasswordPolicy().toBuilder();
+            if (!builder.contains(PasswordPolicy.HASH_ALGORITHM_ID) && "20000".equals(builder.get(PasswordPolicy.HASH_ITERATIONS_ID))) {
+                realm.setPasswordPolicy(builder.remove(PasswordPolicy.HASH_ITERATIONS_ID).build(session));
+            }
+        }
+    }
+
+    @Override
+    public ModelVersion getVersion() {
+        return VERSION;
+    }
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/policy/HashIterationsPasswordPolicyProviderFactory.java b/server-spi-private/src/main/java/org/keycloak/policy/HashIterationsPasswordPolicyProviderFactory.java
index 695ab28..be4dd45 100644
--- a/server-spi-private/src/main/java/org/keycloak/policy/HashIterationsPasswordPolicyProviderFactory.java
+++ b/server-spi-private/src/main/java/org/keycloak/policy/HashIterationsPasswordPolicyProviderFactory.java
@@ -60,7 +60,7 @@ public class HashIterationsPasswordPolicyProviderFactory implements PasswordPoli
 
     @Override
     public Object parseConfig(String value) {
-        return value != null ? Integer.parseInt(value) : PasswordPolicy.HASH_ITERATIONS_DEFAULT;
+        return parseInteger(value, -1);
     }
 
     @Override
diff --git a/services/src/main/java/org/keycloak/services/managers/RealmManager.java b/services/src/main/java/org/keycloak/services/managers/RealmManager.java
index e94ff3c..a83d80d 100755
--- a/services/src/main/java/org/keycloak/services/managers/RealmManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/RealmManager.java
@@ -226,8 +226,6 @@ public class RealmManager {
         realm.setLoginWithEmailAllowed(true);
 
         realm.setEventsListeners(Collections.singleton("jboss-logging"));
-
-        realm.setPasswordPolicy(PasswordPolicy.parse(session, "hashIterations(20000)"));
     }
 
     public boolean removeRealm(RealmModel realm) {
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/adduser/AddUserTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/adduser/AddUserTest.java
index fb23bcd..8dff789 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/adduser/AddUserTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/adduser/AddUserTest.java
@@ -26,7 +26,7 @@ import org.junit.rules.TemporaryFolder;
 import org.keycloak.admin.client.Keycloak;
 import org.keycloak.admin.client.resource.RealmResource;
 import org.keycloak.admin.client.resource.UserResource;
-import org.keycloak.credential.hash.Pbkdf2PasswordHashProviderFactory;
+import org.keycloak.credential.hash.Pbkdf2Sha256PasswordHashProviderFactory;
 import org.keycloak.models.Constants;
 import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.representations.idm.CredentialRepresentation;
@@ -85,7 +85,7 @@ public class AddUserTest {
 
         CredentialRepresentation credentials = user.getCredentials().get(0);
 
-        assertEquals(Pbkdf2PasswordHashProviderFactory.ID, credentials.getAlgorithm());
+        assertEquals(Pbkdf2Sha256PasswordHashProviderFactory.ID, credentials.getAlgorithm());
         assertEquals(new Integer(100000), credentials.getHashIterations());
 
         KeycloakServer server = new KeycloakServer();
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/LogChecker.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/LogChecker.java
index e968c7d..dd5d6d8 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/LogChecker.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/LogChecker.java
@@ -31,7 +31,7 @@ public class LogChecker {
 
     private static final Logger log = Logger.getLogger(LogChecker.class);
 
-    private static final String[] IGNORED = new String[] { ".*Jetty ALPN support not found.*" };
+    private static final String[] IGNORED = new String[] { ".*Jetty ALPN support not found.*", ".*org.keycloak.events.*" };
 
     public static void checkServerLog(File logFile) throws IOException {
         log.info(String.format("Checking server log: '%s'", logFile.getAbsolutePath()));
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/realm/RealmTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/realm/RealmTest.java
index ba0b7c9..7f811c6 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/realm/RealmTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/realm/RealmTest.java
@@ -173,7 +173,7 @@ public class RealmTest extends AbstractAdminTest {
 
         adminClient.realms().create(rep);
 
-        assertEquals("hashIterations(20000)", adminClient.realm("new-realm").toRepresentation().getPasswordPolicy());
+        assertEquals(null, adminClient.realm("new-realm").toRepresentation().getPasswordPolicy());
 
         adminClient.realms().realm("new-realm").remove();
 
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/PasswordHashingTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/PasswordHashingTest.java
index 0784f01..6763e7d 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/PasswordHashingTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/PasswordHashingTest.java
@@ -103,34 +103,38 @@ public class PasswordHashingTest extends AbstractTestRealmKeycloakTest {
 
     @Test
     public void testPasswordRehashedOnAlgorithmChanged() throws Exception {
+        setPasswordPolicy("hashAlgorithm(" + Pbkdf2Sha256PasswordHashProviderFactory.ID + ") and hashIterations(1)");
+
         String username = "testPasswordRehashedOnAlgorithmChanged";
         createUser(username);
 
         CredentialModel credential = fetchCredentials(username);
 
-        assertEquals(Pbkdf2PasswordHashProviderFactory.ID, credential.getAlgorithm());
+        assertEquals(Pbkdf2Sha256PasswordHashProviderFactory.ID, credential.getAlgorithm());
 
-        assertEncoded(credential, "password", credential.getSalt(), "PBKDF2WithHmacSHA1", 20000);
+        assertEncoded(credential, "password", credential.getSalt(), "PBKDF2WithHmacSHA256", 1);
 
-        setPasswordPolicy("hashAlgorithm(" + Pbkdf2Sha256PasswordHashProviderFactory.ID + ")");
+        setPasswordPolicy("hashAlgorithm(" + Pbkdf2PasswordHashProviderFactory.ID + ") and hashIterations(1)");
 
         loginPage.open();
         loginPage.login(username, "password");
 
         credential = fetchCredentials(username);
 
-        assertEquals(Pbkdf2Sha256PasswordHashProviderFactory.ID, credential.getAlgorithm());
-        assertEncoded(credential, "password", credential.getSalt(), "PBKDF2WithHmacSHA256", 20000);
+        assertEquals(Pbkdf2PasswordHashProviderFactory.ID, credential.getAlgorithm());
+        assertEncoded(credential, "password", credential.getSalt(), "PBKDF2WithHmacSHA1", 1);
     }
 
     @Test
     public void testPasswordRehashedOnIterationsChanged() throws Exception {
+        setPasswordPolicy("hashIterations(10000)");
+
         String username = "testPasswordRehashedOnIterationsChanged";
         createUser(username);
 
         CredentialModel credential = fetchCredentials(username);
 
-        assertEquals(20000, credential.getHashIterations());
+        assertEquals(10000, credential.getHashIterations());
 
         setPasswordPolicy("hashIterations(1)");
 
@@ -140,7 +144,7 @@ public class PasswordHashingTest extends AbstractTestRealmKeycloakTest {
         credential = fetchCredentials(username);
 
         assertEquals(1, credential.getHashIterations());
-        assertEncoded(credential, "password", credential.getSalt(), "PBKDF2WithHmacSHA1", 1);
+        assertEncoded(credential, "password", credential.getSalt(), "PBKDF2WithHmacSHA256", 1);
     }
 
     @Test
@@ -154,13 +158,23 @@ public class PasswordHashingTest extends AbstractTestRealmKeycloakTest {
     }
 
     @Test
+    public void testDefault() throws Exception {
+        setPasswordPolicy("");
+        String username = "testDefault";
+        createUser(username);
+
+        CredentialModel credential = fetchCredentials(username);
+        assertEncoded(credential, "password", credential.getSalt(), "PBKDF2WithHmacSHA256", 27500);
+    }
+
+    @Test
     public void testPbkdf2Sha256() throws Exception {
         setPasswordPolicy("hashAlgorithm(" + Pbkdf2Sha256PasswordHashProviderFactory.ID + ")");
         String username = "testPbkdf2Sha256";
         createUser(username);
 
         CredentialModel credential = fetchCredentials(username);
-        assertEncoded(credential, "password", credential.getSalt(), "PBKDF2WithHmacSHA256", 20000);
+        assertEncoded(credential, "password", credential.getSalt(), "PBKDF2WithHmacSHA256", 27500);
     }
 
     @Test
@@ -170,7 +184,7 @@ public class PasswordHashingTest extends AbstractTestRealmKeycloakTest {
         createUser(username);
 
         CredentialModel credential = fetchCredentials(username);
-        assertEncoded(credential, "password", credential.getSalt(), "PBKDF2WithHmacSHA512", 20000);
+        assertEncoded(credential, "password", credential.getSalt(), "PBKDF2WithHmacSHA512", 30000);
     }
 
 
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/MigrationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/MigrationTest.java
index 04a758e..a769687 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/MigrationTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/MigrationTest.java
@@ -59,6 +59,7 @@ import org.keycloak.testsuite.runonserver.RunHelpers;
 import org.keycloak.testsuite.runonserver.RunOnServerDeployment;
 import org.keycloak.testsuite.util.OAuthClient;
 
+import static org.junit.Assert.assertNull;
 import static org.keycloak.models.AccountRoles.MANAGE_ACCOUNT;
 import static org.keycloak.models.AccountRoles.MANAGE_ACCOUNT_LINKS;
 import static org.keycloak.models.Constants.ACCOUNT_MANAGEMENT_CLIENT_ID;
@@ -132,6 +133,7 @@ public class MigrationTest extends AbstractKeycloakTest {
         testMigrationTo2_5_0();
         testMigrationTo2_5_1();
         testMigrationTo3_0_0();
+        testMigrationTo3_2_0();
     }
     
     @Test
@@ -210,7 +212,12 @@ public class MigrationTest extends AbstractKeycloakTest {
     private void testMigrationTo3_0_0() {
         testRoleManageAccountLinks(masterRealm, migrationRealm);
     }
-    
+
+    private void testMigrationTo3_2_0() {
+        assertNull(masterRealm.toRepresentation().getPasswordPolicy());
+        assertNull(migrationRealm.toRepresentation().getPasswordPolicy());
+    }
+
     private void testRoleManageAccountLinks(RealmResource... realms) {
         log.info("testing role manage account links");
         for (RealmResource realm : realms) {