keycloak-uncached

Details

diff --git a/model/api/src/main/java/org/keycloak/hash/PasswordHashManager.java b/model/api/src/main/java/org/keycloak/hash/PasswordHashManager.java
index 5988a41..60effdb 100644
--- a/model/api/src/main/java/org/keycloak/hash/PasswordHashManager.java
+++ b/model/api/src/main/java/org/keycloak/hash/PasswordHashManager.java
@@ -8,7 +8,10 @@ import org.keycloak.models.*;
 public class PasswordHashManager {
 
     public static UserCredentialValueModel encode(KeycloakSession session, RealmModel realm, String rawPassword) {
-        PasswordPolicy passwordPolicy = realm.getPasswordPolicy();
+        return encode(session, realm.getPasswordPolicy(), rawPassword);
+    }
+
+    public static UserCredentialValueModel encode(KeycloakSession session, PasswordPolicy passwordPolicy, String rawPassword) {
         String algorithm = passwordPolicy.getHashAlgorithm();
         int iterations = passwordPolicy.getHashIterations();
         if (iterations < 1) {
@@ -22,7 +25,11 @@ public class PasswordHashManager {
     }
 
     public static boolean verify(KeycloakSession session, RealmModel realm, String password, UserCredentialValueModel credential) {
-        String algorithm = credential.getAlgorithm() != null ? credential.getAlgorithm() : realm.getPasswordPolicy().getHashAlgorithm();
+        return verify(session, realm.getPasswordPolicy(), password, credential);
+    }
+
+    public static boolean verify(KeycloakSession session, PasswordPolicy passwordPolicy, String password, UserCredentialValueModel credential) {
+        String algorithm = credential.getAlgorithm() != null ? credential.getAlgorithm() : passwordPolicy.getHashAlgorithm();
         PasswordHashProvider provider = session.getProvider(PasswordHashProvider.class, algorithm);
         return provider.verify(password, credential);
     }
diff --git a/model/api/src/main/java/org/keycloak/models/PasswordPolicy.java b/model/api/src/main/java/org/keycloak/models/PasswordPolicy.java
index b7ed682..211b8a2 100755
--- a/model/api/src/main/java/org/keycloak/models/PasswordPolicy.java
+++ b/model/api/src/main/java/org/keycloak/models/PasswordPolicy.java
@@ -30,60 +30,52 @@ public class PasswordPolicy implements Serializable {
     private String policyString;
 
     public PasswordPolicy(String policyString) {
-        if (policyString == null || policyString.length() == 0) {
-            this.policyString = null;
-            policies = Collections.emptyList();
-        } else {
-            this.policyString = policyString;
-            policies = parse(policyString);
-        }
-    }
-
-    private static List<Policy> parse(String policyString) {
-        List<Policy> list = new LinkedList<Policy>();
-        String[] policies = policyString.split(" and ");
-        for (String policy : policies) {
-            policy = policy.trim();
-
-            String name;
-            String arg = null;
-
-            int i = policy.indexOf('(');
-            if (i == -1) {
-                name = policy.trim();
-            } else {
-                name = policy.substring(0, i).trim();
-                arg = policy.substring(i + 1, policy.length() - 1);
-            }
+        this.policyString = policyString;
+        this.policies = new LinkedList<>();
+
+        if (policyString != null && !policyString.isEmpty()) {
+            for (String policy : policyString.split(" and ")) {
+                policy = policy.trim();
+
+                String name;
+                String arg = null;
+
+                int i = policy.indexOf('(');
+                if (i == -1) {
+                    name = policy.trim();
+                } else {
+                    name = policy.substring(0, i).trim();
+                    arg = policy.substring(i + 1, policy.length() - 1);
+                }
 
-            if (name.equals(Length.NAME)) {
-                list.add(new Length(arg));
-            } else if (name.equals(Digits.NAME)) {
-                list.add(new Digits(arg));
-            } else if (name.equals(LowerCase.NAME)) {
-                list.add(new LowerCase(arg));
-            } else if (name.equals(UpperCase.NAME)) {
-                list.add(new UpperCase(arg));
-            } else if (name.equals(SpecialChars.NAME)) {
-                list.add(new SpecialChars(arg));
-            } else if (name.equals(NotUsername.NAME)) {
-                list.add(new NotUsername(arg));
-            } else if (name.equals(HashAlgorithm.NAME)) {
-                list.add(new HashAlgorithm(arg));
-            } else if (name.equals(HashIterations.NAME)) {
-                list.add(new HashIterations(arg));
-            } else if (name.equals(RegexPatterns.NAME)) {
-                Pattern.compile(arg);
-                list.add(new RegexPatterns(arg));
-            } else if (name.equals(PasswordHistory.NAME)) {
-                list.add(new PasswordHistory(arg));
-            } else if (name.equals(ForceExpiredPasswordChange.NAME)) {
-                list.add(new ForceExpiredPasswordChange(arg));
-            } else {
-                throw new IllegalArgumentException("Unsupported policy");
+                if (name.equals(Length.NAME)) {
+                    policies.add(new Length(arg));
+                } else if (name.equals(Digits.NAME)) {
+                    policies.add(new Digits(arg));
+                } else if (name.equals(LowerCase.NAME)) {
+                    policies.add(new LowerCase(arg));
+                } else if (name.equals(UpperCase.NAME)) {
+                    policies.add(new UpperCase(arg));
+                } else if (name.equals(SpecialChars.NAME)) {
+                    policies.add(new SpecialChars(arg));
+                } else if (name.equals(NotUsername.NAME)) {
+                    policies.add(new NotUsername(arg));
+                } else if (name.equals(HashAlgorithm.NAME)) {
+                    policies.add(new HashAlgorithm(arg));
+                } else if (name.equals(HashIterations.NAME)) {
+                    policies.add(new HashIterations(arg));
+                } else if (name.equals(RegexPatterns.NAME)) {
+                    Pattern.compile(arg);
+                    policies.add(new RegexPatterns(arg));
+                } else if (name.equals(PasswordHistory.NAME)) {
+                    policies.add(new PasswordHistory(arg, this));
+                } else if (name.equals(ForceExpiredPasswordChange.NAME)) {
+                    policies.add(new ForceExpiredPasswordChange(arg));
+                } else {
+                    throw new IllegalArgumentException("Unsupported policy");
+                }
             }
         }
-        return list;
     }
 
     public String getHashAlgorithm() {
@@ -396,10 +388,12 @@ public class PasswordPolicy implements Serializable {
 
     private static class PasswordHistory implements Policy {
         private static final String NAME = "passwordHistory";
+        private final PasswordPolicy passwordPolicy;
         private int passwordHistoryPolicyValue;
 
-        public PasswordHistory(String arg)
+        public PasswordHistory(String arg, PasswordPolicy passwordPolicy)
         {
+            this.passwordPolicy = passwordPolicy;
             passwordHistoryPolicyValue = intArg(NAME, 3, arg);
         }
         
@@ -410,13 +404,10 @@ public class PasswordPolicy implements Serializable {
 
         @Override
         public Error validate(KeycloakSession session, UserModel user, String password) {
-            
             if (passwordHistoryPolicyValue != -1) {
-            
                 UserCredentialValueModel cred = getCredentialValueModel(user, UserCredentialModel.PASSWORD);
                 if (cred != null) {
-                    PasswordHashProvider hashProvider = session.getProvider(PasswordHashProvider.class, cred.getAlgorithm());
-                    if(hashProvider.verify(password, cred)) {
+                    if(PasswordHashManager.verify(session, passwordPolicy, password, cred)) {
                         return new Error(INVALID_PASSWORD_HISTORY, passwordHistoryPolicyValue);
                     }
                 }
@@ -424,8 +415,7 @@ public class PasswordPolicy implements Serializable {
                 List<UserCredentialValueModel> passwordExpiredCredentials = getCredentialValueModels(user, passwordHistoryPolicyValue - 1,
                         UserCredentialModel.PASSWORD_HISTORY);
                 for (UserCredentialValueModel credential : passwordExpiredCredentials) {
-                    PasswordHashProvider hashProvider = session.getProvider(PasswordHashProvider.class, cred.getAlgorithm());
-                    if (hashProvider.verify(password, credential)) {
+                    if (PasswordHashManager.verify(session, passwordPolicy, password, credential)) {
                         return new Error(INVALID_PASSWORD_HISTORY, passwordHistoryPolicyValue);
                     }
                 }