keycloak-uncached

Merge pull request #3489 from stianst/KEYCLOAK-3882 KEYCLOAK-3882

11/11/2016 6:35:08 AM

Changes

pom.xml 10(+8 -2)

server-spi/src/main/java/org/keycloak/models/dblock/DBLockManager.java 68(+0 -68)

server-spi/src/main/java/org/keycloak/models/dblock/DBLockProvider.java 60(+0 -60)

server-spi/src/main/java/org/keycloak/models/dblock/DBLockProviderFactory.java 31(+0 -31)

server-spi/src/main/java/org/keycloak/models/session/DisabledUserSessionPersisterProvider.java 126(+0 -126)

server-spi/src/main/java/org/keycloak/models/session/PersistentClientSessionModel.java 79(+0 -79)

server-spi/src/main/java/org/keycloak/models/session/PersistentUserSessionModel.java 54(+0 -54)

server-spi/src/main/java/org/keycloak/models/session/UserSessionPersisterProviderFactory.java 26(+0 -26)

server-spi/src/main/java/org/keycloak/models/session/UserSessionPersisterSpi.java 48(+0 -48)

server-spi/src/main/java/org/keycloak/models/utils/ComponentUtil.java 93(+0 -93)

server-spi/src/main/java/org/keycloak/models/utils/CredentialValidation.java 44(+0 -44)

server-spi/src/main/java/org/keycloak/models/utils/DefaultKeyProviders.java 62(+0 -62)

server-spi/src/main/java/org/keycloak/models/utils/DefaultRequiredActions.java 83(+0 -83)

server-spi/src/main/java/org/keycloak/models/utils/FormMessage.java 87(+0 -87)

server-spi/src/main/java/org/keycloak/models/utils/PostMigrationEvent.java 28(+0 -28)

server-spi/src/main/java/org/keycloak/models/utils/RealmImporter.java 31(+0 -31)

server-spi/src/main/java/org/keycloak/models/utils/RealmInfoUtil.java 38(+0 -38)

server-spi/src/main/java/org/keycloak/models/utils/reflection/AnnotatedPropertyCriteria.java 40(+0 -40)

server-spi/src/main/java/org/keycloak/models/utils/reflection/MethodProperty.java 25(+0 -25)

server-spi/src/main/java/org/keycloak/models/utils/reflection/NamedPropertyCriteria.java 57(+0 -57)

server-spi/src/main/java/org/keycloak/models/utils/reflection/Properties.java 59(+0 -59)

server-spi/src/main/java/org/keycloak/models/utils/reflection/Property.java 122(+0 -122)

server-spi/src/main/java/org/keycloak/models/utils/reflection/PropertyCriteria.java 43(+0 -43)

server-spi/src/main/java/org/keycloak/models/utils/reflection/PropertyQueries.java 42(+0 -42)

server-spi/src/main/java/org/keycloak/models/utils/reflection/PropertyQuery.java 179(+0 -179)

server-spi/src/main/java/org/keycloak/models/utils/reflection/TypedPropertyCriteria.java 88(+0 -88)

server-spi/src/main/java/org/keycloak/models/utils/SHAPasswordEncoder.java 77(+0 -77)

server-spi/src/main/java/org/keycloak/models/utils/StripSecretsUtils.java 73(+0 -73)

server-spi/src/main/java/org/keycloak/models/utils/TimeBasedOTP.java 123(+0 -123)

server-spi/src/main/java/org/keycloak/models/utils/UserModelDelegate.java 245(+0 -245)

server-spi/src/main/java/org/keycloak/policy/DefaultPasswordPolicyManagerProvider.java 80(+0 -80)

server-spi/src/main/java/org/keycloak/policy/DefaultPasswordPolicyManagerProviderFactory.java 51(+0 -51)

server-spi/src/main/java/org/keycloak/policy/DigitsPasswordPolicyProvider.java 63(+0 -63)

server-spi/src/main/java/org/keycloak/policy/DigitsPasswordPolicyProviderFactory.java 73(+0 -73)

server-spi/src/main/java/org/keycloak/policy/ForceExpiredPasswordPolicyProviderFactory.java 91(+0 -91)

server-spi/src/main/java/org/keycloak/policy/HashAlgorithmPasswordPolicyProviderFactory.java 92(+0 -92)

server-spi/src/main/java/org/keycloak/policy/HashIterationsPasswordPolicyProviderFactory.java 92(+0 -92)

server-spi/src/main/java/org/keycloak/policy/HistoryPasswordPolicyProvider.java 83(+0 -83)

server-spi/src/main/java/org/keycloak/policy/HistoryPasswordPolicyProviderFactory.java 74(+0 -74)

server-spi/src/main/java/org/keycloak/policy/LengthPasswordPolicyProvider.java 57(+0 -57)

server-spi/src/main/java/org/keycloak/policy/LengthPasswordPolicyProviderFactory.java 73(+0 -73)

server-spi/src/main/java/org/keycloak/policy/LowerCasePasswordPolicyProvider.java 63(+0 -63)

server-spi/src/main/java/org/keycloak/policy/LowerCasePasswordPolicyProviderFactory.java 73(+0 -73)

server-spi/src/main/java/org/keycloak/policy/NotUsernamePasswordPolicyProvider.java 59(+0 -59)

server-spi/src/main/java/org/keycloak/policy/NotUsernamePasswordPolicyProviderFactory.java 73(+0 -73)

server-spi/src/main/java/org/keycloak/policy/PasswordPolicyManagerProvider.java 32(+0 -32)

server-spi/src/main/java/org/keycloak/policy/PasswordPolicyManagerProviderFactory.java 27(+0 -27)

server-spi/src/main/java/org/keycloak/policy/PasswordPolicyManagerSpi.java 49(+0 -49)

server-spi/src/main/java/org/keycloak/policy/PasswordPolicyProviderFactory.java 32(+0 -32)

server-spi/src/main/java/org/keycloak/policy/PasswordPolicySpi.java 48(+0 -48)

server-spi/src/main/java/org/keycloak/policy/RegexPatternsPasswordPolicyProvider.java 67(+0 -67)

server-spi/src/main/java/org/keycloak/policy/RegexPatternsPasswordPolicyProviderFactory.java 73(+0 -73)

server-spi/src/main/java/org/keycloak/policy/SpecialCharsPasswordPolicyProvider.java 63(+0 -63)

server-spi/src/main/java/org/keycloak/policy/SpecialCharsPasswordPolicyProviderFactory.java 73(+0 -73)

server-spi/src/main/java/org/keycloak/policy/UpperCasePasswordPolicyProvider.java 63(+0 -63)

server-spi/src/main/java/org/keycloak/policy/UpperCasePasswordPolicyProviderFactory.java 73(+0 -73)

server-spi/src/main/java/org/keycloak/protocol/AbstractLoginProtocolFactory.java 56(+0 -56)

server-spi/src/main/java/org/keycloak/protocol/ClientInstallationProvider.java 44(+0 -44)

server-spi/src/main/java/org/keycloak/protocol/ClientInstallationSpi.java 49(+0 -49)

server-spi/src/main/java/org/keycloak/protocol/LoginProtocol.java 84(+0 -84)

server-spi/src/main/java/org/keycloak/protocol/LoginProtocolFactory.java 66(+0 -66)

server-spi/src/main/java/org/keycloak/protocol/LoginProtocolSpi.java 49(+0 -49)

server-spi/src/main/java/org/keycloak/protocol/oidc/TokenIntrospectionProvider.java 38(+0 -38)

server-spi/src/main/java/org/keycloak/protocol/oidc/TokenIntrospectionProviderFactory.java 28(+0 -28)

server-spi/src/main/java/org/keycloak/protocol/oidc/TokenIntrospectionSpi.java 49(+0 -49)

server-spi/src/main/java/org/keycloak/protocol/ProtocolMapper.java 49(+0 -49)

server-spi/src/main/java/org/keycloak/protocol/ProtocolMapperConfigException.java 69(+0 -69)

server-spi/src/main/java/org/keycloak/protocol/ProtocolMapperSpi.java 49(+0 -49)

server-spi/src/main/java/org/keycloak/provider/ConfigurationValidationHelper.java 121(+0 -121)

server-spi/src/main/java/org/keycloak/provider/EnvironmentDependentProviderFactory.java 33(+0 -33)

server-spi/src/main/java/org/keycloak/provider/ProviderLoader.java 42(+0 -42)

server-spi/src/main/java/org/keycloak/provider/ProviderLoaderFactory.java 29(+0 -29)

server-spi/src/main/java/org/keycloak/provider/ServerInfoAwareProviderFactory.java 37(+0 -37)

server-spi/src/main/java/org/keycloak/scripting/InvocableScriptAdapter.java 118(+0 -118)

server-spi/src/main/java/org/keycloak/scripting/Script.java 115(+0 -115)

server-spi/src/main/java/org/keycloak/scripting/ScriptBindingsConfigurer.java 41(+0 -41)

server-spi/src/main/java/org/keycloak/scripting/ScriptExecutionException.java 33(+0 -33)

server-spi/src/main/java/org/keycloak/scripting/ScriptingProvider.java 51(+0 -51)

server-spi/src/main/java/org/keycloak/scripting/ScriptingSpi.java 31(+0 -31)

server-spi/src/main/java/org/keycloak/services/managers/BruteForceProtector.java 34(+0 -34)

server-spi/src/main/java/org/keycloak/services/managers/BruteForceProtectorFactory.java 27(+0 -27)

server-spi/src/main/java/org/keycloak/services/managers/BruteForceProtectorSpi.java 49(+0 -49)

server-spi/src/main/java/org/keycloak/services/managers/ClientSessionCode.java 279(+0 -279)

server-spi/src/main/java/org/keycloak/services/managers/UserManager.java 59(+0 -59)

server-spi/src/main/java/org/keycloak/services/resource/RealmResourceProvider.java 38(+0 -38)

server-spi/src/main/java/org/keycloak/services/resource/RealmResourceProviderFactory.java 30(+0 -30)

server-spi/src/main/java/org/keycloak/services/resource/RealmResourceSPI.java 54(+0 -54)

server-spi/src/main/java/org/keycloak/theme/Theme.java 72(+0 -72)

server-spi/src/main/java/org/keycloak/theme/ThemeProvider.java 38(+0 -38)

server-spi/src/main/java/org/keycloak/theme/ThemeProviderFactory.java 26(+0 -26)

server-spi/src/main/java/org/keycloak/theme/ThemeSpi.java 48(+0 -48)

server-spi/src/main/java/org/keycloak/timer/ScheduledTask.java 29(+0 -29)

server-spi/src/main/java/org/keycloak/timer/TimerProvider.java 33(+0 -33)

server-spi/src/main/java/org/keycloak/timer/TimerProviderFactory.java 26(+0 -26)

server-spi/src/main/java/org/keycloak/timer/TimerSpi.java 48(+0 -48)

server-spi/src/main/java/org/keycloak/transaction/JtaTransactionManagerLookup.java 43(+0 -43)

server-spi/src/main/java/org/keycloak/transaction/TransactionManagerLookupSpi.java 49(+0 -49)

server-spi/src/main/java/org/keycloak/truststore/HostnameVerificationPolicy.java 36(+0 -36)

server-spi/src/main/java/org/keycloak/truststore/TruststoreProvider.java 32(+0 -32)

server-spi/src/main/java/org/keycloak/truststore/TruststoreProviderFactory.java 26(+0 -26)

server-spi/src/main/java/org/keycloak/truststore/TruststoreSpi.java 48(+0 -48)

server-spi/src/main/resources/META-INF/services/org.keycloak.models.session.UserSessionPersisterProviderFactory 18(+0 -18)

server-spi/src/main/resources/META-INF/services/org.keycloak.policy.PasswordPolicyManagerProviderFactory 18(+0 -18)

server-spi/src/main/resources/META-INF/services/org.keycloak.policy.PasswordPolicyProviderFactory 28(+0 -28)

server-spi/src/test/java/org/keycloak/models/HmacTest.java 40(+0 -40)

services/pom.xml 5(+5 -0)

Details

diff --git a/authz/policy/common/pom.xml b/authz/policy/common/pom.xml
index 6149e3a..31df304 100644
--- a/authz/policy/common/pom.xml
+++ b/authz/policy/common/pom.xml
@@ -46,6 +46,11 @@
             <artifactId>keycloak-server-spi</artifactId>
             <scope>provided</scope>
         </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-server-spi-private</artifactId>
+            <scope>provided</scope>
+        </dependency>
     </dependencies>
 
 </project>
\ No newline at end of file
diff --git a/authz/policy/drools/pom.xml b/authz/policy/drools/pom.xml
index 7dc1b45..1594329 100644
--- a/authz/policy/drools/pom.xml
+++ b/authz/policy/drools/pom.xml
@@ -25,6 +25,11 @@
         </dependency>
         <dependency>
             <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-server-spi-private</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
             <artifactId>keycloak-services</artifactId>
             <scope>provided</scope>
         </dependency>
diff --git a/dependencies/server-min/pom.xml b/dependencies/server-min/pom.xml
index 6beae84..1c17f64 100755
--- a/dependencies/server-min/pom.xml
+++ b/dependencies/server-min/pom.xml
@@ -60,6 +60,10 @@
             <groupId>org.keycloak</groupId>
             <artifactId>keycloak-server-spi</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-server-spi-private</artifactId>
+        </dependency>
          <dependency>
             <groupId>org.keycloak</groupId>
             <artifactId>keycloak-js-adapter</artifactId>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/drools/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/drools/main/module.xml
index 09d9479..4c5af2f 100755
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/drools/main/module.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/drools/main/module.xml
@@ -31,6 +31,7 @@
         <module name="org.keycloak.keycloak-core"/>
         <module name="org.keycloak.keycloak-common"/>
         <module name="org.keycloak.keycloak-server-spi"/>
+        <module name="org.keycloak.keycloak-server-spi-private"/>
         <module name="com.thoughtworks.xstream"/>
         <module name="org.antlr" slot="3.5"/>
         <module name="org.kie"/>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/eclipse/jdt/core/compiler/ecj/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/eclipse/jdt/core/compiler/ecj/main/module.xml
index 8440c1d..849fc35 100644
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/eclipse/jdt/core/compiler/ecj/main/module.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/eclipse/jdt/core/compiler/ecj/main/module.xml
@@ -31,6 +31,7 @@
         <module name="org.keycloak.keycloak-core"/>
         <module name="org.keycloak.keycloak-common"/>
         <module name="org.keycloak.keycloak-server-spi"/>
+        <module name="org.keycloak.keycloak-server-spi-private"/>
     </dependencies>
 
 </module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-authz-policy-common/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-authz-policy-common/main/module.xml
index 422c683..a8ab099 100644
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-authz-policy-common/main/module.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-authz-policy-common/main/module.xml
@@ -29,6 +29,7 @@
         <module name="org.keycloak.keycloak-core"/>
         <module name="org.keycloak.keycloak-common"/>
         <module name="org.keycloak.keycloak-server-spi"/>
+        <module name="org.keycloak.keycloak-server-spi-private"/>
         <module name="org.keycloak.keycloak-services"/>
     </dependencies>
 
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-authz-policy-drools/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-authz-policy-drools/main/module.xml
index cf36e0a..60dc78a 100644
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-authz-policy-drools/main/module.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-authz-policy-drools/main/module.xml
@@ -28,6 +28,7 @@
         <module name="org.keycloak.keycloak-core"/>
         <module name="org.keycloak.keycloak-common"/>
         <module name="org.keycloak.keycloak-server-spi"/>
+        <module name="org.keycloak.keycloak-server-spi-private"/>
         <module name="org.keycloak.keycloak-services"/>
         <module name="org.kie"/>
     </dependencies>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-common/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-common/main/module.xml
index 4a3d370..7b024b1 100755
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-common/main/module.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-common/main/module.xml
@@ -16,10 +16,6 @@
   ~ limitations under the License.
   -->
 <module xmlns="urn:jboss:module:1.3" name="org.keycloak.keycloak-common">
-    <properties>
-        <property name="jboss.api" value="private"/>
-    </properties>
-
     <resources>
         <artifact name="${org.keycloak:keycloak-common}"/>
     </resources>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-core/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-core/main/module.xml
index 1afc30d..659a055 100755
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-core/main/module.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-core/main/module.xml
@@ -16,10 +16,6 @@
   ~ limitations under the License.
   -->
 <module xmlns="urn:jboss:module:1.3" name="org.keycloak.keycloak-core">
-    <properties>
-        <property name="jboss.api" value="private"/>
-    </properties>
-
     <resources>
         <artifact name="${org.keycloak:keycloak-core}"/>
     </resources>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-kerberos-federation/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-kerberos-federation/main/module.xml
index d0b9730..ebb263c 100755
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-kerberos-federation/main/module.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-kerberos-federation/main/module.xml
@@ -28,6 +28,7 @@
         <module name="org.keycloak.keycloak-common"/>
         <module name="org.keycloak.keycloak-core"/>
         <module name="org.keycloak.keycloak-server-spi"/>
+        <module name="org.keycloak.keycloak-server-spi-private"/>
         <module name="javax.ws.rs.api"/>
         <module name="org.jboss.resteasy.resteasy-jaxrs"/>
         <module name="org.jboss.logging"/>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-ldap-federation/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-ldap-federation/main/module.xml
index 43a1d64..dcca1bf 100755
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-ldap-federation/main/module.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-ldap-federation/main/module.xml
@@ -28,6 +28,7 @@
         <module name="org.keycloak.keycloak-common"/>
         <module name="org.keycloak.keycloak-core"/>
         <module name="org.keycloak.keycloak-server-spi"/>
+        <module name="org.keycloak.keycloak-server-spi-private"/>
         <module name="org.keycloak.keycloak-kerberos-federation"/>
         <module name="javax.ws.rs.api"/>
         <module name="org.jboss.resteasy.resteasy-jaxrs"/>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-model-infinispan/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-model-infinispan/main/module.xml
index 91f423a..a80a008 100755
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-model-infinispan/main/module.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-model-infinispan/main/module.xml
@@ -28,6 +28,7 @@
         <module name="org.keycloak.keycloak-common"/>
         <module name="org.keycloak.keycloak-core"/>
         <module name="org.keycloak.keycloak-server-spi"/>
+        <module name="org.keycloak.keycloak-server-spi-private"/>
         <module name="org.infinispan"/>
         <module name="org.jboss.logging"/>
         <module name="javax.api"/>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-model-jpa/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-model-jpa/main/module.xml
index 94c80a2..88cae4f 100755
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-model-jpa/main/module.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-model-jpa/main/module.xml
@@ -29,6 +29,7 @@
         <module name="org.keycloak.keycloak-common"/>
         <module name="org.keycloak.keycloak-core"/>
         <module name="org.keycloak.keycloak-server-spi"/>
+        <module name="org.keycloak.keycloak-server-spi-private"/>
         <module name="javax.persistence.api"/>
         <module name="org.jboss.logging"/>
         <module name="org.liquibase"/>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-model-mongo/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-model-mongo/main/module.xml
index 20cff7c..3bd99ae 100755
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-model-mongo/main/module.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-model-mongo/main/module.xml
@@ -29,6 +29,7 @@
         <module name="org.keycloak.keycloak-core"/>
         <module name="org.keycloak.keycloak-services"/>
         <module name="org.keycloak.keycloak-server-spi"/>
+        <module name="org.keycloak.keycloak-server-spi-private"/>
         <module name="org.mongodb.mongo-java-driver"/>
         <module name="org.jboss.logging"/>
         <module name="javax.api"/>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-server-spi/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-server-spi/main/module.xml
index 8b5632e..daed0af 100755
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-server-spi/main/module.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-server-spi/main/module.xml
@@ -16,10 +16,6 @@
   ~ limitations under the License.
   -->
 <module xmlns="urn:jboss:module:1.3" name="org.keycloak.keycloak-server-spi">
-    <properties>
-        <property name="jboss.api" value="private"/>
-    </properties>
-
     <resources>
         <artifact name="${org.keycloak:keycloak-server-spi}"/>
     </resources>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-server-spi-private/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-server-spi-private/main/module.xml
new file mode 100755
index 0000000..0f136fd
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-server-spi-private/main/module.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  ~ 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.
+  -->
+<module xmlns="urn:jboss:module:1.3" name="org.keycloak.keycloak-server-spi-private">
+    <properties>
+        <property name="jboss.api" value="private"/>
+    </properties>
+
+    <resources>
+        <artifact name="${org.keycloak:keycloak-server-spi-private}"/>
+    </resources>
+
+    <dependencies>
+        <module name="org.jboss.logging"/>
+        <module name="org.keycloak.keycloak-common"/>
+        <module name="org.keycloak.keycloak-core"/>
+        <module name="org.keycloak.keycloak-server-spi"/>
+        <module name="org.bouncycastle" />
+        <module name="javax.api"/>
+        <module name="javax.ws.rs.api"/>
+        <module name="org.apache.httpcomponents"/>
+        <module name="org.jboss.resteasy.resteasy-jaxrs"/>
+        <module name="javax.transaction.api"/>
+    </dependencies>
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-services/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-services/main/module.xml
index 4f351fd..9db480c 100755
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-services/main/module.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-services/main/module.xml
@@ -32,6 +32,7 @@
         <module name="org.keycloak.keycloak-ldap-federation" services="import"/>
         <module name="org.keycloak.keycloak-sssd-federation" services="import"/>
         <module name="org.keycloak.keycloak-server-spi" services="import"/>
+        <module name="org.keycloak.keycloak-server-spi-private" services="import"/>
         <module name="org.keycloak.keycloak-model-jpa" services="import"/>
         <module name="org.keycloak.keycloak-model-mongo" services="import"/>
         <module name="org.keycloak.keycloak-model-infinispan" services="import"/>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-sssd-federation/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-sssd-federation/main/module.xml
index ad16f3c..58939eb 100644
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-sssd-federation/main/module.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-sssd-federation/main/module.xml
@@ -28,5 +28,6 @@
         <module name="org.jboss.logging"/>
         <module name="org.keycloak.keycloak-core" />
         <module name="org.keycloak.keycloak-server-spi" />
+        <module name="org.keycloak.keycloak-server-spi-private"/>
     </dependencies>
 </module>
\ No newline at end of file
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-wildfly-adduser/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-wildfly-adduser/main/module.xml
index 4ee5c50..178470b 100755
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-wildfly-adduser/main/module.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-wildfly-adduser/main/module.xml
@@ -30,6 +30,7 @@
         <module name="org.keycloak.keycloak-common"/>
         <module name="org.keycloak.keycloak-core"/>
         <module name="org.keycloak.keycloak-server-spi"/>
+        <module name="org.keycloak.keycloak-server-spi-private"/>
         <module name="org.jboss.aesh"/>
         <module name="org.jboss.as.domain-management"/>
         <module name="com.fasterxml.jackson.core.jackson-core"/>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-wildfly-extensions/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-wildfly-extensions/main/module.xml
index d785cb7..89aa901 100755
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-wildfly-extensions/main/module.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-wildfly-extensions/main/module.xml
@@ -28,6 +28,7 @@
         <module name="org.keycloak.keycloak-common"/>
         <module name="org.keycloak.keycloak-core"/>
         <module name="org.keycloak.keycloak-server-spi"/>
+        <module name="org.keycloak.keycloak-server-spi-private"/>
         <module name="org.keycloak.keycloak-services"/>
         <module name="org.jboss.modules"/>
     </dependencies>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/kie/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/kie/main/module.xml
index 242b508..9b41daa 100644
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/kie/main/module.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/kie/main/module.xml
@@ -32,11 +32,13 @@
         <module name="org.keycloak.keycloak-core"/>
         <module name="org.keycloak.keycloak-common"/>
         <module name="org.keycloak.keycloak-server-spi"/>
+        <module name="org.keycloak.keycloak-server-spi-private"/>
         <module name="org.slf4j"/>
         <module name="org.apache.commons.logging"/>
         <module name="org.keycloak.keycloak-core"/>
         <module name="org.keycloak.keycloak-common"/>
         <module name="org.keycloak.keycloak-server-spi"/>
+        <module name="org.keycloak.keycloak-server-spi-private"/>
         <module name="com.sun.xml.bind"/>
         <module name="com.thoughtworks.xstream"/>
         <module name="org.apache.ant"/>
diff --git a/examples/providers/authenticator/pom.xml b/examples/providers/authenticator/pom.xml
index 4e24bf3..0992966 100755
--- a/examples/providers/authenticator/pom.xml
+++ b/examples/providers/authenticator/pom.xml
@@ -42,6 +42,11 @@
             <scope>provided</scope>
         </dependency>
         <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-server-spi-private</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
             <groupId>org.jboss.logging</groupId>
             <artifactId>jboss-logging</artifactId>
             <scope>provided</scope>
diff --git a/examples/providers/domain-extension/pom.xml b/examples/providers/domain-extension/pom.xml
index 43e5cf7..d31ccbf 100755
--- a/examples/providers/domain-extension/pom.xml
+++ b/examples/providers/domain-extension/pom.xml
@@ -48,6 +48,11 @@
         </dependency>
         <dependency>
             <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-server-spi-private</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
             <artifactId>keycloak-model-jpa</artifactId>
             <scope>provided</scope>
         </dependency>
diff --git a/examples/providers/domain-extension/README.md b/examples/providers/domain-extension/README.md
index 9ec5e63..465551b 100644
--- a/examples/providers/domain-extension/README.md
+++ b/examples/providers/domain-extension/README.md
@@ -3,7 +3,7 @@ Example Domain Extension
 
 To run, deploy as a module by running:
 
-    $KEYCLOAK_HOME/bin/jboss-cli.sh --command="module add --name=org.keycloak.examples.domain-extension-example --resources=target/domain-extension-example.jar --dependencies=org.keycloak.keycloak-core,org.keycloak.keycloak-services,org.keycloak.keycloak-model-jpa,org.keycloak.keycloak-server-spi,javax.ws.rs.api,javax.persistence.api,org.hibernate,org.javassist,org.liquibase"
+    $KEYCLOAK_HOME/bin/jboss-cli.sh --command="module add --name=org.keycloak.examples.domain-extension-example --resources=target/domain-extension-example.jar --dependencies=org.keycloak.keycloak-core,org.keycloak.keycloak-services,org.keycloak.keycloak-model-jpa,org.keycloak.keycloak-server-spi,org.keycloak.keycloak-server-spi-private,javax.ws.rs.api,javax.persistence.api,org.hibernate,org.javassist,org.liquibase"
 
 
 Then registering the provider by editing `standalone/configuration/standalone.xml` and adding the module to the providers element:
diff --git a/examples/providers/event-listener-sysout/pom.xml b/examples/providers/event-listener-sysout/pom.xml
index 83f348b..3d61dfd 100755
--- a/examples/providers/event-listener-sysout/pom.xml
+++ b/examples/providers/event-listener-sysout/pom.xml
@@ -40,6 +40,11 @@
             <artifactId>keycloak-server-spi</artifactId>
             <scope>provided</scope>
         </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-server-spi-private</artifactId>
+            <scope>provided</scope>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/examples/providers/event-listener-sysout/README.md b/examples/providers/event-listener-sysout/README.md
index 8e1a085..5540d9b 100644
--- a/examples/providers/event-listener-sysout/README.md
+++ b/examples/providers/event-listener-sysout/README.md
@@ -3,7 +3,7 @@ Example Event Listener that prints events to System.out
 
 To deploy copy target/event-listener-sysout-example.jar to providers directory. Alternatively you can deploy as a module by running:
 
-    KEYCLOAK_HOME/bin/jboss-cli.sh --command="module add --name=org.keycloak.examples.event-sysout --resources=target/event-listener-sysout-example.jar --dependencies=org.keycloak.keycloak-core,org.keycloak.keycloak-server-spi"
+    KEYCLOAK_HOME/bin/jboss-cli.sh --command="module add --name=org.keycloak.examples.event-sysout --resources=target/event-listener-sysout-example.jar --dependencies=org.keycloak.keycloak-core,org.keycloak.keycloak-server-spi,org.keycloak.keycloak-server-spi-private"
 
 Then registering the provider by editing `standalone/configuration/standalone.xml` and adding the module to the providers element:
 
diff --git a/examples/providers/event-store-mem/pom.xml b/examples/providers/event-store-mem/pom.xml
index 16db181..2e48c2d 100755
--- a/examples/providers/event-store-mem/pom.xml
+++ b/examples/providers/event-store-mem/pom.xml
@@ -40,6 +40,11 @@
             <artifactId>keycloak-server-spi</artifactId>
             <scope>provided</scope>
         </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-server-spi-private</artifactId>
+            <scope>provided</scope>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/examples/providers/event-store-mem/README.md b/examples/providers/event-store-mem/README.md
index 682ff42..2c55109 100644
--- a/examples/providers/event-store-mem/README.md
+++ b/examples/providers/event-store-mem/README.md
@@ -3,7 +3,7 @@ Example Event Store that stores events in memory
 
 To deploy copy target/event-store-mem-example.jar to providers directory. Alternatively you can deploy as a module by running:
 
-    KEYCLOAK_HOME/bin/jboss-cli.sh --command="module add --name=org.keycloak.examples.event-inmem --resources=target/event-store-mem-example.jar --dependencies=org.keycloak.keycloak-core,org.keycloak.keycloak-server-spi"
+    KEYCLOAK_HOME/bin/jboss-cli.sh --command="module add --name=org.keycloak.examples.event-inmem --resources=target/event-store-mem-example.jar --dependencies=org.keycloak.keycloak-core,org.keycloak.keycloak-server-spi,org.keycloak.keycloak-server-spi-private"
 
 Then registering the provider by editing `standalone/configuration/standalone.xml` and adding the module to the providers element:
 
diff --git a/examples/providers/federation-provider/pom.xml b/examples/providers/federation-provider/pom.xml
index bd4e1c8..be02cc7 100755
--- a/examples/providers/federation-provider/pom.xml
+++ b/examples/providers/federation-provider/pom.xml
@@ -42,6 +42,11 @@
             <scope>provided</scope>
         </dependency>
         <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-server-spi-private</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
             <groupId>org.jboss.logging</groupId>
             <artifactId>jboss-logging</artifactId>
             <scope>provided</scope>
diff --git a/examples/providers/federation-provider/README.md b/examples/providers/federation-provider/README.md
index c90e791..ae02fc8 100755
--- a/examples/providers/federation-provider/README.md
+++ b/examples/providers/federation-provider/README.md
@@ -4,7 +4,7 @@ Example User Federation Provider
 This is an example of user federation backed by a simple properties file.  This properties file only contains username/password
 key pairs.  To deploy, build this directory then take the jar and copy it to providers directory. Alternatively you can deploy as a module by running:
 
-    KEYCLOAK_HOME/bin/jboss-cli.sh --command="module add --name=org.keycloak.examples.userprops --resources=target/federation-properties-example.jar --dependencies=org.keycloak.keycloak-core,org.keycloak.keycloak-server-spi"
+    KEYCLOAK_HOME/bin/jboss-cli.sh --command="module add --name=org.keycloak.examples.userprops --resources=target/federation-properties-example.jar --dependencies=org.keycloak.keycloak-core,org.keycloak.keycloak-server-spi,org.keycloak.keycloak-server-spi-private"
 
 Then registering the provider by editing `standalone/configuration/standalone.xml` and adding the module to the providers element:
 
diff --git a/examples/providers/rest/pom.xml b/examples/providers/rest/pom.xml
index 416acfc..b94cf43 100755
--- a/examples/providers/rest/pom.xml
+++ b/examples/providers/rest/pom.xml
@@ -42,6 +42,11 @@
             <scope>provided</scope>
         </dependency>
         <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-server-spi-private</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
             <groupId>org.jboss.spec.javax.ws.rs</groupId>
             <artifactId>jboss-jaxrs-api_2.0_spec</artifactId>
         </dependency>
diff --git a/examples/providers/rest/README.md b/examples/providers/rest/README.md
index 5ee9327..d78e9bc 100644
--- a/examples/providers/rest/README.md
+++ b/examples/providers/rest/README.md
@@ -3,7 +3,7 @@ Example Realm REST Resource provider
 
 To deploy copy target/hello-rest-example.jar to providers directory. Alternatively you can deploy as a module by running:
 
-    $KEYCLOAK_HOME/bin/jboss-cli.sh --command="module add --name=org.keycloak.examples.hello-rest-example --resources=target/hello-rest-example.jar --dependencies=org.keycloak.keycloak-core,org.keycloak.keycloak-server-spi,javax.ws.rs.api"
+    $KEYCLOAK_HOME/bin/jboss-cli.sh --command="module add --name=org.keycloak.examples.hello-rest-example --resources=target/hello-rest-example.jar --dependencies=org.keycloak.keycloak-core,org.keycloak.keycloak-server-spi,org.keycloak.keycloak-server-spi-private,javax.ws.rs.api"
 
 Then registering the provider by editing `standalone/configuration/standalone.xml` and adding the module to the providers element:
 
diff --git a/examples/providers/user-storage-jpa/src/main/java/org/keycloak/examples/storage/user/EjbExampleUserStorageProvider.java b/examples/providers/user-storage-jpa/src/main/java/org/keycloak/examples/storage/user/EjbExampleUserStorageProvider.java
index 837f2b6..86b2a30 100644
--- a/examples/providers/user-storage-jpa/src/main/java/org/keycloak/examples/storage/user/EjbExampleUserStorageProvider.java
+++ b/examples/providers/user-storage-jpa/src/main/java/org/keycloak/examples/storage/user/EjbExampleUserStorageProvider.java
@@ -30,7 +30,6 @@ import org.keycloak.models.UserCredentialModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.cache.CachedUserModel;
 import org.keycloak.models.cache.OnUserCache;
-import org.keycloak.models.utils.KeycloakModelUtils;
 import org.keycloak.storage.StorageId;
 import org.keycloak.storage.UserStorageProvider;
 import org.keycloak.storage.user.UserLookupProvider;
@@ -49,6 +48,7 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.UUID;
 
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -139,7 +139,7 @@ public class EjbExampleUserStorageProvider implements UserStorageProvider,
     @Override
     public UserModel addUser(RealmModel realm, String username) {
         UserEntity entity = new UserEntity();
-        entity.setId(KeycloakModelUtils.generateId());
+        entity.setId(UUID.randomUUID().toString());
         entity.setUsername(username);
         em.persist(entity);
         logger.info("added user: " + username);
diff --git a/federation/kerberos/pom.xml b/federation/kerberos/pom.xml
index 75d3ab4..da453d6 100755
--- a/federation/kerberos/pom.xml
+++ b/federation/kerberos/pom.xml
@@ -41,6 +41,11 @@
             <scope>provided</scope>
         </dependency>
         <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-server-spi-private</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
             <groupId>org.jboss.logging</groupId>
             <artifactId>jboss-logging</artifactId>
             <scope>provided</scope>
diff --git a/federation/kerberos/src/main/java/org/keycloak/federation/kerberos/KerberosFederationProvider.java b/federation/kerberos/src/main/java/org/keycloak/federation/kerberos/KerberosFederationProvider.java
index d656a0d..b5f4709 100755
--- a/federation/kerberos/src/main/java/org/keycloak/federation/kerberos/KerberosFederationProvider.java
+++ b/federation/kerberos/src/main/java/org/keycloak/federation/kerberos/KerberosFederationProvider.java
@@ -33,7 +33,7 @@ import org.keycloak.models.UserCredentialModel;
 import org.keycloak.models.UserFederationProvider;
 import org.keycloak.models.UserFederationProviderModel;
 import org.keycloak.models.UserModel;
-import org.keycloak.services.managers.UserManager;
+import org.keycloak.models.UserManager;
 
 import java.util.Collections;
 import java.util.HashMap;
diff --git a/federation/ldap/pom.xml b/federation/ldap/pom.xml
index 4187ef6..38fa19d 100755
--- a/federation/ldap/pom.xml
+++ b/federation/ldap/pom.xml
@@ -42,6 +42,11 @@
         </dependency>
         <dependency>
             <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-server-spi-private</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
             <artifactId>keycloak-kerberos-federation</artifactId>
             <scope>provided</scope>
         </dependency>
diff --git a/federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPFederationProvider.java b/federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPFederationProvider.java
index 880f0f7..67cfb45 100755
--- a/federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPFederationProvider.java
+++ b/federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPFederationProvider.java
@@ -47,7 +47,7 @@ import org.keycloak.models.UserFederationMapperModel;
 import org.keycloak.models.UserFederationProvider;
 import org.keycloak.models.UserFederationProviderModel;
 import org.keycloak.models.UserModel;
-import org.keycloak.services.managers.UserManager;
+import org.keycloak.models.UserManager;
 
 import javax.naming.AuthenticationException;
 import java.util.ArrayList;
diff --git a/federation/ldap/src/main/java/org/keycloak/federation/ldap/mappers/membership/group/GroupLDAPFederationMapper.java b/federation/ldap/src/main/java/org/keycloak/federation/ldap/mappers/membership/group/GroupLDAPFederationMapper.java
index 460ab62..d135dfa 100644
--- a/federation/ldap/src/main/java/org/keycloak/federation/ldap/mappers/membership/group/GroupLDAPFederationMapper.java
+++ b/federation/ldap/src/main/java/org/keycloak/federation/ldap/mappers/membership/group/GroupLDAPFederationMapper.java
@@ -38,6 +38,7 @@ import org.keycloak.models.UserFederationMapperModel;
 import org.keycloak.models.UserFederationSyncResult;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.models.utils.RoleUtils;
 import org.keycloak.models.utils.UserModelDelegate;
 
 import java.util.Collection;
@@ -563,7 +564,7 @@ public class GroupLDAPFederationMapper extends AbstractLDAPFederationMapper impl
 
         @Override
         public boolean hasRole(RoleModel role) {
-            return super.hasRole(role) || KeycloakModelUtils.hasRoleFromGroup(getGroups(), role, true);
+            return super.hasRole(role) || RoleUtils.hasRoleFromGroup(getGroups(), role, true);
         }
 
         @Override
diff --git a/federation/ldap/src/main/java/org/keycloak/federation/ldap/mappers/membership/role/RoleLDAPFederationMapper.java b/federation/ldap/src/main/java/org/keycloak/federation/ldap/mappers/membership/role/RoleLDAPFederationMapper.java
index 9d6e2a1..b45f348 100644
--- a/federation/ldap/src/main/java/org/keycloak/federation/ldap/mappers/membership/role/RoleLDAPFederationMapper.java
+++ b/federation/ldap/src/main/java/org/keycloak/federation/ldap/mappers/membership/role/RoleLDAPFederationMapper.java
@@ -38,6 +38,7 @@ import org.keycloak.models.UserFederationMapperModel;
 import org.keycloak.models.UserFederationSyncResult;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.models.utils.RoleUtils;
 import org.keycloak.models.utils.UserModelDelegate;
 
 import java.util.Collection;
@@ -348,8 +349,8 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper imple
         @Override
         public boolean hasRole(RoleModel role) {
             Set<RoleModel> roles = getRoleMappings();
-            return KeycloakModelUtils.hasRole(roles, role)
-              || KeycloakModelUtils.hasRoleFromGroup(getGroups(), role, true);
+            return RoleUtils.hasRole(roles, role)
+              || RoleUtils.hasRoleFromGroup(getGroups(), role, true);
         }
 
         @Override
diff --git a/federation/sssd/pom.xml b/federation/sssd/pom.xml
index 8430e7c..29113f7 100644
--- a/federation/sssd/pom.xml
+++ b/federation/sssd/pom.xml
@@ -61,6 +61,11 @@
             <scope>provided</scope>
         </dependency>
         <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-server-spi-private</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
             <groupId>org.jboss.logging</groupId>
             <artifactId>jboss-logging</artifactId>
             <scope>provided</scope>
diff --git a/federation/sssd/src/main/java/org/keycloak/federation/sssd/SSSDFederationProvider.java b/federation/sssd/src/main/java/org/keycloak/federation/sssd/SSSDFederationProvider.java
index 2820947..44662de 100755
--- a/federation/sssd/src/main/java/org/keycloak/federation/sssd/SSSDFederationProvider.java
+++ b/federation/sssd/src/main/java/org/keycloak/federation/sssd/SSSDFederationProvider.java
@@ -34,7 +34,7 @@ import org.keycloak.models.UserFederationProvider;
 import org.keycloak.models.UserFederationProviderModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.utils.KeycloakModelUtils;
-import org.keycloak.services.managers.UserManager;
+import org.keycloak.models.UserManager;
 
 import java.util.Collections;
 import java.util.HashSet;
diff --git a/model/infinispan/pom.xml b/model/infinispan/pom.xml
index 08aef53..f10fa60 100755
--- a/model/infinispan/pom.xml
+++ b/model/infinispan/pom.xml
@@ -38,6 +38,10 @@
         <dependency>
             <groupId>org.keycloak</groupId>
             <artifactId>keycloak-server-spi</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-server-spi-private</artifactId>
             <scope>provided</scope>
         </dependency>
         <dependency>
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserAdapter.java
index 6030a66..1a52aa9 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserAdapter.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserAdapter.java
@@ -27,6 +27,7 @@ import org.keycloak.models.UserModel;
 import org.keycloak.models.cache.CachedUserModel;
 import org.keycloak.models.cache.infinispan.entities.CachedUser;
 import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.models.utils.RoleUtils;
 
 import java.util.Collections;
 import java.util.HashSet;
@@ -301,7 +302,7 @@ public class UserAdapter implements CachedUserModel {
         for (RoleModel mapping: mappings) {
            if (mapping.hasRole(role)) return true;
         }
-        return KeycloakModelUtils.hasRoleFromGroup(getGroups(), role, true);
+        return RoleUtils.hasRoleFromGroup(getGroups(), role, true);
     }
 
     @Override
@@ -368,7 +369,7 @@ public class UserAdapter implements CachedUserModel {
         if (updated != null) return updated.isMemberOf(group);
         if (cached.getGroups().contains(group.getId())) return true;
         Set<GroupModel> roles = getGroups();
-        return KeycloakModelUtils.isMember(roles, group);
+        return RoleUtils.isMember(roles, group);
     }
 
     @Override
diff --git a/model/jpa/pom.xml b/model/jpa/pom.xml
index 13f3ae0..0b2ae4d 100755
--- a/model/jpa/pom.xml
+++ b/model/jpa/pom.xml
@@ -50,6 +50,10 @@
         </dependency>
         <dependency>
             <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-server-spi-private</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
             <artifactId>keycloak-services</artifactId>
         </dependency>
         <dependency>
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/GroupAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/GroupAdapter.java
index 6ea87c5..3dc7bcc 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/GroupAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/GroupAdapter.java
@@ -27,6 +27,7 @@ import org.keycloak.models.jpa.entities.GroupAttributeEntity;
 import org.keycloak.models.jpa.entities.GroupEntity;
 import org.keycloak.models.jpa.entities.GroupRoleMappingEntity;
 import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.models.utils.RoleUtils;
 
 import javax.persistence.EntityManager;
 import javax.persistence.TypedQuery;
@@ -228,7 +229,7 @@ public class GroupAdapter implements GroupModel , JpaModel<GroupEntity> {
     @Override
     public boolean hasRole(RoleModel role) {
         Set<RoleModel> roles = getRoleMappings();
-        return KeycloakModelUtils.hasRole(roles, role);
+        return RoleUtils.hasRole(roles, role);
     }
 
     protected TypedQuery<GroupRoleMappingEntity> getGroupRoleMappingEntityTypedQuery(RoleModel role) {
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/UserAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/UserAdapter.java
index 5ee5490..a95548b 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/UserAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/UserAdapter.java
@@ -31,6 +31,7 @@ import org.keycloak.models.jpa.entities.UserGroupMembershipEntity;
 import org.keycloak.models.jpa.entities.UserRequiredActionEntity;
 import org.keycloak.models.jpa.entities.UserRoleMappingEntity;
 import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.models.utils.RoleUtils;
 
 import javax.persistence.EntityManager;
 import javax.persistence.Query;
@@ -338,7 +339,7 @@ public class UserAdapter implements UserModel, JpaModel<UserEntity> {
     @Override
     public boolean isMemberOf(GroupModel group) {
         Set<GroupModel> roles = getGroups();
-        return KeycloakModelUtils.isMember(roles, group);
+        return RoleUtils.isMember(roles, group);
     }
 
     protected TypedQuery<UserGroupMembershipEntity> getUserGroupMappingQuery(GroupModel group) {
@@ -352,8 +353,8 @@ public class UserAdapter implements UserModel, JpaModel<UserEntity> {
     @Override
     public boolean hasRole(RoleModel role) {
         Set<RoleModel> roles = getRoleMappings();
-        return KeycloakModelUtils.hasRole(roles, role)
-          || KeycloakModelUtils.hasRoleFromGroup(getGroups(), role, true);
+        return RoleUtils.hasRole(roles, role)
+          || RoleUtils.hasRoleFromGroup(getGroups(), role, true);
     }
 
     protected TypedQuery<UserRoleMappingEntity> getUserRoleMappingEntityTypedQuery(RoleModel role) {
diff --git a/model/mongo/pom.xml b/model/mongo/pom.xml
index d31fa69..054d320 100755
--- a/model/mongo/pom.xml
+++ b/model/mongo/pom.xml
@@ -50,6 +50,10 @@
         <dependency>
             <groupId>org.keycloak</groupId>
             <artifactId>keycloak-server-spi</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-server-spi-private</artifactId>
             <scope>provided</scope>
         </dependency>
         <dependency>
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/GroupAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/GroupAdapter.java
index 724dd69..d4ad3af 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/GroupAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/GroupAdapter.java
@@ -28,6 +28,7 @@ import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleModel;
 import org.keycloak.models.mongo.keycloak.entities.MongoGroupEntity;
 import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.models.utils.RoleUtils;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -146,7 +147,7 @@ public class GroupAdapter extends AbstractMongoAdapter<MongoGroupEntity> impleme
     @Override
     public boolean hasRole(RoleModel role) {
         Set<RoleModel> roles = getRoleMappings();
-        return KeycloakModelUtils.hasRole(roles, role);
+        return RoleUtils.hasRole(roles, role);
     }
 
     @Override
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/UserAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/UserAdapter.java
index 972f440..9d5ad7c 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/UserAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/UserAdapter.java
@@ -27,6 +27,7 @@ import org.keycloak.models.UserModel;
 import org.keycloak.models.mongo.keycloak.entities.MongoUserEntity;
 import org.keycloak.models.mongo.utils.MongoModelUtils;
 import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.models.utils.RoleUtils;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -262,14 +263,14 @@ public class UserAdapter extends AbstractMongoAdapter<MongoUserEntity> implement
     public boolean isMemberOf(GroupModel group) {
         if (user.getGroupIds().contains(group.getId())) return true;
         Set<GroupModel> groups = getGroups();
-        return KeycloakModelUtils.isMember(groups, group);
+        return RoleUtils.isMember(groups, group);
     }
 
     @Override
     public boolean hasRole(RoleModel role) {
         Set<RoleModel> roles = getRoleMappings();
-        return KeycloakModelUtils.hasRole(roles, role)
-          || KeycloakModelUtils.hasRoleFromGroup(getGroups(), role, true);
+        return RoleUtils.hasRole(roles, role)
+          || RoleUtils.hasRoleFromGroup(getGroups(), role, true);
     }
 
     @Override

pom.xml 10(+8 -2)

diff --git a/pom.xml b/pom.xml
index 8a61e5b..7918c6d 100755
--- a/pom.xml
+++ b/pom.xml
@@ -120,7 +120,7 @@
         <osgi.bundle.plugin.version>2.3.7</osgi.bundle.plugin.version>
         <wildfly.plugin.version>1.0.1.Final</wildfly.plugin.version>
         <nexus.staging.plugin.version>1.6.5</nexus.staging.plugin.version>
-        
+
         <!-- Surefire Settings -->
         <surefire.memory.settings>-Xms512m -Xmx2048m -XX:MetaspaceSize=96m -XX:MaxMetaspaceSize=256m</surefire.memory.settings>
     </properties>
@@ -175,6 +175,7 @@
         <module>core</module>
         <module>dependencies</module>
         <module>server-spi</module>
+        <module>server-spi-private</module>
         <module>saml-core-api</module>
         <module>saml-core</module>
         <module>proxy</module>
@@ -940,6 +941,11 @@
             </dependency>
             <dependency>
                 <groupId>org.keycloak</groupId>
+                <artifactId>keycloak-server-spi-private</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.keycloak</groupId>
                 <artifactId>keycloak-model-jpa</artifactId>
                 <version>${project.version}</version>
             </dependency>
@@ -1483,7 +1489,7 @@
                 </plugins>
             </build>
         </profile>
-        
+
         <profile>
             <id>nexus-staging</id>
             <build>
diff --git a/server-spi/src/main/java/org/keycloak/models/KeycloakContext.java b/server-spi/src/main/java/org/keycloak/models/KeycloakContext.java
index e644a80..be5f551 100755
--- a/server-spi/src/main/java/org/keycloak/models/KeycloakContext.java
+++ b/server-spi/src/main/java/org/keycloak/models/KeycloakContext.java
@@ -18,7 +18,6 @@
 package org.keycloak.models;
 
 import org.keycloak.common.ClientConnection;
-import org.keycloak.models.utils.RealmImporter;
 
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.UriInfo;
@@ -52,8 +51,6 @@ public interface KeycloakContext {
 
     void setConnection(ClientConnection connection);
 
-    RealmImporter getRealmManager();
-
     Locale resolveLocale(UserModel user);
 
 }
diff --git a/server-spi/src/main/java/org/keycloak/models/KeycloakSession.java b/server-spi/src/main/java/org/keycloak/models/KeycloakSession.java
index cb10891..f3242eb 100755
--- a/server-spi/src/main/java/org/keycloak/models/KeycloakSession.java
+++ b/server-spi/src/main/java/org/keycloak/models/KeycloakSession.java
@@ -20,7 +20,6 @@ package org.keycloak.models;
 import org.keycloak.component.ComponentModel;
 import org.keycloak.models.cache.UserCache;
 import org.keycloak.provider.Provider;
-import org.keycloak.scripting.ScriptingProvider;
 import org.keycloak.storage.federated.UserFederatedStorageProvider;
 
 import java.util.Set;
@@ -157,8 +156,4 @@ public interface KeycloakSession {
      */
     KeyManager keys();
 
-    /**
-     * Keycloak scripting support.
-     */
-    ScriptingProvider scripting();
 }
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 95dfc53..8833c8a 100755
--- a/server-spi/src/main/java/org/keycloak/models/PasswordPolicy.java
+++ b/server-spi/src/main/java/org/keycloak/models/PasswordPolicy.java
@@ -17,10 +17,6 @@
 
 package org.keycloak.models;
 
-import org.keycloak.policy.ForceExpiredPasswordPolicyProviderFactory;
-import org.keycloak.policy.HashAlgorithmPasswordPolicyProviderFactory;
-import org.keycloak.policy.HashIterationsPasswordPolicyProviderFactory;
-import org.keycloak.policy.HistoryPasswordPolicyProviderFactory;
 import org.keycloak.policy.PasswordPolicyProvider;
 
 import java.io.Serializable;
@@ -33,6 +29,18 @@ import java.util.Set;
  */
 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_ITERATIONS_ID = "hashIterations";
+
+    public static final int HASH_ITERATIONS_DEFAULT = 20000;
+
+    public static final String PASSWORD_HISTORY_ID = "passwordHistory";
+
+    public static final String FORCE_EXPIRED_ID = "forceExpiredPasswordChange";
+
     private String policyString;
     private Map<String, Object> policyConfig;
 
@@ -84,32 +92,32 @@ public class PasswordPolicy implements Serializable {
     }
 
     public String getHashAlgorithm() {
-        if (policyConfig.containsKey(HashAlgorithmPasswordPolicyProviderFactory.ID)) {
-            return getPolicyConfig(HashAlgorithmPasswordPolicyProviderFactory.ID);
+        if (policyConfig.containsKey(HASH_ALGORITHM_ID)) {
+            return getPolicyConfig(HASH_ALGORITHM_ID);
         } else {
-            return HashAlgorithmPasswordPolicyProviderFactory.DEFAULT_VALUE;
+            return HASH_ALGORITHM_DEFAULT;
         }
     }
 
     public int getHashIterations() {
-        if (policyConfig.containsKey(HashIterationsPasswordPolicyProviderFactory.ID)) {
-            return getPolicyConfig(HashIterationsPasswordPolicyProviderFactory.ID);
+        if (policyConfig.containsKey(HASH_ITERATIONS_ID)) {
+            return getPolicyConfig(HASH_ITERATIONS_ID);
         } else {
-            return HashIterationsPasswordPolicyProviderFactory.DEFAULT_VALUE;
+            return HASH_ITERATIONS_DEFAULT;
         }
     }
 
     public int getExpiredPasswords() {
-        if (policyConfig.containsKey(HistoryPasswordPolicyProviderFactory.ID)) {
-            return getPolicyConfig(HistoryPasswordPolicyProviderFactory.ID);
+        if (policyConfig.containsKey(PASSWORD_HISTORY_ID)) {
+            return getPolicyConfig(PASSWORD_HISTORY_ID);
         } else {
             return -1;
         }
     }
 
     public int getDaysToExpirePassword() {
-        if (policyConfig.containsKey(ForceExpiredPasswordPolicyProviderFactory.ID)) {
-            return getPolicyConfig(ForceExpiredPasswordPolicyProviderFactory.ID);
+        if (policyConfig.containsKey(FORCE_EXPIRED_ID)) {
+            return getPolicyConfig(FORCE_EXPIRED_ID);
         } else {
             return -1;
         }
diff --git a/server-spi/src/main/java/org/keycloak/models/UserFederationManager.java b/server-spi/src/main/java/org/keycloak/models/UserFederationManager.java
index 1765bad..707b96a 100755
--- a/server-spi/src/main/java/org/keycloak/models/UserFederationManager.java
+++ b/server-spi/src/main/java/org/keycloak/models/UserFederationManager.java
@@ -19,8 +19,6 @@ package org.keycloak.models;
 
 import org.jboss.logging.Logger;
 import org.keycloak.component.ComponentModel;
-import org.keycloak.models.utils.KeycloakModelUtils;
-import org.keycloak.services.managers.UserManager;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -74,7 +72,8 @@ public class UserFederationManager implements UserProvider {
     }
 
     public UserFederationProvider getFederationProvider(UserFederationProviderModel model) {
-        return KeycloakModelUtils.getFederationProviderInstance(session, model);
+        UserFederationProviderFactory factory = (UserFederationProviderFactory)session.getKeycloakSessionFactory().getProviderFactory(UserFederationProvider.class, model.getProviderName());
+        return factory.getInstance(session, model);
     }
 
     public UserFederationProvider getFederationLink(RealmModel realm, UserModel user) {
@@ -122,7 +121,7 @@ public class UserFederationManager implements UserProvider {
     }
 
     protected void deleteInvalidUser(final RealmModel realm, final UserModel user) {
-        KeycloakModelUtils.runJobInTransaction(session.getKeycloakSessionFactory(), new KeycloakSessionTask() {
+        runJobInTransaction(session.getKeycloakSessionFactory(), new KeycloakSessionTask() {
 
             @Override
             public void run(KeycloakSession session) {
@@ -136,6 +135,29 @@ public class UserFederationManager implements UserProvider {
         });
     }
 
+    private  static void runJobInTransaction(KeycloakSessionFactory factory, KeycloakSessionTask task) {
+        KeycloakSession session = factory.create();
+        KeycloakTransaction tx = session.getTransactionManager();
+        try {
+            tx.begin();
+            task.run(session);
+
+            if (tx.isActive()) {
+                if (tx.getRollbackOnly()) {
+                    tx.rollback();
+                } else {
+                    tx.commit();
+                }
+            }
+        } catch (RuntimeException re) {
+            if (tx.isActive()) {
+                tx.rollback();
+            }
+            throw re;
+        } finally {
+            session.close();
+        }
+    }
 
     protected UserModel validateAndProxyUser(RealmModel realm, UserModel user) {
         UserModel managed = managedUsers.get(user.getId());
diff --git a/server-spi/src/main/java/org/keycloak/models/UserManager.java b/server-spi/src/main/java/org/keycloak/models/UserManager.java
new file mode 100755
index 0000000..81b2b51
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/models/UserManager.java
@@ -0,0 +1,54 @@
+/*
+ * 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.models;
+
+import org.keycloak.models.session.UserSessionPersisterProvider;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class UserManager {
+
+    private KeycloakSession session;
+
+    public UserManager(KeycloakSession session) {
+        this.session = session;
+    }
+
+    public boolean removeUser(RealmModel realm, UserModel user) {
+        return removeUser(realm, user, session.users());
+    }
+
+    public boolean removeUser(RealmModel realm, UserModel user, UserProvider userProvider) {
+        UserSessionProvider sessions = session.sessions();
+        if (sessions != null) {
+            sessions.onUserRemoved(realm, user);
+        }
+
+        UserSessionPersisterProvider sessionsPersister = session.getProvider(UserSessionPersisterProvider.class);
+        if (sessionsPersister != null) {
+            sessionsPersister.onUserRemoved(realm, user);
+        }
+
+        if (userProvider.removeUser(realm, user)) {
+            return true;
+        }
+        return false;
+    }
+
+}
diff --git a/server-spi/src/main/java/org/keycloak/models/utils/RoleUtils.java b/server-spi/src/main/java/org/keycloak/models/utils/RoleUtils.java
new file mode 100644
index 0000000..a03a55d
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/models/utils/RoleUtils.java
@@ -0,0 +1,101 @@
+/*
+ * 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.models.utils;
+
+import org.keycloak.models.GroupModel;
+import org.keycloak.models.RoleModel;
+
+import java.util.Set;
+import java.util.stream.StreamSupport;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class RoleUtils {
+
+    /**
+     *
+     * @param groups
+     * @param targetGroup
+     * @return true if targetGroup is in groups (directly or indirectly via parent child relationship)
+     */
+    public static boolean isMember(Set<GroupModel> groups, GroupModel targetGroup) {
+        if (groups.contains(targetGroup)) return true;
+
+        for (GroupModel mapping : groups) {
+            GroupModel child = mapping;
+            while(child.getParent() != null) {
+                if (child.getParent().equals(targetGroup)) return true;
+                child = child.getParent();
+            }
+        }
+        return false;
+    }
+
+    /**
+     * @param roles
+     * @param targetRole
+     * @return true if targetRole is in roles (directly or indirectly via composite role)
+     */
+    public static boolean hasRole(Set<RoleModel> roles, RoleModel targetRole) {
+        if (roles.contains(targetRole)) return true;
+
+        for (RoleModel mapping : roles) {
+            if (mapping.hasRole(targetRole)) return true;
+        }
+        return false;
+    }
+
+    /**
+     * Checks whether the {@code targetRole} is contained in the given group or its parents
+     * (if requested)
+     * @param group Group to check role for
+     * @param targetRole
+     * @param checkParentGroup When {@code true}, also parent group is recursively checked for role
+     * @return true if targetRole is in roles (directly or indirectly via composite role)
+     */
+    public static boolean hasRoleFromGroup(GroupModel group, RoleModel targetRole, boolean checkParentGroup) {
+        if (group.hasRole(targetRole))
+            return true;
+
+        if (checkParentGroup) {
+            GroupModel parent = group.getParent();
+            return parent != null && hasRoleFromGroup(parent, targetRole, true);
+        }
+
+        return false;
+    }
+
+    /**
+     * Checks whether the {@code targetRole} is contained in any of the {@code groups} or their parents
+     * (if requested)
+     * @param groups
+     * @param targetRole
+     * @param checkParentGroup When {@code true}, also parent group is recursively checked for role
+     * @return true if targetRole is in roles (directly or indirectly via composite role)
+     */
+    public static boolean hasRoleFromGroup(Iterable<GroupModel> groups, RoleModel targetRole, boolean checkParentGroup) {
+        if (groups == null) {
+            return false;
+        }
+
+        return StreamSupport.stream(groups.spliterator(), false)
+                .anyMatch(group -> hasRoleFromGroup(group, targetRole, checkParentGroup));
+    }
+
+}
diff --git a/server-spi/src/main/java/org/keycloak/provider/Spi.java b/server-spi/src/main/java/org/keycloak/provider/Spi.java
index b9c47f8..8043bcf 100644
--- a/server-spi/src/main/java/org/keycloak/provider/Spi.java
+++ b/server-spi/src/main/java/org/keycloak/provider/Spi.java
@@ -17,9 +17,6 @@
 
 package org.keycloak.provider;
 
-import java.util.Collections;
-import java.util.List;
-
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
  */
diff --git a/server-spi/src/main/java/org/keycloak/storage/adapter/AbstractUserAdapter.java b/server-spi/src/main/java/org/keycloak/storage/adapter/AbstractUserAdapter.java
index df6c37a..c159020 100644
--- a/server-spi/src/main/java/org/keycloak/storage/adapter/AbstractUserAdapter.java
+++ b/server-spi/src/main/java/org/keycloak/storage/adapter/AbstractUserAdapter.java
@@ -26,7 +26,7 @@ import org.keycloak.models.RoleContainerModel;
 import org.keycloak.models.RoleModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.utils.DefaultRoles;
-import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.models.utils.RoleUtils;
 import org.keycloak.storage.StorageId;
 
 import java.util.Collections;
@@ -135,7 +135,7 @@ public abstract class AbstractUserAdapter implements UserModel {
     @Override
     public boolean isMemberOf(GroupModel group) {
         Set<GroupModel> roles = getGroups();
-        return KeycloakModelUtils.isMember(roles, group);
+        return RoleUtils.isMember(roles, group);
     }
 
     @Override
@@ -172,8 +172,8 @@ public abstract class AbstractUserAdapter implements UserModel {
     @Override
     public boolean hasRole(RoleModel role) {
         Set<RoleModel> roles = getRoleMappings();
-        return KeycloakModelUtils.hasRole(roles, role)
-          || KeycloakModelUtils.hasRoleFromGroup(getGroups(), role, true);
+        return RoleUtils.hasRole(roles, role)
+          || RoleUtils.hasRoleFromGroup(getGroups(), role, true);
     }
 
     @Override
diff --git a/server-spi/src/main/java/org/keycloak/storage/adapter/AbstractUserAdapterFederatedStorage.java b/server-spi/src/main/java/org/keycloak/storage/adapter/AbstractUserAdapterFederatedStorage.java
index 865f454..c93dac4 100644
--- a/server-spi/src/main/java/org/keycloak/storage/adapter/AbstractUserAdapterFederatedStorage.java
+++ b/server-spi/src/main/java/org/keycloak/storage/adapter/AbstractUserAdapterFederatedStorage.java
@@ -25,7 +25,7 @@ import org.keycloak.models.RoleContainerModel;
 import org.keycloak.models.RoleModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.utils.DefaultRoles;
-import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.models.utils.RoleUtils;
 import org.keycloak.storage.StorageId;
 import org.keycloak.storage.federated.UserFederatedStorageProvider;
 
@@ -140,7 +140,7 @@ public abstract class AbstractUserAdapterFederatedStorage implements UserModel {
     @Override
     public boolean isMemberOf(GroupModel group) {
         Set<GroupModel> roles = getGroups();
-        return KeycloakModelUtils.isMember(roles, group);
+        return RoleUtils.isMember(roles, group);
     }
 
     @Override
@@ -177,8 +177,8 @@ public abstract class AbstractUserAdapterFederatedStorage implements UserModel {
     @Override
     public boolean hasRole(RoleModel role) {
         Set<RoleModel> roles = getRoleMappings();
-        return KeycloakModelUtils.hasRole(roles, role)
-          || KeycloakModelUtils.hasRoleFromGroup(getGroups(), role, true);
+        return RoleUtils.hasRole(roles, role)
+          || RoleUtils.hasRoleFromGroup(getGroups(), role, true);
     }
 
     @Override
diff --git a/server-spi/src/main/resources/META-INF/services/org.keycloak.provider.Spi b/server-spi/src/main/resources/META-INF/services/org.keycloak.provider.Spi
index bbd588e..c7ee486 100755
--- a/server-spi/src/main/resources/META-INF/services/org.keycloak.provider.Spi
+++ b/server-spi/src/main/resources/META-INF/services/org.keycloak.provider.Spi
@@ -15,54 +15,21 @@
 # limitations under the License.
 #
 
-org.keycloak.models.UserFederationSpi
-org.keycloak.storage.UserStorageProviderSpi
-org.keycloak.storage.federated.UserFederatedStorageProviderSpi
-org.keycloak.mappers.UserFederationMapperSpi
-org.keycloak.models.RealmSpi
-org.keycloak.models.UserSessionSpi
-org.keycloak.models.UserSpi
-org.keycloak.models.session.UserSessionPersisterSpi
-org.keycloak.models.dblock.DBLockSpi
-org.keycloak.migration.MigrationSpi
-org.keycloak.events.EventListenerSpi
-org.keycloak.events.EventStoreSpi
-org.keycloak.exportimport.ExportSpi
-org.keycloak.exportimport.ImportSpi
-org.keycloak.timer.TimerSpi
-org.keycloak.scripting.ScriptingSpi
-org.keycloak.services.managers.BruteForceProtectorSpi
-org.keycloak.services.resource.RealmResourceSPI
-org.keycloak.protocol.ClientInstallationSpi
-org.keycloak.protocol.LoginProtocolSpi
-org.keycloak.protocol.ProtocolMapperSpi
-org.keycloak.broker.provider.IdentityProviderSpi
-org.keycloak.broker.provider.IdentityProviderMapperSpi
-org.keycloak.broker.social.SocialProviderSpi
-org.keycloak.forms.account.AccountSpi
-org.keycloak.forms.login.LoginFormsSpi
-org.keycloak.email.EmailSenderSpi
-org.keycloak.email.EmailTemplateSpi
-org.keycloak.theme.ThemeSpi
-org.keycloak.truststore.TruststoreSpi
-org.keycloak.connections.httpclient.HttpClientSpi
-org.keycloak.models.cache.CacheRealmProviderSpi
-org.keycloak.models.cache.CacheUserProviderSpi
-org.keycloak.authentication.AuthenticatorSpi
-org.keycloak.authentication.ClientAuthenticatorSpi
-org.keycloak.authentication.RequiredActionSpi
-org.keycloak.authentication.FormAuthenticatorSpi
-org.keycloak.authentication.FormActionSpi
-org.keycloak.cluster.ClusterSpi
-org.keycloak.authorization.policy.provider.PolicySpi
-org.keycloak.authorization.store.StoreFactorySpi
-org.keycloak.authorization.AuthorizationSpi
-org.keycloak.models.cache.authorization.CachedStoreFactorySpi
-org.keycloak.protocol.oidc.TokenIntrospectionSpi
-org.keycloak.policy.PasswordPolicySpi
-org.keycloak.policy.PasswordPolicyManagerSpi
-org.keycloak.transaction.TransactionManagerLookupSpi
-org.keycloak.credential.hash.PasswordHashSpi
-org.keycloak.credential.CredentialSpi
-org.keycloak.keys.PublicKeyStorageSpi
-org.keycloak.keys.KeySpi
\ No newline at end of file
+#
+# 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.
+#
+
+org.keycloak.storage.UserStorageProviderSpi
\ No newline at end of file
diff --git a/server-spi-private/pom.xml b/server-spi-private/pom.xml
new file mode 100755
index 0000000..a1d3df2
--- /dev/null
+++ b/server-spi-private/pom.xml
@@ -0,0 +1,98 @@
+<?xml version="1.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.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <parent>
+        <artifactId>keycloak-parent</artifactId>
+        <groupId>org.keycloak</groupId>
+        <version>2.4.0.CR1-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>keycloak-server-spi-private</artifactId>
+    <name>Keycloak Server Private SPI</name>
+    <description/>
+
+    <properties>
+        <maven.compiler.target>1.8</maven.compiler.target>
+        <maven.compiler.source>1.8</maven.compiler.source>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-server-spi</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.spec.javax.transaction</groupId>
+            <artifactId>jboss-transaction-api_1.2_spec</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.resteasy</groupId>
+            <artifactId>resteasy-jaxrs</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.bouncycastle</groupId>
+            <artifactId>bcprov-jdk15on</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.bouncycastle</groupId>
+            <artifactId>bcpkix-jdk15on</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.logging</groupId>
+            <artifactId>jboss-logging</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+   </dependencies>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>${maven.compiler.source}</source>
+                    <target>${maven.compiler.target}</target>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/server-spi-private/src/main/java/org/keycloak/models/dblock/DBLockManager.java b/server-spi-private/src/main/java/org/keycloak/models/dblock/DBLockManager.java
new file mode 100644
index 0000000..c41d371
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/models/dblock/DBLockManager.java
@@ -0,0 +1,68 @@
+/*
+ * 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.models.dblock;
+
+import org.jboss.logging.Logger;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmProvider;
+import org.keycloak.models.RealmProviderFactory;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class DBLockManager {
+
+    protected static final Logger logger = Logger.getLogger(DBLockManager.class);
+
+    private final KeycloakSession session;
+
+    public DBLockManager(KeycloakSession session) {
+        this.session = session;
+    }
+
+
+    public void checkForcedUnlock() {
+        if (Boolean.getBoolean("keycloak.dblock.forceUnlock")) {
+            DBLockProvider lock = getDBLock();
+            if (lock.supportsForcedUnlock()) {
+                logger.warn("Forced release of DB lock at startup requested by System property. Make sure to not use this in production environment! And especially when more cluster nodes are started concurrently.");
+                lock.releaseLock();
+            } else {
+                throw new IllegalStateException("Forced unlock requested, but provider " + lock + " doesn't support it");
+            }
+        }
+    }
+
+
+    // Try to detect ID from realmProvider
+    public DBLockProvider getDBLock() {
+        String realmProviderId = getRealmProviderId();
+        return session.getProvider(DBLockProvider.class, realmProviderId);
+    }
+
+    public DBLockProviderFactory getDBLockFactory() {
+        String realmProviderId = getRealmProviderId();
+        return (DBLockProviderFactory) session.getKeycloakSessionFactory().getProviderFactory(DBLockProvider.class, realmProviderId);
+    }
+
+    private String getRealmProviderId() {
+        RealmProviderFactory realmProviderFactory = (RealmProviderFactory) session.getKeycloakSessionFactory().getProviderFactory(RealmProvider.class);
+        return realmProviderFactory.getId();
+    }
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/models/dblock/DBLockProvider.java b/server-spi-private/src/main/java/org/keycloak/models/dblock/DBLockProvider.java
new file mode 100644
index 0000000..d7d6053
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/models/dblock/DBLockProvider.java
@@ -0,0 +1,60 @@
+/*
+ * 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.models.dblock;
+
+import org.keycloak.provider.Provider;
+
+/**
+ * Global database lock to ensure that some actions in DB can be done just be one cluster node at a time.
+ *
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public interface DBLockProvider extends Provider {
+
+
+    /**
+     * Try to retrieve DB lock or wait if retrieve was unsuccessful. Throw exception if lock can't be retrieved within specified timeout (900 seconds by default)
+     */
+    void waitForLock();
+
+
+    /**
+     * Release previously acquired lock
+     */
+    void releaseLock();
+
+    /**
+     * Check if I have lock
+     *
+     * @return
+     */
+    boolean hasLock();
+
+
+    /**
+     * @return true if provider supports forced unlock at startup
+     */
+    boolean supportsForcedUnlock();
+
+
+    /**
+     * Will destroy whole state of DB lock (drop table/collection to track locking).
+     * */
+    void destroyLockInfo();
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/models/dblock/DBLockProviderFactory.java b/server-spi-private/src/main/java/org/keycloak/models/dblock/DBLockProviderFactory.java
new file mode 100644
index 0000000..747a168
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/models/dblock/DBLockProviderFactory.java
@@ -0,0 +1,31 @@
+/*
+ * 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.models.dblock;
+
+import org.keycloak.provider.ProviderFactory;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public interface DBLockProviderFactory extends ProviderFactory<DBLockProvider> {
+
+    /**
+     * Useful for testing to override provided configuration
+     */
+    void setTimeouts(long lockRecheckTimeMillis, long lockWaitTimeoutMillis);
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/models/dblock/DBLockSpi.java b/server-spi-private/src/main/java/org/keycloak/models/dblock/DBLockSpi.java
new file mode 100644
index 0000000..cd78f0f
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/models/dblock/DBLockSpi.java
@@ -0,0 +1,48 @@
+/*
+ * 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.models.dblock;
+
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.provider.Spi;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class DBLockSpi implements Spi {
+
+    @Override
+    public boolean isInternal() {
+        return true;
+    }
+
+    @Override
+    public String getName() {
+        return "dblock";
+    }
+
+    @Override
+    public Class<? extends Provider> getProviderClass() {
+        return DBLockProvider.class;
+    }
+
+    @Override
+    public Class<? extends ProviderFactory> getProviderFactoryClass() {
+        return DBLockProviderFactory.class;
+    }
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/models/session/DisabledUserSessionPersisterProvider.java b/server-spi-private/src/main/java/org/keycloak/models/session/DisabledUserSessionPersisterProvider.java
new file mode 100644
index 0000000..f5e58d3
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/models/session/DisabledUserSessionPersisterProvider.java
@@ -0,0 +1,126 @@
+/*
+ * 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.models.session;
+
+import org.keycloak.Config;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.ClientSessionModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.UserSessionModel;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Persistence of userSessions is disabled . Useful just if you never need survive of userSessions/clientSessions
+ * among server restart. Offline sessions / offline tokens will be invalid after server restart as well,
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class DisabledUserSessionPersisterProvider implements UserSessionPersisterProviderFactory, UserSessionPersisterProvider {
+
+    public static final String ID = "disabled";
+
+    @Override
+    public UserSessionPersisterProvider create(KeycloakSession session) {
+        return this;
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+
+    }
+
+    @Override
+    public void close() {
+
+    }
+
+    @Override
+    public String getId() {
+        return ID;
+    }
+
+    @Override
+    public void createUserSession(UserSessionModel userSession, boolean offline) {
+
+    }
+
+    @Override
+    public void createClientSession(ClientSessionModel clientSession, boolean offline) {
+
+    }
+
+    @Override
+    public void updateUserSession(UserSessionModel userSession, boolean offline) {
+
+    }
+
+    @Override
+    public void removeUserSession(String userSessionId, boolean offline) {
+
+    }
+
+    @Override
+    public void removeClientSession(String clientSessionId, boolean offline) {
+
+    }
+
+    @Override
+    public void onRealmRemoved(RealmModel realm) {
+
+    }
+
+    @Override
+    public void onClientRemoved(RealmModel realm, ClientModel client) {
+
+    }
+
+    @Override
+    public void onUserRemoved(RealmModel realm, UserModel user) {
+
+    }
+
+    @Override
+    public void clearDetachedUserSessions() {
+
+    }
+
+    @Override
+    public void updateAllTimestamps(int time) {
+
+    }
+
+    @Override
+    public List<UserSessionModel> loadUserSessions(int firstResult, int maxResults, boolean offline) {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public int getUserSessionsCount(boolean offline) {
+        return 0;
+    }
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/models/session/PersistentClientSessionModel.java b/server-spi-private/src/main/java/org/keycloak/models/session/PersistentClientSessionModel.java
new file mode 100644
index 0000000..5990eea
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/models/session/PersistentClientSessionModel.java
@@ -0,0 +1,79 @@
+/*
+ * 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.models.session;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class PersistentClientSessionModel {
+
+    private String clientSessionId;
+    private String userSessionId;
+    private String clientId;
+    private String userId;
+    private int timestamp;
+    private String data;
+
+    public String getClientSessionId() {
+        return clientSessionId;
+    }
+
+    public void setClientSessionId(String clientSessionId) {
+        this.clientSessionId = clientSessionId;
+    }
+
+    public String getUserSessionId() {
+        return userSessionId;
+    }
+
+    public void setUserSessionId(String userSessionId) {
+        this.userSessionId = userSessionId;
+    }
+
+    public String getClientId() {
+        return clientId;
+    }
+
+    public void setClientId(String clientId) {
+        this.clientId = clientId;
+    }
+
+    public String getUserId() {
+        return userId;
+    }
+
+    public void setUserId(String userId) {
+        this.userId = userId;
+    }
+
+    public int getTimestamp() {
+        return timestamp;
+    }
+
+    public void setTimestamp(int timestamp) {
+        this.timestamp = timestamp;
+    }
+
+    public String getData() {
+        return data;
+    }
+
+    public void setData(String data) {
+        this.data = data;
+    }
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/models/session/PersistentUserSessionModel.java b/server-spi-private/src/main/java/org/keycloak/models/session/PersistentUserSessionModel.java
new file mode 100644
index 0000000..d7e0a04
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/models/session/PersistentUserSessionModel.java
@@ -0,0 +1,54 @@
+/*
+ * 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.models.session;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class PersistentUserSessionModel {
+
+    private String userSessionId;
+    private int lastSessionRefresh;
+
+    private String data;
+
+    public String getUserSessionId() {
+        return userSessionId;
+    }
+
+    public void setUserSessionId(String userSessionId) {
+        this.userSessionId = userSessionId;
+    }
+
+    public int getLastSessionRefresh() {
+        return lastSessionRefresh;
+    }
+
+    public void setLastSessionRefresh(int lastSessionRefresh) {
+        this.lastSessionRefresh = lastSessionRefresh;
+    }
+
+
+    public String getData() {
+        return data;
+    }
+
+    public void setData(String data) {
+        this.data = data;
+    }
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/models/session/UserSessionPersisterProviderFactory.java b/server-spi-private/src/main/java/org/keycloak/models/session/UserSessionPersisterProviderFactory.java
new file mode 100644
index 0000000..2c0b98c
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/models/session/UserSessionPersisterProviderFactory.java
@@ -0,0 +1,26 @@
+/*
+ * 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.models.session;
+
+import org.keycloak.provider.ProviderFactory;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public interface UserSessionPersisterProviderFactory extends ProviderFactory<UserSessionPersisterProvider> {
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/models/session/UserSessionPersisterSpi.java b/server-spi-private/src/main/java/org/keycloak/models/session/UserSessionPersisterSpi.java
new file mode 100644
index 0000000..7e9dc4f
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/models/session/UserSessionPersisterSpi.java
@@ -0,0 +1,48 @@
+/*
+ * 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.models.session;
+
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.provider.Spi;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class UserSessionPersisterSpi implements Spi {
+
+    @Override
+    public boolean isInternal() {
+        return true;
+    }
+
+    @Override
+    public String getName() {
+        return "userSessionPersister";
+    }
+
+    @Override
+    public Class<? extends Provider> getProviderClass() {
+        return UserSessionPersisterProvider.class;
+    }
+
+    @Override
+    public Class<? extends ProviderFactory> getProviderFactoryClass() {
+        return UserSessionPersisterProviderFactory.class;
+    }
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/ComponentUtil.java b/server-spi-private/src/main/java/org/keycloak/models/utils/ComponentUtil.java
new file mode 100644
index 0000000..5efbb1c
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/models/utils/ComponentUtil.java
@@ -0,0 +1,93 @@
+/*
+ * 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.models.utils;
+
+import org.keycloak.component.ComponentFactory;
+import org.keycloak.component.ComponentModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderConfigProperty;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.representations.idm.ComponentRepresentation;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class ComponentUtil {
+
+    public static Map<String, ProviderConfigProperty> getComponentConfigProperties(KeycloakSession session, ComponentRepresentation component) {
+        return getComponentConfigProperties(session, component.getProviderType(), component.getProviderId());
+    }
+
+    public static Map<String, ProviderConfigProperty> getComponentConfigProperties(KeycloakSession session, ComponentModel component) {
+        return getComponentConfigProperties(session, component.getProviderType(), component.getProviderId());
+    }
+
+    public static ComponentFactory getComponentFactory(KeycloakSession session, ComponentRepresentation component) {
+        return getComponentFactory(session, component.getProviderType(), component.getProviderId());
+    }
+
+    public static ComponentFactory getComponentFactory(KeycloakSession session, ComponentModel component) {
+        return getComponentFactory(session, component.getProviderType(), component.getProviderId());
+    }
+
+    private static Map<String, ProviderConfigProperty> getComponentConfigProperties(KeycloakSession session, String providerType, String providerId) {
+        try {
+            ComponentFactory componentFactory = getComponentFactory(session, providerType, providerId);
+            List<ProviderConfigProperty> l = componentFactory.getConfigProperties();
+            Map<String, ProviderConfigProperty> properties = new HashMap<>();
+            for (ProviderConfigProperty p : l) {
+                properties.put(p.getName(), p);
+            }
+            List<ProviderConfigProperty> common = componentFactory.getCommonProviderConfigProperties();
+            for (ProviderConfigProperty p : common) {
+                properties.put(p.getName(), p);
+            }
+
+            return properties;
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private static ComponentFactory getComponentFactory(KeycloakSession session, String providerType, String providerId) {
+        Class<? extends Provider> provider = session.getProviderClass(providerType);
+        if (provider == null) {
+            throw new IllegalArgumentException("Invalid provider type '" + providerType + "'");
+        }
+
+        ProviderFactory<? extends Provider> f = session.getKeycloakSessionFactory().getProviderFactory(provider, providerId);
+        if (f == null) {
+            throw new IllegalArgumentException("No such provider '" + providerId + "'");
+        }
+
+        ComponentFactory cf = (ComponentFactory) f;
+        return cf;
+    }
+
+    public static void notifyCreated(KeycloakSession session, RealmModel realm, ComponentModel model) {
+        ComponentFactory factory = getComponentFactory(session, model);
+        factory.onCreate(session, realm, model);
+    }
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/CredentialValidation.java b/server-spi-private/src/main/java/org/keycloak/models/utils/CredentialValidation.java
new file mode 100755
index 0000000..598e3e9
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/models/utils/CredentialValidation.java
@@ -0,0 +1,44 @@
+/*
+ * 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.models.utils;
+
+import org.keycloak.models.OTPPolicy;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserCredentialModel;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class CredentialValidation {
+
+    public static boolean validOTP(RealmModel realm, String token, String secret) {
+        OTPPolicy policy = realm.getOTPPolicy();
+        if (policy.getType().equals(UserCredentialModel.TOTP)) {
+            TimeBasedOTP validator = new TimeBasedOTP(policy.getAlgorithm(), policy.getDigits(), policy.getPeriod(), policy.getLookAheadWindow());
+            return validator.validateTOTP(token, secret.getBytes());
+        } else {
+            HmacOTP validator = new HmacOTP(policy.getDigits(), policy.getAlgorithm(), policy.getLookAheadWindow());
+            int c = validator.validateHOTP(token, secret, policy.getInitialCounter());
+            return c > -1;
+        }
+
+    }
+
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/DefaultKeyProviders.java b/server-spi-private/src/main/java/org/keycloak/models/utils/DefaultKeyProviders.java
new file mode 100644
index 0000000..30ff7d7
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/models/utils/DefaultKeyProviders.java
@@ -0,0 +1,62 @@
+/*
+ * 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.models.utils;
+
+import org.keycloak.common.util.MultivaluedHashMap;
+import org.keycloak.component.ComponentModel;
+import org.keycloak.keys.KeyProvider;
+import org.keycloak.models.RealmModel;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class DefaultKeyProviders {
+
+    public static void createProviders(RealmModel realm) {
+        ComponentModel generated = new ComponentModel();
+        generated.setName("rsa-generated");
+        generated.setParentId(realm.getId());
+        generated.setProviderId("rsa-generated");
+        generated.setProviderType(KeyProvider.class.getName());
+
+        MultivaluedHashMap<String, String> config = new MultivaluedHashMap<>();
+        config.putSingle("priority", "100");
+        generated.setConfig(config);
+
+        realm.addComponentModel(generated);
+    }
+
+    public static void createProviders(RealmModel realm, String privateKeyPem, String certificatePem) {
+        ComponentModel rsa = new ComponentModel();
+        rsa.setName("rsa");
+        rsa.setParentId(realm.getId());
+        rsa.setProviderId("rsa");
+        rsa.setProviderType(KeyProvider.class.getName());
+
+        MultivaluedHashMap<String, String> config = new MultivaluedHashMap<>();
+        config.putSingle("priority", "100");
+        config.putSingle("privateKey", privateKeyPem);
+        if (certificatePem != null) {
+            config.putSingle("certificate", certificatePem);
+        }
+        rsa.setConfig(config);
+
+        realm.addComponentModel(rsa);
+    }
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/DefaultRequiredActions.java b/server-spi-private/src/main/java/org/keycloak/models/utils/DefaultRequiredActions.java
new file mode 100755
index 0000000..db38b64
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/models/utils/DefaultRequiredActions.java
@@ -0,0 +1,83 @@
+/*
+ * 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.models.utils;
+
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RequiredActionProviderModel;
+import org.keycloak.models.UserModel;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class DefaultRequiredActions {
+    public static void addActions(RealmModel realm) {
+        if (realm.getRequiredActionProviderByAlias(UserModel.RequiredAction.VERIFY_EMAIL.name()) == null) {
+            RequiredActionProviderModel verifyEmail = new RequiredActionProviderModel();
+            verifyEmail.setEnabled(true);
+            verifyEmail.setAlias(UserModel.RequiredAction.VERIFY_EMAIL.name());
+            verifyEmail.setName("Verify Email");
+            verifyEmail.setProviderId(UserModel.RequiredAction.VERIFY_EMAIL.name());
+            verifyEmail.setDefaultAction(false);
+            realm.addRequiredActionProvider(verifyEmail);
+
+        }
+
+        if (realm.getRequiredActionProviderByAlias(UserModel.RequiredAction.UPDATE_PROFILE.name()) == null) {
+            RequiredActionProviderModel updateProfile = new RequiredActionProviderModel();
+            updateProfile.setEnabled(true);
+            updateProfile.setAlias(UserModel.RequiredAction.UPDATE_PROFILE.name());
+            updateProfile.setName("Update Profile");
+            updateProfile.setProviderId(UserModel.RequiredAction.UPDATE_PROFILE.name());
+            updateProfile.setDefaultAction(false);
+            realm.addRequiredActionProvider(updateProfile);
+        }
+
+        if (realm.getRequiredActionProviderByAlias(UserModel.RequiredAction.CONFIGURE_TOTP.name()) == null) {
+            RequiredActionProviderModel totp = new RequiredActionProviderModel();
+            totp.setEnabled(true);
+            totp.setAlias(UserModel.RequiredAction.CONFIGURE_TOTP.name());
+            totp.setName("Configure OTP");
+            totp.setProviderId(UserModel.RequiredAction.CONFIGURE_TOTP.name());
+            totp.setDefaultAction(false);
+            realm.addRequiredActionProvider(totp);
+        }
+
+        if (realm.getRequiredActionProviderByAlias(UserModel.RequiredAction.UPDATE_PASSWORD.name()) == null) {
+            RequiredActionProviderModel updatePassword = new RequiredActionProviderModel();
+            updatePassword.setEnabled(true);
+            updatePassword.setAlias(UserModel.RequiredAction.UPDATE_PASSWORD.name());
+            updatePassword.setName("Update Password");
+            updatePassword.setProviderId(UserModel.RequiredAction.UPDATE_PASSWORD.name());
+            updatePassword.setDefaultAction(false);
+            realm.addRequiredActionProvider(updatePassword);
+        }
+
+        if (realm.getRequiredActionProviderByAlias("terms_and_conditions") == null) {
+            RequiredActionProviderModel termsAndConditions = new RequiredActionProviderModel();
+            termsAndConditions.setEnabled(false);
+            termsAndConditions.setAlias("terms_and_conditions");
+            termsAndConditions.setName("Terms and Conditions");
+            termsAndConditions.setProviderId("terms_and_conditions");
+            termsAndConditions.setDefaultAction(false);
+            realm.addRequiredActionProvider(termsAndConditions);
+        }
+
+
+    }
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/FormMessage.java b/server-spi-private/src/main/java/org/keycloak/models/utils/FormMessage.java
new file mode 100755
index 0000000..e3b6a23
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/models/utils/FormMessage.java
@@ -0,0 +1,87 @@
+/*
+ * 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.models.utils;
+
+import java.util.Arrays;
+
+/**
+ * Message (eg. error) to be shown in form.
+ * 
+ * @author Vlastimil Elias (velias at redhat dot com)
+ */
+public class FormMessage {
+
+	/**
+	 * Value used for {@link #field} if message is global (not tied to any specific form field)
+	 */
+	public static final String GLOBAL = "global";
+
+	private String field;
+	private String message;
+	private Object[] parameters;
+
+	public FormMessage() {
+	}
+
+	/**
+	 * Create message.
+	 * 
+	 * @param field this message is for. {@link #GLOBAL} is used if null
+	 * @param message key for the message
+	 * @param parameters to be formatted into message
+	 */
+	public FormMessage(String field, String message, Object... parameters) {
+		this(field, message);
+		this.parameters = parameters;
+	}
+
+    public FormMessage(String message, Object...parameters) {
+        this(null, message, parameters);
+    }
+	
+	/**
+     * Create message without parameters.
+     * 
+     * @param field this message is for. {@link #GLOBAL} is used if null
+     * @param message key for the message
+     */
+    public FormMessage(String field, String message) {
+        super();
+        if (field == null)
+            field = GLOBAL;
+        this.field = field;
+        this.message = message;
+    }
+
+	public String getField() {
+		return field;
+	}
+
+	public String getMessage() {
+		return message;
+	}
+
+	public Object[] getParameters() {
+		return parameters;
+	}
+
+	@Override
+	public String toString() {
+		return "FormMessage [field=" + field + ", message=" + message + ", parameters=" + Arrays.toString(parameters) + "]";
+	}
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/PostMigrationEvent.java b/server-spi-private/src/main/java/org/keycloak/models/utils/PostMigrationEvent.java
new file mode 100644
index 0000000..73889e0
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/models/utils/PostMigrationEvent.java
@@ -0,0 +1,28 @@
+/*
+ * 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.models.utils;
+
+import org.keycloak.provider.ProviderEvent;
+
+/**
+ * Executed at startup after model migration is finished
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class PostMigrationEvent implements ProviderEvent {
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/RealmImporter.java b/server-spi-private/src/main/java/org/keycloak/models/utils/RealmImporter.java
new file mode 100644
index 0000000..e2c3401
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/models/utils/RealmImporter.java
@@ -0,0 +1,31 @@
+/*
+ * 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.models.utils;
+
+import org.keycloak.models.RealmModel;
+import org.keycloak.representations.idm.RealmRepresentation;
+
+/**
+ * Helper interface used just because RealmManager is in keycloak-services and not accessible for ImportUtils
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public interface RealmImporter {
+
+    RealmModel importRealm(RealmRepresentation rep);
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/RealmInfoUtil.java b/server-spi-private/src/main/java/org/keycloak/models/utils/RealmInfoUtil.java
new file mode 100644
index 0000000..e55e065
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/models/utils/RealmInfoUtil.java
@@ -0,0 +1,38 @@
+/*
+ * 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.models.utils;
+
+import org.keycloak.models.RealmModel;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class RealmInfoUtil {
+
+    public static int getDettachedClientSessionLifespan(RealmModel realm) {
+        int lifespan = realm.getAccessCodeLifespanLogin();
+        if (realm.getAccessCodeLifespanUserAction() > lifespan) {
+            lifespan = realm.getAccessCodeLifespanUserAction();
+        }
+        if (realm.getAccessCodeLifespan() > lifespan) {
+            lifespan = realm.getAccessCodeLifespan();
+        }
+        return lifespan;
+    }
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/reflection/AnnotatedPropertyCriteria.java b/server-spi-private/src/main/java/org/keycloak/models/utils/reflection/AnnotatedPropertyCriteria.java
new file mode 100644
index 0000000..2dbec10
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/models/utils/reflection/AnnotatedPropertyCriteria.java
@@ -0,0 +1,40 @@
+/*
+ * 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.models.utils.reflection;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+
+/**
+ * A criteria that matches a property based on its annotations
+ *
+ * @see PropertyCriteria
+ */
+public class AnnotatedPropertyCriteria implements PropertyCriteria {
+    private final Class<? extends Annotation> annotationClass;
+
+    public AnnotatedPropertyCriteria(Class<? extends Annotation> annotationClass) {
+        this.annotationClass = annotationClass;
+    }
+
+    @Override
+    public boolean methodMatches(Method m) {
+        return m.isAnnotationPresent(annotationClass);
+    }
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/reflection/MethodProperty.java b/server-spi-private/src/main/java/org/keycloak/models/utils/reflection/MethodProperty.java
new file mode 100644
index 0000000..fac6a89
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/models/utils/reflection/MethodProperty.java
@@ -0,0 +1,25 @@
+/*
+ * 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.models.utils.reflection;
+
+import java.lang.reflect.Method;
+
+public interface MethodProperty<V> extends Property<V> {
+
+    Method getAnnotatedElement();
+}
\ No newline at end of file
diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/reflection/NamedPropertyCriteria.java b/server-spi-private/src/main/java/org/keycloak/models/utils/reflection/NamedPropertyCriteria.java
new file mode 100644
index 0000000..e81734a
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/models/utils/reflection/NamedPropertyCriteria.java
@@ -0,0 +1,57 @@
+/*
+ * 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.models.utils.reflection;
+
+import java.beans.Introspector;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+/**
+ * A criteria that matches a property based on name
+ *
+ * @see PropertyCriteria
+ */
+public class NamedPropertyCriteria implements PropertyCriteria {
+    private final String[] propertyNames;
+
+    public NamedPropertyCriteria(String... propertyNames) {
+        this.propertyNames = propertyNames;
+    }
+
+    public boolean fieldMatches(Field f) {
+        for (String propertyName : propertyNames) {
+            if (propertyName.equals(f.getName())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public boolean methodMatches(Method m) {
+        String[] validPrefix = {"get", "is"};
+        for (String propertyName : propertyNames) {
+            for (String prefix : validPrefix) {
+                if (m.getName().startsWith(prefix) &&
+                        Introspector.decapitalize(m.getName().substring(prefix.length())).equals(propertyName)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/reflection/Properties.java b/server-spi-private/src/main/java/org/keycloak/models/utils/reflection/Properties.java
new file mode 100755
index 0000000..ebb1381
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/models/utils/reflection/Properties.java
@@ -0,0 +1,59 @@
+/*
+ * 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.models.utils.reflection;
+
+import java.lang.reflect.Method;
+
+/**
+ * Utility class for working with JavaBean style properties
+ *
+ * @see Property
+ */
+public class Properties {
+
+    private Properties() {
+    }
+
+    /**
+     * Create a JavaBean style property from the specified method
+     *
+     * @param <V>
+     * @param method
+     *
+     * @return
+     *
+     * @throws IllegalArgumentException if the method does not match JavaBean conventions
+     * @see http://www.oracle.com/technetwork/java/javase/documentation/spec-136004.html
+     */
+    public static <V> MethodProperty<V> createProperty(Method method) {
+        return new MethodPropertyImpl<V>(method);
+    }
+
+    /**
+     * Indicates whether this method is a valid property method.
+     */
+    public static <V> boolean isProperty(Method method) {
+        try {
+            new MethodPropertyImpl<V>(method);
+            return true;
+        } catch (IllegalArgumentException e) {
+            return false;
+        }
+    }
+}
+
diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/reflection/Property.java b/server-spi-private/src/main/java/org/keycloak/models/utils/reflection/Property.java
new file mode 100644
index 0000000..fcf6fe4
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/models/utils/reflection/Property.java
@@ -0,0 +1,122 @@
+/*
+ * 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.models.utils.reflection;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Member;
+import java.lang.reflect.Type;
+
+/**
+ * A representation of a JavaBean style property
+ *
+ * @param <V> the type of the properties value
+ *
+ * @see Properties
+ */
+public interface Property<V> {
+
+    /**
+     * Returns the name of the property. If the property is a field, then the field name is returned. Otherwise, if the
+     * property is a method, then the name that is returned is the getter method name without the "get" or "is" prefix,
+     * and a lower case first letter.
+     *
+     * @return The name of the property
+     */
+    String getName();
+
+    /**
+     * Returns the property type
+     *
+     * @return The property type
+     */
+    Type getBaseType();
+
+    /**
+     * Returns the property type
+     *
+     * @return The property type
+     */
+    Class<V> getJavaClass();
+
+    /**
+     * Get the element responsible for retrieving the property value
+     *
+     * @return
+     */
+    AnnotatedElement getAnnotatedElement();
+
+    /**
+     * Get the member responsible for retrieving the property value
+     *
+     * @return
+     */
+    Member getMember();
+
+    /**
+     * Returns the property value for the specified bean. The property to be returned is either a field or getter
+     * method.
+     *
+     * @param bean The bean to read the property from
+     *
+     * @return The property value
+     *
+     * @throws ClassCastException if the value is not of the type V
+     */
+    V getValue(Object instance);
+
+    /**
+     * This method sets the property value for a specified bean to the specified value. The property to be set is either
+     * a field or setter method.
+     *
+     * @param bean The bean containing the property to set
+     * @param value The new property value
+     */
+    void setValue(Object instance, V value);
+
+    /**
+     * Returns the class that declares the property
+     *
+     * @return
+     */
+    Class<?> getDeclaringClass();
+
+    /**
+     * Indicates whether this is a read-only property
+     *
+     * @return
+     */
+    boolean isReadOnly();
+
+    /**
+     * Calls the setAccessible method on the underlying member(s).
+     * <p/>
+     * The operation should be performed within a {@link PrivilegedAction}
+     */
+    void setAccessible();
+
+    /**
+     * Indicates whether the given <code>annotation</code> is defined for this property. This method will consider
+     * the annotations present in both field and accessor method.
+     *
+     * @param annotation The Annotation to check.
+     *
+     * @return True if the annotation is defined. Otherwise is false.
+     */
+    boolean isAnnotationPresent(Class<? extends Annotation> annotation);
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/reflection/PropertyCriteria.java b/server-spi-private/src/main/java/org/keycloak/models/utils/reflection/PropertyCriteria.java
new file mode 100755
index 0000000..2f3b8b1
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/models/utils/reflection/PropertyCriteria.java
@@ -0,0 +1,43 @@
+/*
+ * 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.models.utils.reflection;
+
+import java.lang.reflect.Method;
+
+/**
+ * <p> A property criteria can be used to filter the properties found by a {@link PropertyQuery} </p> <p/> <p>
+ * DeltaSpike provides a number of property queries ( {@link TypedPropertyCriteria}, {@link NamedPropertyCriteria} and
+ * {@link AnnotatedPropertyCriteria}), or you can create a custom query by implementing this interface. </p>
+ *
+ * @see PropertyQuery#addCriteria(PropertyCriteria)
+ * @see PropertyQueries
+ * @see TypedPropertyCriteria
+ * @see AnnotatedPropertyCriteria
+ * @see NamedPropertyCriteria
+ */
+public interface PropertyCriteria {
+
+    /**
+     * Tests whether the specified method matches the criteria
+     *
+     * @param m
+     *
+     * @return true if the method matches
+     */
+    boolean methodMatches(Method m);
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/reflection/PropertyQueries.java b/server-spi-private/src/main/java/org/keycloak/models/utils/reflection/PropertyQueries.java
new file mode 100644
index 0000000..debabb7
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/models/utils/reflection/PropertyQueries.java
@@ -0,0 +1,42 @@
+/*
+ * 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.models.utils.reflection;
+
+/**
+ * Utilities for working with property queries
+ *
+ * @see PropertyQuery
+ */
+public class PropertyQueries {
+
+    private PropertyQueries() {
+    }
+
+    /**
+     * Create a new {@link PropertyQuery}
+     *
+     * @param <V>
+     * @param targetClass
+     *
+     * @return
+     */
+    public static <V> PropertyQuery<V> createQuery(Class<?> targetClass) {
+        return new PropertyQuery<V>(targetClass);
+    }
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/reflection/PropertyQuery.java b/server-spi-private/src/main/java/org/keycloak/models/utils/reflection/PropertyQuery.java
new file mode 100644
index 0000000..5d7cbf5
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/models/utils/reflection/PropertyQuery.java
@@ -0,0 +1,179 @@
+/*
+ * 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.models.utils.reflection;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * <p> Queries a target class for properties that match certain criteria. A property may either be a private or public
+ * field, declared by the target class or inherited from a superclass, or a public method declared by the target class
+ * or inherited from any of its superclasses. For properties that are exposed via a method, the property must be a
+ * JavaBean style property, i.e. it must provide both an accessor and mutator method according to the JavaBean
+ * specification. </p> <p/> <p> This class is not thread-safe, however the result returned by the getResultList() method
+ * is. </p>
+ *
+ * @see PropertyQueries
+ * @see PropertyCriteria
+ */
+public class PropertyQuery<V> {
+    private final Class<?> targetClass;
+    private final List<PropertyCriteria> criteria;
+
+    PropertyQuery(Class<?> targetClass) {
+        if (targetClass == null) {
+            throw new IllegalArgumentException("targetClass parameter may not be null");
+        }
+
+        this.targetClass = targetClass;
+        this.criteria = new ArrayList<PropertyCriteria>();
+    }
+
+    /**
+     * Add a criteria to query
+     *
+     * @param criteria the criteria to add
+     */
+    public PropertyQuery<V> addCriteria(PropertyCriteria criteria) {
+        this.criteria.add(criteria);
+        return this;
+    }
+
+    /**
+     * Get the first result from the query, causing the query to be run.
+     *
+     * @return the first result, or null if there are no results
+     */
+    public Property<V> getFirstResult() {
+        Map<String, Property<V>> results = getResultList();
+        return results.isEmpty() ? null : results.values().iterator().next();
+    }
+
+    /**
+     * Get the first result from the query that is not marked as read only, causing the query to be run.
+     *
+     * @return the first writable result, or null if there are no results
+     */
+    public Property<V> getFirstWritableResult() {
+        Map<String, Property<V>>  results = getWritableResultList();
+        return results.isEmpty() ? null : results.values().iterator().next();
+    }
+
+    /**
+     * Get a single result from the query, causing the query to be run. An exception is thrown if the query does not
+     * return exactly one result.
+     *
+     * @return the single result
+     *
+     * @throws RuntimeException if the query does not return exactly one result
+     */
+    public Property<V> getSingleResult() {
+        Map<String, Property<V>> results = getResultList();
+        if (results.size() == 1) {
+            return results.values().iterator().next();
+        } else if (results.isEmpty()) {
+            throw new RuntimeException(
+                    "Expected one property match, but the criteria did not match any properties on " +
+                            targetClass.getName());
+        } else {
+            throw new RuntimeException("Expected one property match, but the criteria matched " + results.size() +
+                    " properties on " + targetClass.getName());
+        }
+    }
+
+    /**
+     * Get a single result from the query that is not marked as read only, causing the query to be run. An exception is
+     * thrown if the query does not return exactly one result.
+     *
+     * @return the single writable result
+     *
+     * @throws RuntimeException if the query does not return exactly one result
+     */
+    public Property<V> getWritableSingleResult() {
+        Map<String, Property<V>> results = getWritableResultList();
+        if (results.size() == 1) {
+            return results.values().iterator().next();
+        } else if (results.isEmpty()) {
+            throw new RuntimeException(
+                    "Expected one property match, but the criteria did not match any properties on " +
+                            targetClass.getName());
+        } else {
+            throw new RuntimeException("Expected one property match, but the criteria matched " +
+                    results.size() + " properties on " + targetClass.getName());
+        }
+    }
+
+    /**
+     * Get the result from the query, causing the query to be run.
+     *
+     * @return the results, or an empty list if there are no results
+     */
+    public Map<String, Property<V>> getResultList() {
+        return getResultList(false);
+    }
+
+    /**
+     * Get the non read only results from the query, causing the query to be run.
+     *
+     * @return the results, or an empty list if there are no results
+     */
+    public Map<String, Property<V>> getWritableResultList() {
+        return getResultList(true);
+    }
+
+    /**
+     * Get the result from the query, causing the query to be run.
+     *
+     * @param writable if this query should only return properties that are not read only
+     *
+     * @return the results, or an empty list if there are no results
+     */
+    private Map<String, Property<V>> getResultList(boolean writable) {
+        Map<String, Property<V>> properties = new HashMap<String, Property<V>>();
+
+        // First check public accessor methods (we ignore private methods)
+        for (Method method : targetClass.getMethods()) {
+            if (!(method.getName().startsWith("is") || method.getName().startsWith("get"))) {
+                continue;
+            }
+
+            boolean match = true;
+            for (PropertyCriteria c : criteria) {
+                if (!c.methodMatches(method)) {
+                    match = false;
+                    break;
+                }
+            }
+
+            if (match) {
+                MethodProperty<V> property = Properties.<V>createProperty(method);
+
+                if (!writable || !property.isReadOnly()) {
+                    properties.put(property.getName(), property);
+                }
+            }
+        }
+
+        return Collections.unmodifiableMap(properties);
+    }
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/reflection/TypedPropertyCriteria.java b/server-spi-private/src/main/java/org/keycloak/models/utils/reflection/TypedPropertyCriteria.java
new file mode 100644
index 0000000..1fbafe1
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/models/utils/reflection/TypedPropertyCriteria.java
@@ -0,0 +1,88 @@
+/*
+ * 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.models.utils.reflection;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+/**
+ * A criteria that matches a property based on its type
+ *
+ * @see PropertyCriteria
+ */
+public class TypedPropertyCriteria implements PropertyCriteria {
+
+    /**
+     * <p> Different options can be used to match a specific property based on its type. Regardless of the option
+     * chosen, if the property type equals the <code>propertyClass</code> it will be selected. <p/> <ul> <li>SUB_TYPE:
+     * Also consider properties where its type is a subtype of <code>propertyClass</code>. .</li> <li>SUPER_TYPE: Also
+     * consider properties where its type is a superclass or superinterface of <code>propertyClass</code>. .</li> </ul>
+     * </p>
+     */
+    public static enum MatchOption {
+        SUB_TYPE, SUPER_TYPE, ALL
+    }
+
+    private final Class<?> propertyClass;
+    private final MatchOption matchOption;
+
+    public TypedPropertyCriteria(Class<?> propertyClass) {
+        this(propertyClass, null);
+    }
+
+    public TypedPropertyCriteria(Class<?> propertyClass, MatchOption matchOption) {
+        if (propertyClass == null) {
+            throw new IllegalArgumentException("Property class can not be null.");
+        }
+        this.propertyClass = propertyClass;
+        this.matchOption = matchOption;
+    }
+
+    public boolean fieldMatches(Field f) {
+        return match(f.getType());
+    }
+
+    public boolean methodMatches(Method m) {
+        return match(m.getReturnType());
+    }
+
+    private boolean match(Class<?> type) {
+        if (propertyClass.equals(type)) {
+            return true;
+        } else {
+            boolean matchSubType = propertyClass.isAssignableFrom(type);
+
+            if (MatchOption.SUB_TYPE == this.matchOption) {
+                return matchSubType;
+            }
+
+            boolean matchSuperType = type.isAssignableFrom(propertyClass);
+
+            if (MatchOption.SUPER_TYPE == this.matchOption) {
+                return matchSuperType;
+            }
+
+            if (MatchOption.ALL == this.matchOption) {
+                return matchSubType || matchSuperType;
+            }
+        }
+
+        return false;
+    }
+}
+
diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/SHAPasswordEncoder.java b/server-spi-private/src/main/java/org/keycloak/models/utils/SHAPasswordEncoder.java
new file mode 100755
index 0000000..8b4c25a
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/models/utils/SHAPasswordEncoder.java
@@ -0,0 +1,77 @@
+/*
+ * 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.models.utils;
+
+import org.keycloak.common.util.Base64;
+
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+
+/**
+ * <p>
+ * Password that uses SHA to encode passwords. You can always change the SHA strength by specifying a valid
+ * integer when creating a new instance.
+ * </p>
+ * <p>Passwords are returned with a Base64 encoding.</p>
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Silva</a>
+ *
+ */
+public class SHAPasswordEncoder {
+
+    private int strength;
+
+    public SHAPasswordEncoder(int strength) {
+        this.strength = strength;
+    }
+
+    public String encode(String rawPassword) {
+        MessageDigest messageDigest = getMessageDigest();
+
+        String encodedPassword = null;
+
+        try {
+            byte[] digest = messageDigest.digest(rawPassword.getBytes("UTF-8"));
+            encodedPassword = Base64.encodeBytes(digest);
+        } catch (UnsupportedEncodingException e) {
+            throw new RuntimeException("Credential could not be encoded");
+        }
+
+        return encodedPassword;
+    }
+
+    public boolean verify(String rawPassword, String encodedPassword) {
+        return encode(rawPassword).equals(encodedPassword);
+    }
+
+    protected final MessageDigest getMessageDigest() throws IllegalArgumentException {
+        String algorithm = "SHA-" + this.strength;
+
+        try {
+            return MessageDigest.getInstance(algorithm);
+        } catch (NoSuchAlgorithmException e) {
+            throw new RuntimeException("invalid credential encoding algorithm");
+        }
+    }
+
+    public int getStrength() {
+        return this.strength;
+    }
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/StripSecretsUtils.java b/server-spi-private/src/main/java/org/keycloak/models/utils/StripSecretsUtils.java
new file mode 100644
index 0000000..26f5adc
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/models/utils/StripSecretsUtils.java
@@ -0,0 +1,73 @@
+/*
+ * 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.models.utils;
+
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.provider.ProviderConfigProperty;
+import org.keycloak.representations.idm.ComponentRepresentation;
+import org.keycloak.representations.idm.IdentityProviderRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class StripSecretsUtils {
+
+    public static ComponentRepresentation strip(KeycloakSession session, ComponentRepresentation rep) {
+        Map<String, ProviderConfigProperty> configProperties = ComponentUtil.getComponentConfigProperties(session, rep);
+        if (rep.getConfig() == null) {
+            return rep;
+        }
+
+        Iterator<Map.Entry<String, List<String>>> itr = rep.getConfig().entrySet().iterator();
+        while (itr.hasNext()) {
+            Map.Entry<String, List<String>> next = itr.next();
+            ProviderConfigProperty configProperty = configProperties.get(next.getKey());
+            if (configProperty != null) {
+                if (configProperty.isSecret()) {
+                    next.setValue(Collections.singletonList(ComponentRepresentation.SECRET_VALUE));
+                }
+            } else {
+                itr.remove();
+            }
+        }
+        return rep;
+    }
+
+    public static RealmRepresentation strip(RealmRepresentation rep) {
+        if (rep.getSmtpServer() != null && rep.getSmtpServer().containsKey("password")) {
+            rep.getSmtpServer().put("password", ComponentRepresentation.SECRET_VALUE);
+        }
+        return rep;
+    }
+
+    public static IdentityProviderRepresentation strip(IdentityProviderRepresentation rep) {
+        if (rep.getConfig() != null && rep.getConfig().containsKey("clientSecret")) {
+            rep.getConfig().put("clientSecret", ComponentRepresentation.SECRET_VALUE);
+        }
+        return rep;
+    }
+
+}
\ No newline at end of file
diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/TimeBasedOTP.java b/server-spi-private/src/main/java/org/keycloak/models/utils/TimeBasedOTP.java
new file mode 100755
index 0000000..d02bc55
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/models/utils/TimeBasedOTP.java
@@ -0,0 +1,123 @@
+/*
+ * 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.models.utils;
+
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.TimeZone;
+
+/**
+ * TOTP: Time-based One-time Password Algorithm Based on http://tools.ietf.org/html/draft-mraihi-totp-timebased-06
+ *
+ * @author anil saldhana
+ * @since Sep 20, 2010
+ */
+public class TimeBasedOTP extends HmacOTP {
+
+    public static final int DEFAULT_INTERVAL_SECONDS = 30;
+    public static final int DEFAULT_DELAY_WINDOW = 1;
+
+    private Clock clock;
+
+    public TimeBasedOTP() {
+        this(DEFAULT_ALGORITHM, DEFAULT_NUMBER_DIGITS, DEFAULT_INTERVAL_SECONDS, DEFAULT_DELAY_WINDOW);
+    }
+
+    /**
+     * @param algorithm the encryption algorithm
+     * @param numberDigits the number of digits for tokens
+     * @param timeIntervalInSeconds the number of seconds a token is valid
+     * @param lookAheadWindow the number of previous intervals that should be used to validate tokens.
+     */
+    public TimeBasedOTP(String algorithm, int numberDigits, int timeIntervalInSeconds, int lookAheadWindow) {
+        super(numberDigits, algorithm, lookAheadWindow);
+        this.clock = new Clock(timeIntervalInSeconds);
+    }
+
+    /**
+     * <p>Generates a token.</p>
+     *
+     * @param secretKey the secret key to derive the token from.
+     */
+    public String generateTOTP(String secretKey) {
+        long T = this.clock.getCurrentInterval();
+
+        String steps = Long.toHexString(T).toUpperCase();
+
+        // Just get a 16 digit string
+        while (steps.length() < 16)
+            steps = "0" + steps;
+
+        return generateOTP(secretKey, steps, this.numberDigits, this.algorithm);
+    }
+
+    /**
+     * <p>Validates a token using a secret key.</p>
+     *
+     * @param token  OTP string to validate
+     * @param secret Shared secret
+     * @return
+     */
+    public boolean validateTOTP(String token, byte[] secret) {
+        long currentInterval = this.clock.getCurrentInterval();
+
+        for (int i = this.lookAheadWindow; i >= 0; --i) {
+            String steps = Long.toHexString(currentInterval - i).toUpperCase();
+
+            // Just get a 16 digit string
+            while (steps.length() < 16)
+                steps = "0" + steps;
+
+            String candidate = generateOTP(new String(secret), steps, this.numberDigits, this.algorithm);
+
+            if (candidate.equals(token)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    public void setCalendar(Calendar calendar) {
+        this.clock.setCalendar(calendar);
+    }
+
+    private class Clock {
+
+        private final int interval;
+        private Calendar calendar;
+
+        public Clock(int interval) {
+            this.interval = interval;
+        }
+
+        public long getCurrentInterval() {
+            Calendar currentCalendar = this.calendar;
+
+            if (currentCalendar == null) {
+                currentCalendar = GregorianCalendar.getInstance(TimeZone.getTimeZone("UTC"));
+            }
+
+            return (currentCalendar.getTimeInMillis() / 1000) / this.interval;
+        }
+
+        public void setCalendar(Calendar calendar) {
+            this.calendar = calendar;
+        }
+    }
+}
\ No newline at end of file
diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/UserModelDelegate.java b/server-spi-private/src/main/java/org/keycloak/models/utils/UserModelDelegate.java
new file mode 100755
index 0000000..a08e18a
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/models/utils/UserModelDelegate.java
@@ -0,0 +1,245 @@
+/*
+ * 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.models.utils;
+
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.GroupModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserModel;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class UserModelDelegate implements UserModel {
+    protected UserModel delegate;
+
+    public UserModelDelegate(UserModel delegate) {
+        this.delegate = delegate;
+    }
+
+    @Override
+    public String getId() {
+        return delegate.getId();
+    }
+
+    @Override
+    public String getUsername() {
+        return delegate.getUsername();
+    }
+
+    @Override
+    public void setUsername(String username) {
+        delegate.setUsername(username);
+    }
+
+    @Override
+    public boolean isEnabled() {
+        return delegate.isEnabled();
+    }
+
+    @Override
+    public void setEnabled(boolean enabled) {
+        delegate.setEnabled(enabled);
+    }
+
+    @Override
+    public void setSingleAttribute(String name, String value) {
+        delegate.setSingleAttribute(name, value);
+    }
+
+    @Override
+    public void setAttribute(String name, List<String> values) {
+        delegate.setAttribute(name, values);
+    }
+
+    @Override
+    public void removeAttribute(String name) {
+        delegate.removeAttribute(name);
+    }
+
+    @Override
+    public String getFirstAttribute(String name) {
+        return delegate.getFirstAttribute(name);
+    }
+
+    @Override
+    public List<String> getAttribute(String name) {
+        return delegate.getAttribute(name);
+    }
+
+    @Override
+    public Map<String, List<String>> getAttributes() {
+        return delegate.getAttributes();
+    }
+
+    @Override
+    public Set<String> getRequiredActions() {
+        return delegate.getRequiredActions();
+    }
+
+    @Override
+    public void addRequiredAction(String action) {
+        delegate.addRequiredAction(action);
+    }
+
+    @Override
+    public void removeRequiredAction(String action) {
+        delegate.removeRequiredAction(action);
+    }
+
+    @Override
+    public void addRequiredAction(RequiredAction action) {
+        delegate.addRequiredAction(action);
+    }
+
+    @Override
+    public void removeRequiredAction(RequiredAction action) {
+        delegate.removeRequiredAction(action);
+    }
+
+    @Override
+    public String getFirstName() {
+        return delegate.getFirstName();
+    }
+
+    @Override
+    public void setFirstName(String firstName) {
+        delegate.setFirstName(firstName);
+    }
+
+    @Override
+    public String getLastName() {
+        return delegate.getLastName();
+    }
+
+    @Override
+    public void setLastName(String lastName) {
+        delegate.setLastName(lastName);
+    }
+
+    @Override
+    public String getEmail() {
+        return delegate.getEmail();
+    }
+
+    @Override
+    public void setEmail(String email) {
+        delegate.setEmail(email);
+    }
+
+    @Override
+    public boolean isEmailVerified() {
+        return delegate.isEmailVerified();
+    }
+
+    @Override
+    public void setEmailVerified(boolean verified) {
+        delegate.setEmailVerified(verified);
+    }
+
+    @Override
+    public Set<RoleModel> getRealmRoleMappings() {
+        return delegate.getRealmRoleMappings();
+    }
+
+    @Override
+    public Set<RoleModel> getClientRoleMappings(ClientModel app) {
+        return delegate.getClientRoleMappings(app);
+    }
+
+    @Override
+    public boolean hasRole(RoleModel role) {
+        return delegate.hasRole(role);
+    }
+
+    @Override
+    public void grantRole(RoleModel role) {
+        delegate.grantRole(role);
+    }
+
+    @Override
+    public Set<RoleModel> getRoleMappings() {
+        return delegate.getRoleMappings();
+    }
+
+    @Override
+    public void deleteRoleMapping(RoleModel role) {
+        delegate.deleteRoleMapping(role);
+    }
+
+    @Override
+    public String getFederationLink() {
+        return delegate.getFederationLink();
+    }
+
+    @Override
+    public void setFederationLink(String link) {
+        delegate.setFederationLink(link);
+    }
+
+    @Override
+    public String getServiceAccountClientLink() {
+        return delegate.getServiceAccountClientLink();
+    }
+
+    @Override
+    public void setServiceAccountClientLink(String clientInternalId) {
+        delegate.setServiceAccountClientLink(clientInternalId);
+    }
+
+    public UserModel getDelegate() {
+        return delegate;
+    }
+    
+    @Override
+    public Long getCreatedTimestamp(){
+        return delegate.getCreatedTimestamp();
+    }
+    
+    @Override
+    public void setCreatedTimestamp(Long timestamp){
+        delegate.setCreatedTimestamp(timestamp);
+    }
+
+    @Override
+    public Set<GroupModel> getGroups() {
+        return delegate.getGroups();
+    }
+
+    @Override
+    public void joinGroup(GroupModel group) {
+        delegate.joinGroup(group);
+
+    }
+
+    @Override
+    public void leaveGroup(GroupModel group) {
+        delegate.leaveGroup(group);
+
+    }
+
+    @Override
+    public boolean isMemberOf(GroupModel group) {
+        return delegate.isMemberOf(group);
+    }
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/policy/DefaultPasswordPolicyManagerProvider.java b/server-spi-private/src/main/java/org/keycloak/policy/DefaultPasswordPolicyManagerProvider.java
new file mode 100644
index 0000000..b1bfc0c
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/policy/DefaultPasswordPolicyManagerProvider.java
@@ -0,0 +1,80 @@
+/*
+ * 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.policy;
+
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.PasswordPolicy;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class DefaultPasswordPolicyManagerProvider implements PasswordPolicyManagerProvider {
+
+    private KeycloakSession session;
+
+    public DefaultPasswordPolicyManagerProvider(KeycloakSession session) {
+        this.session = session;
+    }
+
+    @Override
+    public PolicyError validate(RealmModel realm, UserModel user, String password) {
+        for (PasswordPolicyProvider p : getProviders(realm, session)) {
+            PolicyError policyError = p.validate(realm, user, password);
+            if (policyError != null) {
+                return policyError;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public PolicyError validate(String user, String password) {
+        for (PasswordPolicyProvider p : getProviders(session)) {
+            PolicyError policyError = p.validate(user, password);
+            if (policyError != null) {
+                return policyError;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public void close() {
+    }
+
+    private List<PasswordPolicyProvider> getProviders(KeycloakSession session) {
+        return getProviders(session.getContext().getRealm(), session);
+
+    }
+
+    private List<PasswordPolicyProvider> getProviders(RealmModel realm, KeycloakSession session) {
+        LinkedList<PasswordPolicyProvider> list = new LinkedList<>();
+        PasswordPolicy policy = realm.getPasswordPolicy();
+        for (String id : policy.getPolicies()) {
+            PasswordPolicyProvider provider = session.getProvider(PasswordPolicyProvider.class, id);
+            list.add(provider);
+        }
+        return list;
+    }
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/policy/DefaultPasswordPolicyManagerProviderFactory.java b/server-spi-private/src/main/java/org/keycloak/policy/DefaultPasswordPolicyManagerProviderFactory.java
new file mode 100644
index 0000000..b8aabd4
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/policy/DefaultPasswordPolicyManagerProviderFactory.java
@@ -0,0 +1,51 @@
+/*
+ * 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.policy;
+
+import org.keycloak.Config;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class DefaultPasswordPolicyManagerProviderFactory implements PasswordPolicyManagerProviderFactory {
+
+    @Override
+    public PasswordPolicyManagerProvider create(KeycloakSession session) {
+        return new DefaultPasswordPolicyManagerProvider(session);
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+    }
+
+    @Override
+    public void close() {
+    }
+
+    @Override
+    public String getId() {
+        return "default";
+    }
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/policy/DigitsPasswordPolicyProvider.java b/server-spi-private/src/main/java/org/keycloak/policy/DigitsPasswordPolicyProvider.java
new file mode 100644
index 0000000..391317e
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/policy/DigitsPasswordPolicyProvider.java
@@ -0,0 +1,63 @@
+/*
+ * 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.policy;
+
+import org.keycloak.models.KeycloakContext;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class DigitsPasswordPolicyProvider implements PasswordPolicyProvider {
+
+    private static final String ERROR_MESSAGE = "invalidPasswordMinDigitsMessage";
+
+    private KeycloakContext context;
+
+    public DigitsPasswordPolicyProvider(KeycloakContext context) {
+        this.context = context;
+    }
+
+    @Override
+    public PolicyError validate(String username, String password) {
+        int min = context.getRealm().getPasswordPolicy().getPolicyConfig(DigitsPasswordPolicyProviderFactory.ID);
+        int count = 0;
+        for (char c : password.toCharArray()) {
+            if (Character.isDigit(c)) {
+                count++;
+            }
+        }
+        return count < min ? new PolicyError(ERROR_MESSAGE, min) : null;
+    }
+
+    @Override
+    public PolicyError validate(RealmModel realm, UserModel user, String password) {
+        return validate(user.getUsername(), password);
+    }
+
+    @Override
+    public Object parseConfig(String value) {
+        return value != null ? Integer.parseInt(value) : 1;
+    }
+
+    @Override
+    public void close() {
+    }
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/policy/DigitsPasswordPolicyProviderFactory.java b/server-spi-private/src/main/java/org/keycloak/policy/DigitsPasswordPolicyProviderFactory.java
new file mode 100644
index 0000000..d7fce9c
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/policy/DigitsPasswordPolicyProviderFactory.java
@@ -0,0 +1,73 @@
+/*
+ * 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.policy;
+
+import org.keycloak.Config;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class DigitsPasswordPolicyProviderFactory implements PasswordPolicyProviderFactory {
+
+    static final String ID = "digits";
+
+    @Override
+    public String getId() {
+        return ID;
+    }
+
+    @Override
+    public PasswordPolicyProvider create(KeycloakSession session) {
+        return new DigitsPasswordPolicyProvider(session.getContext());
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+    }
+
+    @Override
+    public String getDisplayName() {
+        return "Digits";
+    }
+
+    @Override
+    public String getConfigType() {
+        return PasswordPolicyProvider.INT_CONFIG_TYPE;
+    }
+
+    @Override
+    public String getDefaultConfigValue() {
+        return "1";
+    }
+
+    @Override
+    public boolean isMultiplSupported() {
+        return false;
+    }
+
+    @Override
+    public void close() {
+    }
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/policy/ForceExpiredPasswordPolicyProviderFactory.java b/server-spi-private/src/main/java/org/keycloak/policy/ForceExpiredPasswordPolicyProviderFactory.java
new file mode 100644
index 0000000..b9f6f4c
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/policy/ForceExpiredPasswordPolicyProviderFactory.java
@@ -0,0 +1,91 @@
+/*
+ * 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.policy;
+
+import org.keycloak.Config;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.PasswordPolicy;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class ForceExpiredPasswordPolicyProviderFactory implements PasswordPolicyProviderFactory, PasswordPolicyProvider {
+
+    public static final int DEFAULT_VALUE = 365;
+
+    @Override
+    public PasswordPolicyProvider create(KeycloakSession session) {
+        return this;
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+    }
+
+    @Override
+    public void close() {
+    }
+
+    @Override
+    public String getId() {
+        return PasswordPolicy.FORCE_EXPIRED_ID;
+    }
+
+    @Override
+    public PolicyError validate(RealmModel realm, UserModel user, String password) {
+        return null;
+    }
+
+    @Override
+    public PolicyError validate(String user, String password) {
+        return null;
+    }
+
+    @Override
+    public String getDisplayName() {
+        return "Expire Password";
+    }
+
+    @Override
+    public String getConfigType() {
+        return PasswordPolicyProvider.STRING_CONFIG_TYPE;
+    }
+
+    @Override
+    public String getDefaultConfigValue() {
+        return String.valueOf(DEFAULT_VALUE);
+    }
+
+    @Override
+    public boolean isMultiplSupported() {
+        return false;
+    }
+
+    @Override
+    public Object parseConfig(String value) {
+        return value != null ? Integer.parseInt(value) : DEFAULT_VALUE;
+    }
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/policy/HashAlgorithmPasswordPolicyProviderFactory.java b/server-spi-private/src/main/java/org/keycloak/policy/HashAlgorithmPasswordPolicyProviderFactory.java
new file mode 100644
index 0000000..303ba79
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/policy/HashAlgorithmPasswordPolicyProviderFactory.java
@@ -0,0 +1,89 @@
+/*
+ * 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.policy;
+
+import org.keycloak.Config;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.PasswordPolicy;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class HashAlgorithmPasswordPolicyProviderFactory implements PasswordPolicyProviderFactory, PasswordPolicyProvider {
+
+    @Override
+    public PasswordPolicyProvider create(KeycloakSession session) {
+        return this;
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+    }
+
+    @Override
+    public void close() {
+    }
+
+    @Override
+    public String getId() {
+        return PasswordPolicy.HASH_ALGORITHM_ID;
+    }
+
+    @Override
+    public PolicyError validate(RealmModel realm, UserModel user, String password) {
+        return null;
+    }
+
+    @Override
+    public PolicyError validate(String user, String password) {
+        return null;
+    }
+
+    @Override
+    public String getDisplayName() {
+        return "Hashing Algorithm";
+    }
+
+    @Override
+    public String getConfigType() {
+        return PasswordPolicyProvider.STRING_CONFIG_TYPE;
+    }
+
+    @Override
+    public String getDefaultConfigValue() {
+        return PasswordPolicy.HASH_ALGORITHM_DEFAULT;
+    }
+
+    @Override
+    public boolean isMultiplSupported() {
+        return false;
+    }
+
+    @Override
+    public Object parseConfig(String value) {
+        return value != null ? value : PasswordPolicy.HASH_ALGORITHM_DEFAULT;
+    }
+
+}
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
new file mode 100644
index 0000000..695ab28
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/policy/HashIterationsPasswordPolicyProviderFactory.java
@@ -0,0 +1,90 @@
+/*
+ * 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.policy;
+
+import org.keycloak.Config;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.PasswordPolicy;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class HashIterationsPasswordPolicyProviderFactory implements PasswordPolicyProvider, PasswordPolicyProviderFactory {
+
+
+    @Override
+    public PasswordPolicyProvider create(KeycloakSession session) {
+        return this;
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+    }
+
+    @Override
+    public String getId() {
+        return PasswordPolicy.HASH_ITERATIONS_ID;
+    }
+
+    @Override
+    public PolicyError validate(RealmModel realm, UserModel user, String password) {
+        return null;
+    }
+
+    @Override
+    public PolicyError validate(String user, String password) {
+        return null;
+    }
+
+    @Override
+    public Object parseConfig(String value) {
+        return value != null ? Integer.parseInt(value) : PasswordPolicy.HASH_ITERATIONS_DEFAULT;
+    }
+
+    @Override
+    public String getDisplayName() {
+        return "Hashing Iterations";
+    }
+
+    @Override
+    public String getConfigType() {
+        return PasswordPolicyProvider.INT_CONFIG_TYPE;
+    }
+
+    @Override
+    public String getDefaultConfigValue() {
+        return String.valueOf(PasswordPolicy.HASH_ITERATIONS_DEFAULT);
+    }
+
+    @Override
+    public boolean isMultiplSupported() {
+        return false;
+    }
+
+    @Override
+    public void close() {
+    }
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/policy/HistoryPasswordPolicyProvider.java b/server-spi-private/src/main/java/org/keycloak/policy/HistoryPasswordPolicyProvider.java
new file mode 100644
index 0000000..004d540
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/policy/HistoryPasswordPolicyProvider.java
@@ -0,0 +1,83 @@
+/*
+ * 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.policy;
+
+import org.jboss.logging.Logger;
+import org.keycloak.credential.CredentialModel;
+import org.keycloak.credential.hash.PasswordHashProvider;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.PasswordPolicy;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
+
+import java.util.List;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class HistoryPasswordPolicyProvider implements PasswordPolicyProvider {
+
+    private static final Logger logger = Logger.getLogger(HistoryPasswordPolicyProvider.class);
+    private static final String ERROR_MESSAGE = "invalidPasswordHistoryMessage";
+
+    private KeycloakSession session;
+
+    public HistoryPasswordPolicyProvider(KeycloakSession session) {
+        this.session = session;
+    }
+
+    @Override
+    public PolicyError validate(String username, String password) {
+        return null;
+    }
+
+    @Override
+    public PolicyError validate(RealmModel realm, UserModel user, String password) {
+        PasswordPolicy policy = session.getContext().getRealm().getPasswordPolicy();
+        int passwordHistoryPolicyValue = policy.getPolicyConfig(PasswordPolicy.PASSWORD_HISTORY_ID);
+        if (passwordHistoryPolicyValue != -1) {
+            List<CredentialModel> storedPasswords = session.userCredentialManager().getStoredCredentialsByType(realm, user, CredentialModel.PASSWORD);
+            for (CredentialModel cred : storedPasswords) {
+                PasswordHashProvider hash = session.getProvider(PasswordHashProvider.class, cred.getAlgorithm());
+                if (hash == null) continue;
+                if (hash.verify(password, cred)) {
+                    return new PolicyError(ERROR_MESSAGE, passwordHistoryPolicyValue);
+                }
+            }
+            List<CredentialModel> passwordHistory = session.userCredentialManager().getStoredCredentialsByType(realm, user, CredentialModel.PASSWORD_HISTORY);
+            for (CredentialModel cred : passwordHistory) {
+                PasswordHashProvider hash = session.getProvider(PasswordHashProvider.class, cred.getAlgorithm());
+                if (hash.verify(password, cred)) {
+                    return new PolicyError(ERROR_MESSAGE, passwordHistoryPolicyValue);
+                }
+
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public Object parseConfig(String value) {
+        return value != null ? Integer.parseInt(value) : HistoryPasswordPolicyProviderFactory.DEFAULT_VALUE;
+    }
+
+    @Override
+    public void close() {
+    }
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/policy/HistoryPasswordPolicyProviderFactory.java b/server-spi-private/src/main/java/org/keycloak/policy/HistoryPasswordPolicyProviderFactory.java
new file mode 100644
index 0000000..5f8a9d1
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/policy/HistoryPasswordPolicyProviderFactory.java
@@ -0,0 +1,74 @@
+/*
+ * 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.policy;
+
+import org.keycloak.Config;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.PasswordPolicy;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class HistoryPasswordPolicyProviderFactory implements PasswordPolicyProviderFactory {
+
+    public static final Integer DEFAULT_VALUE = 3;
+
+    @Override
+    public String getId() {
+        return PasswordPolicy.PASSWORD_HISTORY_ID;
+    }
+
+    @Override
+    public PasswordPolicyProvider create(KeycloakSession session) {
+        return new HistoryPasswordPolicyProvider(session);
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+    }
+
+    @Override
+    public String getDisplayName() {
+        return "Not Recently Used";
+    }
+
+    @Override
+    public String getConfigType() {
+        return PasswordPolicyProvider.INT_CONFIG_TYPE;
+    }
+
+    @Override
+    public String getDefaultConfigValue() {
+        return String.valueOf(HistoryPasswordPolicyProviderFactory.DEFAULT_VALUE);
+    }
+
+    @Override
+    public boolean isMultiplSupported() {
+        return false;
+    }
+
+    @Override
+    public void close() {
+    }
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/policy/LengthPasswordPolicyProvider.java b/server-spi-private/src/main/java/org/keycloak/policy/LengthPasswordPolicyProvider.java
new file mode 100644
index 0000000..5ba71fe
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/policy/LengthPasswordPolicyProvider.java
@@ -0,0 +1,57 @@
+/*
+ * 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.policy;
+
+import org.keycloak.models.KeycloakContext;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class LengthPasswordPolicyProvider implements PasswordPolicyProvider {
+
+    private static final String ERROR_MESSAGE = "invalidPasswordMinLengthMessage";
+
+    private KeycloakContext context;
+
+    public LengthPasswordPolicyProvider(KeycloakContext context) {
+        this.context = context;
+    }
+
+    @Override
+    public PolicyError validate(String username, String password) {
+        int min = context.getRealm().getPasswordPolicy().getPolicyConfig(LengthPasswordPolicyProviderFactory.ID);
+        return password.length() < min ? new PolicyError(ERROR_MESSAGE, min) : null;
+    }
+
+    @Override
+    public PolicyError validate(RealmModel realm, UserModel user, String password) {
+        return validate(user.getUsername(), password);
+    }
+
+    @Override
+    public Object parseConfig(String value) {
+        return value != null ? Integer.parseInt(value) : 8;
+    }
+
+    @Override
+    public void close() {
+    }
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/policy/LengthPasswordPolicyProviderFactory.java b/server-spi-private/src/main/java/org/keycloak/policy/LengthPasswordPolicyProviderFactory.java
new file mode 100644
index 0000000..a60c250
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/policy/LengthPasswordPolicyProviderFactory.java
@@ -0,0 +1,73 @@
+/*
+ * 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.policy;
+
+import org.keycloak.Config;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class LengthPasswordPolicyProviderFactory implements PasswordPolicyProviderFactory {
+
+    static final String ID = "length";
+
+    @Override
+    public String getId() {
+        return ID;
+    }
+
+    @Override
+    public PasswordPolicyProvider create(KeycloakSession session) {
+        return new LengthPasswordPolicyProvider(session.getContext());
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+    }
+
+    @Override
+    public String getDisplayName() {
+        return "Minimum Length";
+    }
+
+    @Override
+    public String getConfigType() {
+        return PasswordPolicyProvider.INT_CONFIG_TYPE;
+    }
+
+    @Override
+    public String getDefaultConfigValue() {
+        return "8";
+    }
+
+    @Override
+    public boolean isMultiplSupported() {
+        return false;
+    }
+
+    @Override
+    public void close() {
+    }
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/policy/LowerCasePasswordPolicyProvider.java b/server-spi-private/src/main/java/org/keycloak/policy/LowerCasePasswordPolicyProvider.java
new file mode 100644
index 0000000..f080d00
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/policy/LowerCasePasswordPolicyProvider.java
@@ -0,0 +1,63 @@
+/*
+ * 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.policy;
+
+import org.keycloak.models.KeycloakContext;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class LowerCasePasswordPolicyProvider implements PasswordPolicyProvider {
+
+    private static final String ERROR_MESSAGE = "invalidPasswordMinLowerCaseCharsMessage";
+
+    private KeycloakContext context;
+
+    public LowerCasePasswordPolicyProvider(KeycloakContext context) {
+        this.context = context;
+    }
+
+    @Override
+    public PolicyError validate(String username, String password) {
+        int min = context.getRealm().getPasswordPolicy().getPolicyConfig(LowerCasePasswordPolicyProviderFactory.ID);
+        int count = 0;
+        for (char c : password.toCharArray()) {
+            if (Character.isLowerCase(c)) {
+                count++;
+            }
+        }
+        return count < min ? new PolicyError(ERROR_MESSAGE, min) : null;
+    }
+
+    @Override
+    public PolicyError validate(RealmModel realm, UserModel user, String password) {
+        return validate(user.getUsername(), password);
+    }
+
+    @Override
+    public Object parseConfig(String value) {
+        return value != null ? Integer.parseInt(value) : 1;
+    }
+
+    @Override
+    public void close() {
+    }
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/policy/LowerCasePasswordPolicyProviderFactory.java b/server-spi-private/src/main/java/org/keycloak/policy/LowerCasePasswordPolicyProviderFactory.java
new file mode 100644
index 0000000..7e96dcf
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/policy/LowerCasePasswordPolicyProviderFactory.java
@@ -0,0 +1,73 @@
+/*
+ * 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.policy;
+
+import org.keycloak.Config;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class LowerCasePasswordPolicyProviderFactory implements PasswordPolicyProviderFactory {
+
+    public static final String ID = "lowerCase";
+
+    @Override
+    public PasswordPolicyProvider create(KeycloakSession session) {
+        return new LowerCasePasswordPolicyProvider(session.getContext());
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+    }
+
+    @Override
+    public String getDisplayName() {
+        return "Lowercase Characters";
+    }
+
+    @Override
+    public String getConfigType() {
+        return PasswordPolicyProvider.INT_CONFIG_TYPE;
+    }
+
+    @Override
+    public String getDefaultConfigValue() {
+        return "1";
+    }
+
+    @Override
+    public void close() {
+    }
+
+    @Override
+    public boolean isMultiplSupported() {
+        return false;
+    }
+
+    @Override
+    public String getId() {
+        return ID;
+    }
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/policy/NotUsernamePasswordPolicyProvider.java b/server-spi-private/src/main/java/org/keycloak/policy/NotUsernamePasswordPolicyProvider.java
new file mode 100644
index 0000000..f08edab
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/policy/NotUsernamePasswordPolicyProvider.java
@@ -0,0 +1,59 @@
+/*
+ * 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.policy;
+
+import org.keycloak.models.KeycloakContext;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class NotUsernamePasswordPolicyProvider implements PasswordPolicyProvider {
+
+    private static final String ERROR_MESSAGE = "invalidPasswordNotUsernameMessage";
+
+    private KeycloakContext context;
+
+    public NotUsernamePasswordPolicyProvider(KeycloakContext context) {
+        this.context = context;
+    }
+
+    @Override
+    public PolicyError validate(String username, String password) {
+        if (username == null) {
+            return null;
+        }
+        return username.equals(password) ? new PolicyError(ERROR_MESSAGE) : null;
+    }
+
+    @Override
+    public PolicyError validate(RealmModel realm, UserModel user, String password) {
+        return validate(user.getUsername(), password);
+    }
+
+    @Override
+    public Object parseConfig(String value) {
+        return null;
+    }
+
+    @Override
+    public void close() {
+    }
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/policy/NotUsernamePasswordPolicyProviderFactory.java b/server-spi-private/src/main/java/org/keycloak/policy/NotUsernamePasswordPolicyProviderFactory.java
new file mode 100644
index 0000000..30ebbff
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/policy/NotUsernamePasswordPolicyProviderFactory.java
@@ -0,0 +1,73 @@
+/*
+ * 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.policy;
+
+import org.keycloak.Config;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class NotUsernamePasswordPolicyProviderFactory implements PasswordPolicyProviderFactory {
+
+    static final String ID = "notUsername";
+
+    @Override
+    public String getId() {
+        return ID;
+    }
+
+    @Override
+    public PasswordPolicyProvider create(KeycloakSession session) {
+        return new NotUsernamePasswordPolicyProvider(session.getContext());
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+    }
+
+    @Override
+    public String getDisplayName() {
+        return "Not Username";
+    }
+
+    @Override
+    public String getConfigType() {
+        return null;
+    }
+
+    @Override
+    public String getDefaultConfigValue() {
+        return null;
+    }
+
+    @Override
+    public boolean isMultiplSupported() {
+        return false;
+    }
+
+    @Override
+    public void close() {
+    }
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/policy/PasswordPolicyManagerProvider.java b/server-spi-private/src/main/java/org/keycloak/policy/PasswordPolicyManagerProvider.java
new file mode 100644
index 0000000..e5e8497
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/policy/PasswordPolicyManagerProvider.java
@@ -0,0 +1,32 @@
+/*
+ * 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.policy;
+
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.provider.Provider;
+
+/**
+ * @author <a href="mailto:roelof.naude@epiuse.com">Roelof Naude</a>
+ */
+public interface PasswordPolicyManagerProvider extends Provider {
+
+    PolicyError validate(RealmModel realm, UserModel user, String password);
+    PolicyError validate(String user, String password);
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/policy/PasswordPolicyManagerProviderFactory.java b/server-spi-private/src/main/java/org/keycloak/policy/PasswordPolicyManagerProviderFactory.java
new file mode 100644
index 0000000..f68701e
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/policy/PasswordPolicyManagerProviderFactory.java
@@ -0,0 +1,27 @@
+/*
+ * 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.policy;
+
+import org.keycloak.provider.ProviderFactory;
+
+/**
+ * @author <a href="mailto:roelof.naude@epiuse.com">Roelof Naude</a>
+ */
+public interface PasswordPolicyManagerProviderFactory extends ProviderFactory<PasswordPolicyManagerProvider> {
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/policy/PasswordPolicyManagerSpi.java b/server-spi-private/src/main/java/org/keycloak/policy/PasswordPolicyManagerSpi.java
new file mode 100644
index 0000000..266cf1f
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/policy/PasswordPolicyManagerSpi.java
@@ -0,0 +1,49 @@
+/*
+ * 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.policy;
+
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.provider.Spi;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class PasswordPolicyManagerSpi implements Spi {
+
+    @Override
+    public boolean isInternal() {
+        return true;
+    }
+
+    @Override
+    public String getName() {
+        return "password-policy-manager";
+    }
+
+    @Override
+    public Class<? extends Provider> getProviderClass() {
+        return PasswordPolicyManagerProvider.class;
+    }
+
+    @Override
+    public Class<? extends ProviderFactory> getProviderFactoryClass() {
+        return PasswordPolicyManagerProviderFactory.class;
+    }
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/policy/PasswordPolicyProviderFactory.java b/server-spi-private/src/main/java/org/keycloak/policy/PasswordPolicyProviderFactory.java
new file mode 100644
index 0000000..44714e3
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/policy/PasswordPolicyProviderFactory.java
@@ -0,0 +1,32 @@
+/*
+ * 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.policy;
+
+import org.keycloak.provider.ProviderFactory;
+
+/**
+ * @author <a href="mailto:roelof.naude@epiuse.com">Roelof Naude</a>
+ */
+public interface PasswordPolicyProviderFactory extends ProviderFactory<PasswordPolicyProvider> {
+
+    String getDisplayName();
+    String getConfigType();
+    String getDefaultConfigValue();
+    boolean isMultiplSupported();
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/policy/PasswordPolicySpi.java b/server-spi-private/src/main/java/org/keycloak/policy/PasswordPolicySpi.java
new file mode 100644
index 0000000..97ad19a
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/policy/PasswordPolicySpi.java
@@ -0,0 +1,48 @@
+/*
+ * 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.policy;
+
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.provider.Spi;
+
+/**
+ * @author <a href="mailto:roelof.naude@epiuse.com">Roelof Naude</a>
+ */
+public class PasswordPolicySpi implements Spi {
+
+    @Override
+    public boolean isInternal() {
+        return false;
+    }
+
+    @Override
+    public String getName() {
+        return "password-policy";
+    }
+
+    @Override
+    public Class<? extends Provider> getProviderClass() {
+        return PasswordPolicyProvider.class;
+    }
+
+    @Override
+    public Class<? extends ProviderFactory> getProviderFactoryClass() {
+        return PasswordPolicyProviderFactory.class;
+    }
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/policy/RegexPatternsPasswordPolicyProvider.java b/server-spi-private/src/main/java/org/keycloak/policy/RegexPatternsPasswordPolicyProvider.java
new file mode 100644
index 0000000..52c83b8
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/policy/RegexPatternsPasswordPolicyProvider.java
@@ -0,0 +1,67 @@
+/*
+ * 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.policy;
+
+import org.keycloak.models.KeycloakContext;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class RegexPatternsPasswordPolicyProvider implements PasswordPolicyProvider {
+
+    private static final String ERROR_MESSAGE = "invalidPasswordRegexPatternMessage";
+
+    private KeycloakContext context;
+
+    public RegexPatternsPasswordPolicyProvider(KeycloakContext context) {
+        this.context = context;
+    }
+
+    @Override
+    public PolicyError validate(String username, String password) {
+        Pattern pattern = context.getRealm().getPasswordPolicy().getPolicyConfig(RegexPatternsPasswordPolicyProviderFactory.ID);
+        Matcher matcher = pattern.matcher(password);
+        if (!matcher.matches()) {
+            return new PolicyError(ERROR_MESSAGE, pattern.pattern());
+        }
+        return null;
+    }
+
+    @Override
+    public PolicyError validate(RealmModel realm, UserModel user, String password) {
+        return validate(user.getUsername(), password);
+    }
+
+    @Override
+    public Object parseConfig(String value) {
+        if (value == null) {
+            throw new IllegalArgumentException("Config required");
+        }
+        return Pattern.compile(value);
+    }
+
+    @Override
+    public void close() {
+    }
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/policy/RegexPatternsPasswordPolicyProviderFactory.java b/server-spi-private/src/main/java/org/keycloak/policy/RegexPatternsPasswordPolicyProviderFactory.java
new file mode 100644
index 0000000..c0ce732
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/policy/RegexPatternsPasswordPolicyProviderFactory.java
@@ -0,0 +1,73 @@
+/*
+ * 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.policy;
+
+import org.keycloak.Config;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class RegexPatternsPasswordPolicyProviderFactory implements PasswordPolicyProviderFactory {
+
+    static final String ID = "regexPattern";
+
+    @Override
+    public String getId() {
+        return ID;
+    }
+
+    @Override
+    public PasswordPolicyProvider create(KeycloakSession session) {
+        return new RegexPatternsPasswordPolicyProvider(session.getContext());
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+    }
+
+    @Override
+    public String getDisplayName() {
+        return "Regular Expression";
+    }
+
+    @Override
+    public String getConfigType() {
+        return PasswordPolicyProvider.STRING_CONFIG_TYPE;
+    }
+
+    @Override
+    public String getDefaultConfigValue() {
+        return "";
+    }
+
+    @Override
+    public boolean isMultiplSupported() {
+        return true;
+    }
+
+    @Override
+    public void close() {
+    }
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/policy/SpecialCharsPasswordPolicyProvider.java b/server-spi-private/src/main/java/org/keycloak/policy/SpecialCharsPasswordPolicyProvider.java
new file mode 100644
index 0000000..fa85137
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/policy/SpecialCharsPasswordPolicyProvider.java
@@ -0,0 +1,63 @@
+/*
+ * 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.policy;
+
+import org.keycloak.models.KeycloakContext;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class SpecialCharsPasswordPolicyProvider implements PasswordPolicyProvider {
+
+    private static final String ERROR_MESSAGE = "invalidPasswordMinSpecialCharsMessage";
+
+    private KeycloakContext context;
+
+    public SpecialCharsPasswordPolicyProvider(KeycloakContext context) {
+        this.context = context;
+    }
+
+    @Override
+    public PolicyError validate(String username, String password) {
+        int min = context.getRealm().getPasswordPolicy().getPolicyConfig(SpecialCharsPasswordPolicyProviderFactory.ID);
+        int count = 0;
+        for (char c : password.toCharArray()) {
+            if (!Character.isLetterOrDigit(c)) {
+                count++;
+            }
+        }
+        return count < min ? new PolicyError(ERROR_MESSAGE, min) : null;
+    }
+
+    @Override
+    public PolicyError validate(RealmModel realm, UserModel user, String password) {
+        return validate(user.getUsername(), password);
+    }
+
+    @Override
+    public Object parseConfig(String value) {
+        return value != null ? Integer.parseInt(value) : 1;
+    }
+
+    @Override
+    public void close() {
+    }
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/policy/SpecialCharsPasswordPolicyProviderFactory.java b/server-spi-private/src/main/java/org/keycloak/policy/SpecialCharsPasswordPolicyProviderFactory.java
new file mode 100644
index 0000000..908cbee
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/policy/SpecialCharsPasswordPolicyProviderFactory.java
@@ -0,0 +1,73 @@
+/*
+ * 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.policy;
+
+import org.keycloak.Config;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class SpecialCharsPasswordPolicyProviderFactory implements PasswordPolicyProviderFactory {
+
+    public static final String ID = "specialChars";
+
+    @Override
+    public PasswordPolicyProvider create(KeycloakSession session) {
+        return new SpecialCharsPasswordPolicyProvider(session.getContext());
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+    }
+
+    @Override
+    public void close() {
+    }
+
+    @Override
+    public String getDisplayName() {
+        return "Special Characters";
+    }
+
+    @Override
+    public String getConfigType() {
+        return PasswordPolicyProvider.INT_CONFIG_TYPE;
+    }
+
+    @Override
+    public String getDefaultConfigValue() {
+        return "1";
+    }
+
+    @Override
+    public boolean isMultiplSupported() {
+        return false;
+    }
+
+    @Override
+    public String getId() {
+        return ID;
+    }
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/policy/UpperCasePasswordPolicyProvider.java b/server-spi-private/src/main/java/org/keycloak/policy/UpperCasePasswordPolicyProvider.java
new file mode 100644
index 0000000..16ac1ef
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/policy/UpperCasePasswordPolicyProvider.java
@@ -0,0 +1,63 @@
+/*
+ * 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.policy;
+
+import org.keycloak.models.KeycloakContext;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class UpperCasePasswordPolicyProvider implements PasswordPolicyProvider {
+
+    private static final String ERROR_MESSAGE = "invalidPasswordMinUpperCaseCharsMessage";
+
+    private KeycloakContext context;
+
+    public UpperCasePasswordPolicyProvider(KeycloakContext context) {
+        this.context = context;
+    }
+
+    @Override
+    public PolicyError validate(String username, String password) {
+        int min = context.getRealm().getPasswordPolicy().getPolicyConfig(UpperCasePasswordPolicyProviderFactory.ID);
+        int count = 0;
+        for (char c : password.toCharArray()) {
+            if (Character.isUpperCase(c)) {
+                count++;
+            }
+        }
+        return count < min ? new PolicyError(ERROR_MESSAGE, min) : null;
+    }
+
+    @Override
+    public PolicyError validate(RealmModel realm, UserModel user, String password) {
+        return validate(user.getUsername(), password);
+    }
+
+    @Override
+    public Object parseConfig(String value) {
+        return value != null ? Integer.parseInt(value) : 1;
+    }
+
+    @Override
+    public void close() {
+    }
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/policy/UpperCasePasswordPolicyProviderFactory.java b/server-spi-private/src/main/java/org/keycloak/policy/UpperCasePasswordPolicyProviderFactory.java
new file mode 100644
index 0000000..8dce247
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/policy/UpperCasePasswordPolicyProviderFactory.java
@@ -0,0 +1,73 @@
+/*
+ * 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.policy;
+
+import org.keycloak.Config;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class UpperCasePasswordPolicyProviderFactory implements PasswordPolicyProviderFactory {
+
+    public static final String ID = "upperCase";
+
+    @Override
+    public PasswordPolicyProvider create(KeycloakSession session) {
+        return new UpperCasePasswordPolicyProvider(session.getContext());
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+    }
+
+    @Override
+    public void close() {
+    }
+
+    @Override
+    public String getDisplayName() {
+        return "Uppercase Characters";
+    }
+
+    @Override
+    public String getConfigType() {
+        return PasswordPolicyProvider.INT_CONFIG_TYPE;
+    }
+
+    @Override
+    public String getDefaultConfigValue() {
+        return "1";
+    }
+
+    @Override
+    public boolean isMultiplSupported() {
+        return false;
+    }
+
+    @Override
+    public String getId() {
+        return ID;
+    }
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/protocol/AbstractLoginProtocolFactory.java b/server-spi-private/src/main/java/org/keycloak/protocol/AbstractLoginProtocolFactory.java
new file mode 100755
index 0000000..4d39f8a
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/protocol/AbstractLoginProtocolFactory.java
@@ -0,0 +1,56 @@
+/*
+ * 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.protocol;
+
+import org.keycloak.Config;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.RealmModel;
+import org.keycloak.provider.ProviderEvent;
+import org.keycloak.provider.ProviderEventListener;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public abstract class AbstractLoginProtocolFactory implements LoginProtocolFactory {
+
+    @Override
+    public void init(Config.Scope config) {
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+        factory.register(new ProviderEventListener() {
+            @Override
+            public void onEvent(ProviderEvent event) {
+                if (event instanceof RealmModel.ClientCreationEvent) {
+                    ClientModel client = ((RealmModel.ClientCreationEvent)event).getCreatedClient();
+                    addDefaults(client);
+                }
+            }
+        });
+    }
+
+    protected abstract void addDefaults(ClientModel realm);
+
+    @Override
+    public void close() {
+
+    }
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/protocol/ClientInstallationProvider.java b/server-spi-private/src/main/java/org/keycloak/protocol/ClientInstallationProvider.java
new file mode 100755
index 0000000..0c55c4f
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/protocol/ClientInstallationProvider.java
@@ -0,0 +1,44 @@
+/*
+ * 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.protocol;
+
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderFactory;
+
+import javax.ws.rs.core.Response;
+import java.net.URI;
+
+/**
+ * Provides a template/sample client config adapter file.  For example keycloak.json for our OIDC adapter.  keycloak-saml.xml for our SAML client adapter
+ *
+ *
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface ClientInstallationProvider extends Provider, ProviderFactory<ClientInstallationProvider> {
+    Response generateInstallation(KeycloakSession session, RealmModel realm, ClientModel client, URI serverBaseUri);
+    String getProtocol();
+    String getDisplayType();
+    String getHelpText();
+    String getFilename();
+    String getMediaType();
+    boolean isDownloadOnly();
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/protocol/ClientInstallationSpi.java b/server-spi-private/src/main/java/org/keycloak/protocol/ClientInstallationSpi.java
new file mode 100755
index 0000000..abd86ff
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/protocol/ClientInstallationSpi.java
@@ -0,0 +1,49 @@
+/*
+ * 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.protocol;
+
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.provider.Spi;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class ClientInstallationSpi implements Spi {
+
+    @Override
+    public boolean isInternal() {
+        return true;
+    }
+
+    @Override
+    public String getName() {
+        return "client-installation";
+    }
+
+    @Override
+    public Class<? extends Provider> getProviderClass() {
+        return ClientInstallationProvider.class;
+    }
+
+    @Override
+    public Class<? extends ProviderFactory> getProviderFactoryClass() {
+        return ClientInstallationProvider.class;
+    }
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/protocol/LoginProtocol.java b/server-spi-private/src/main/java/org/keycloak/protocol/LoginProtocol.java
new file mode 100755
index 0000000..086a8ed
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/protocol/LoginProtocol.java
@@ -0,0 +1,84 @@
+/*
+ * 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.protocol;
+
+import org.keycloak.events.EventBuilder;
+import org.keycloak.models.ClientSessionModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserSessionModel;
+import org.keycloak.provider.Provider;
+import org.keycloak.services.managers.ClientSessionCode;
+
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface LoginProtocol extends Provider {
+
+    public static enum Error {
+
+        /**
+         * Login cancelled by the user
+         */
+        CANCELLED_BY_USER,
+        /**
+         * Consent denied by the user
+         */
+        CONSENT_DENIED,
+        /**
+         * Passive authentication mode requested but nobody is logged in
+         */
+        PASSIVE_LOGIN_REQUIRED,
+        /**
+         * Passive authentication mode requested, user is logged in, but some other user interaction is necessary (eg. some required login actions exist or Consent approval is necessary for logged in
+         * user)
+         */
+        PASSIVE_INTERACTION_REQUIRED;
+    }
+
+    LoginProtocol setSession(KeycloakSession session);
+
+    LoginProtocol setRealm(RealmModel realm);
+
+    LoginProtocol setUriInfo(UriInfo uriInfo);
+
+    LoginProtocol setHttpHeaders(HttpHeaders headers);
+
+    LoginProtocol setEventBuilder(EventBuilder event);
+
+    Response authenticated(UserSessionModel userSession, ClientSessionCode accessCode);
+
+    Response sendError(ClientSessionModel clientSession, Error error);
+
+    void backchannelLogout(UserSessionModel userSession, ClientSessionModel clientSession);
+    Response frontchannelLogout(UserSessionModel userSession, ClientSessionModel clientSession);
+    Response finishLogout(UserSessionModel userSession);
+
+    /**
+     * @param userSession
+     * @param clientSession
+     * @return true if SSO cookie authentication can't be used. User will need to "actively" reauthenticate
+     */
+    boolean requireReauthentication(UserSessionModel userSession, ClientSessionModel clientSession);
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/protocol/LoginProtocolFactory.java b/server-spi-private/src/main/java/org/keycloak/protocol/LoginProtocolFactory.java
new file mode 100755
index 0000000..931a00d
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/protocol/LoginProtocolFactory.java
@@ -0,0 +1,66 @@
+/*
+ * 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.protocol;
+
+import org.keycloak.events.EventBuilder;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.ClientTemplateModel;
+import org.keycloak.models.ProtocolMapperModel;
+import org.keycloak.models.RealmModel;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.representations.idm.ClientTemplateRepresentation;
+
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface LoginProtocolFactory extends ProviderFactory<LoginProtocol> {
+    /**
+     * List of built in protocol mappers that can be used to apply to clients.
+     *
+     * @return
+     */
+    List<ProtocolMapperModel> getBuiltinMappers();
+
+    /**
+     * List of mappers, which are added to new clients by default
+     * @return
+     */
+    List<ProtocolMapperModel> getDefaultBuiltinMappers();
+
+    Object createProtocolEndpoint(RealmModel realm, EventBuilder event);
+
+    /**
+     * Setup default values for new clients. This expects that the representation has already set up the client
+     *
+     * @param rep
+     * @param newClient
+     */
+    void setupClientDefaults(ClientRepresentation rep, ClientModel newClient);
+
+    /**
+     * Setup default values for new templates.  This expects that the representation has already set up the template
+     *
+     * @param clientRep
+     * @param newClient
+     */
+    void setupTemplateDefaults(ClientTemplateRepresentation clientRep, ClientTemplateModel newClient);
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/protocol/LoginProtocolSpi.java b/server-spi-private/src/main/java/org/keycloak/protocol/LoginProtocolSpi.java
new file mode 100755
index 0000000..84133a7
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/protocol/LoginProtocolSpi.java
@@ -0,0 +1,49 @@
+/*
+ * 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.protocol;
+
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.provider.Spi;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class LoginProtocolSpi implements Spi {
+
+    @Override
+    public boolean isInternal() {
+        return true;
+    }
+
+    @Override
+    public String getName() {
+        return "login-protocol";
+    }
+
+    @Override
+    public Class<? extends Provider> getProviderClass() {
+        return LoginProtocol.class;
+    }
+
+    @Override
+    public Class<? extends ProviderFactory> getProviderFactoryClass() {
+        return LoginProtocolFactory.class;
+    }
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/protocol/oidc/TokenIntrospectionProvider.java b/server-spi-private/src/main/java/org/keycloak/protocol/oidc/TokenIntrospectionProvider.java
new file mode 100644
index 0000000..e30f5da
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/protocol/oidc/TokenIntrospectionProvider.java
@@ -0,0 +1,38 @@
+/*
+ *  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.protocol.oidc;
+
+import org.keycloak.provider.Provider;
+
+import javax.ws.rs.core.Response;
+
+/**
+ * Provides introspection for a determined OAuth2 token type.
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface TokenIntrospectionProvider extends Provider {
+
+    /**
+     * Introspect the <code>token</code>.
+     *
+     * @param token the token to introspect.
+     * @return the response with the information about the token
+     */
+    Response introspect(String token);
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/protocol/oidc/TokenIntrospectionProviderFactory.java b/server-spi-private/src/main/java/org/keycloak/protocol/oidc/TokenIntrospectionProviderFactory.java
new file mode 100644
index 0000000..48b7556
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/protocol/oidc/TokenIntrospectionProviderFactory.java
@@ -0,0 +1,28 @@
+/*
+ *  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.protocol.oidc;
+
+import org.keycloak.provider.ProviderFactory;
+
+/**
+ * A factory that creates {@link TokenIntrospectionProvider} instances.
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface TokenIntrospectionProviderFactory extends ProviderFactory<TokenIntrospectionProvider> {
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/protocol/oidc/TokenIntrospectionSpi.java b/server-spi-private/src/main/java/org/keycloak/protocol/oidc/TokenIntrospectionSpi.java
new file mode 100644
index 0000000..4eb6d39
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/protocol/oidc/TokenIntrospectionSpi.java
@@ -0,0 +1,49 @@
+/*
+ *  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.protocol.oidc;
+
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.provider.Spi;
+
+/**
+ * <p>A {@link Spi} to support additional tokens types to the OAuth2 Token Introspection Endpoint.
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class TokenIntrospectionSpi implements Spi {
+    @Override
+    public boolean isInternal() {
+        return true;
+    }
+
+    @Override
+    public String getName() {
+        return "oauth2-token-introspection";
+    }
+
+    @Override
+    public Class<? extends Provider> getProviderClass() {
+        return TokenIntrospectionProvider.class;
+    }
+
+    @Override
+    public Class<? extends ProviderFactory> getProviderFactoryClass() {
+        return TokenIntrospectionProviderFactory.class;
+    }
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/protocol/ProtocolMapper.java b/server-spi-private/src/main/java/org/keycloak/protocol/ProtocolMapper.java
new file mode 100755
index 0000000..8055fae
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/protocol/ProtocolMapper.java
@@ -0,0 +1,49 @@
+/*
+ * 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.protocol;
+
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.ProtocolMapperContainerModel;
+import org.keycloak.models.ProtocolMapperModel;
+import org.keycloak.models.RealmModel;
+import org.keycloak.provider.ConfiguredProvider;
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderFactory;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface ProtocolMapper extends Provider, ProviderFactory<ProtocolMapper>,ConfiguredProvider {
+    String getProtocol();
+    String getDisplayCategory();
+    String getDisplayType();
+
+    /**
+     * Called when instance of mapperModel is created/updated for this protocolMapper through admin endpoint
+     *
+     * @param session
+     * @param realm
+     * @param client client or clientTemplate
+     * @param mapperModel
+     * @throws ProtocolMapperConfigException if configuration provided in mapperModel is not valid
+     */
+    default void validateConfig(KeycloakSession session, RealmModel realm, ProtocolMapperContainerModel client, ProtocolMapperModel mapperModel) throws ProtocolMapperConfigException {
+    };
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/protocol/ProtocolMapperConfigException.java b/server-spi-private/src/main/java/org/keycloak/protocol/ProtocolMapperConfigException.java
new file mode 100644
index 0000000..3f1f676
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/protocol/ProtocolMapperConfigException.java
@@ -0,0 +1,69 @@
+/*
+ * 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.protocol;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class ProtocolMapperConfigException extends Exception {
+
+    private String messageKey;
+    private Object[] parameters;
+
+    public ProtocolMapperConfigException(String message) {
+        super(message);
+    }
+
+    public ProtocolMapperConfigException(String message, String messageKey) {
+        super(message);
+        this.messageKey = messageKey;
+    }
+
+    public ProtocolMapperConfigException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public ProtocolMapperConfigException(String message, String messageKey, Throwable cause) {
+        super(message, cause);
+        this.messageKey = messageKey;
+    }
+
+    public ProtocolMapperConfigException(String message, Object ... parameters) {
+        super(message);
+        this.parameters = parameters;
+    }
+
+    public ProtocolMapperConfigException(String messageKey, String message, Object ... parameters) {
+        super(message);
+        this.messageKey = messageKey;
+        this.parameters = parameters;
+    }
+
+    public String getMessageKey() {
+        return messageKey;
+    }
+
+    public Object[] getParameters() {
+        return parameters;
+    }
+
+    public void setParameters(Object[] parameters) {
+        this.parameters = parameters;
+    }
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/protocol/ProtocolMapperSpi.java b/server-spi-private/src/main/java/org/keycloak/protocol/ProtocolMapperSpi.java
new file mode 100755
index 0000000..5aa841c
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/protocol/ProtocolMapperSpi.java
@@ -0,0 +1,49 @@
+/*
+ * 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.protocol;
+
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.provider.Spi;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class ProtocolMapperSpi implements Spi {
+
+    @Override
+    public boolean isInternal() {
+        return true;
+    }
+
+    @Override
+    public String getName() {
+        return "protocol-mapper";
+    }
+
+    @Override
+    public Class<? extends Provider> getProviderClass() {
+        return ProtocolMapper.class;
+    }
+
+    @Override
+    public Class<? extends ProviderFactory> getProviderFactoryClass() {
+        return ProtocolMapper.class;
+    }
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/provider/ConfigurationValidationHelper.java b/server-spi-private/src/main/java/org/keycloak/provider/ConfigurationValidationHelper.java
new file mode 100644
index 0000000..047c1bd
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/provider/ConfigurationValidationHelper.java
@@ -0,0 +1,121 @@
+/*
+ * 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.provider;
+
+import org.keycloak.component.ComponentModel;
+import org.keycloak.component.ComponentValidationException;
+
+import java.util.List;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class ConfigurationValidationHelper {
+
+    private ComponentModel model;
+
+    private ConfigurationValidationHelper(ComponentModel model) {
+        this.model = model;
+    }
+
+    public static ConfigurationValidationHelper check(ComponentModel model) {
+        return new ConfigurationValidationHelper(model);
+    }
+
+    public ConfigurationValidationHelper checkInt(ProviderConfigProperty property, boolean required) throws ComponentValidationException {
+        return checkInt(property.getName(), property.getLabel(), required);
+    }
+
+    public ConfigurationValidationHelper checkInt(String key, String label, boolean required) throws ComponentValidationException {
+        checkSingle(key, label, required);
+
+        String val = model.getConfig().getFirst(key);
+        if (val != null) {
+            try {
+                Integer.parseInt(val);
+            } catch (NumberFormatException e) {
+                throw new ComponentValidationException("''{0}'' should be a number", label);
+            }
+        }
+
+        return this;
+    }
+
+    public ConfigurationValidationHelper checkLong(ProviderConfigProperty property, boolean required) throws ComponentValidationException {
+        return checkLong(property.getName(), property.getLabel(), required);
+    }
+
+    public ConfigurationValidationHelper checkLong(String key, String label, boolean required) throws ComponentValidationException {
+        checkSingle(key, label, required);
+
+        String val = model.getConfig().getFirst(key);
+        if (val != null) {
+            try {
+                Long.parseLong(val);
+            } catch (NumberFormatException e) {
+                throw new ComponentValidationException("''{0}'' should be a number", label);
+            }
+        }
+
+        return this;
+    }
+
+    public ConfigurationValidationHelper checkSingle(ProviderConfigProperty property, boolean required) throws ComponentValidationException {
+        return checkSingle(property.getName(), property.getLabel(), required);
+    }
+
+    public ConfigurationValidationHelper checkSingle(String key, String label, boolean required) throws ComponentValidationException {
+        if (model.getConfig().containsKey(key) && model.getConfig().get(key).size() > 1) {
+            throw new ComponentValidationException("''{0}'' should be a single entry", label);
+        }
+
+        if (required) {
+            checkRequired(key, label);
+        }
+
+        return this;
+    }
+
+    public ConfigurationValidationHelper checkRequired(ProviderConfigProperty property) throws ComponentValidationException {
+        return checkRequired(property.getName(), property.getLabel());
+    }
+
+    public ConfigurationValidationHelper checkRequired(String key, String label) throws ComponentValidationException {
+        List<String> values = model.getConfig().get(key);
+        if (values == null) {
+            throw new ComponentValidationException("''{0}'' is required", label);
+        }
+
+        return this;
+    }
+
+    public ConfigurationValidationHelper checkBoolean(ProviderConfigProperty property, boolean required) throws ComponentValidationException {
+        return checkBoolean(property.getName(), property.getLabel(), required);
+    }
+
+    public ConfigurationValidationHelper checkBoolean(String key, String label, boolean required) {
+        checkSingle(key, label, required);
+
+        String val = model.getConfig().getFirst(key);
+        if (val != null && !(val.equals("true") || val.equals("false"))) {
+            throw new ComponentValidationException("''{0}'' should be ''true'' or ''false''", label);
+        }
+
+        return this;
+    }
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/provider/EnvironmentDependentProviderFactory.java b/server-spi-private/src/main/java/org/keycloak/provider/EnvironmentDependentProviderFactory.java
new file mode 100644
index 0000000..b4e993a
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/provider/EnvironmentDependentProviderFactory.java
@@ -0,0 +1,33 @@
+/*
+ * 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.provider;
+
+/**
+ * Providers that are only supported in some environments can implement this interface to be able to determine if they
+ * should be available or not.
+ *
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public interface EnvironmentDependentProviderFactory {
+
+    /**
+     * @return <code>true</code> if the provider is supported and should be available, <code>false</code> otherwise
+     */
+    boolean isSupported();
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/provider/ProviderLoader.java b/server-spi-private/src/main/java/org/keycloak/provider/ProviderLoader.java
new file mode 100644
index 0000000..2d7a07a
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/provider/ProviderLoader.java
@@ -0,0 +1,42 @@
+/*
+ * 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.provider;
+
+import java.util.List;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public interface ProviderLoader {
+
+    /**
+     * Load the SPI definitions themselves.
+     *
+     * @return a list of Spi definition objects
+     */
+    List<Spi> loadSpis();
+
+    /**
+     * Load all provider factories of a specific SPI.
+     *
+     * @param spi the Spi definition
+     * @return a list of provider factories
+     */
+    List<ProviderFactory> load(Spi spi);
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/provider/ProviderLoaderFactory.java b/server-spi-private/src/main/java/org/keycloak/provider/ProviderLoaderFactory.java
new file mode 100644
index 0000000..85a5e17
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/provider/ProviderLoaderFactory.java
@@ -0,0 +1,29 @@
+/*
+ * 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.provider;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public interface ProviderLoaderFactory {
+
+    boolean supports(String type);
+
+    ProviderLoader create(ClassLoader baseClassLoader, String resource);
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/provider/ServerInfoAwareProviderFactory.java b/server-spi-private/src/main/java/org/keycloak/provider/ServerInfoAwareProviderFactory.java
new file mode 100644
index 0000000..a4e6718
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/provider/ServerInfoAwareProviderFactory.java
@@ -0,0 +1,37 @@
+/*
+ * 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.provider;
+
+import java.util.Map;
+
+/**
+ * Marker interface for {@link ProviderFactory} of Provider which wants to show some info on "Server Info" page in Admin console.
+ * 
+ * @author Vlastimil Elias (velias at redhat dot com)
+ */
+public interface ServerInfoAwareProviderFactory {
+
+    /**
+     * Return actual info about the provider. This info contains informations about providers configuration and operational conditions (eg. errors in connection to remote systems etc) which is
+     * shown on "Server Info" page then.
+     * 
+     * @return Map with keys describing value and relevant values itself
+     */
+    public Map<String, String> getOperationalInfo();
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/scripting/InvocableScriptAdapter.java b/server-spi-private/src/main/java/org/keycloak/scripting/InvocableScriptAdapter.java
new file mode 100644
index 0000000..c3859ab
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/scripting/InvocableScriptAdapter.java
@@ -0,0 +1,118 @@
+/*
+ * 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.scripting;
+
+import org.keycloak.models.ScriptModel;
+
+import javax.script.Invocable;
+import javax.script.ScriptEngine;
+import javax.script.ScriptException;
+
+/**
+ * Wraps a {@link ScriptModel} and makes it {@link Invocable}.
+ *
+ * @author <a href="mailto:thomas.darimont@gmail.com">Thomas Darimont</a>
+ */
+public class InvocableScriptAdapter implements Invocable {
+
+    /**
+     * Holds the {@ScriptModel}
+     */
+    private final ScriptModel scriptModel;
+
+    /**
+     * Holds the {@link ScriptEngine} instance initialized with the script code.
+     */
+    private final ScriptEngine scriptEngine;
+
+    /**
+     * Creates a new {@link InvocableScriptAdapter} instance.
+     *
+     * @param scriptModel  must not be {@literal null}
+     * @param scriptEngine must not be {@literal null}
+     */
+    public InvocableScriptAdapter(ScriptModel scriptModel, ScriptEngine scriptEngine) {
+
+        if (scriptModel == null) {
+            throw new IllegalArgumentException("scriptModel must not be null");
+        }
+
+        if (scriptEngine == null) {
+            throw new IllegalArgumentException("scriptEngine must not be null");
+        }
+
+        this.scriptModel = scriptModel;
+        this.scriptEngine = loadScriptIntoEngine(scriptModel, scriptEngine);
+    }
+
+    @Override
+    public Object invokeMethod(Object thiz, String name, Object... args) throws ScriptExecutionException {
+
+        try {
+            return getInvocableEngine().invokeMethod(thiz, name, args);
+        } catch (ScriptException | NoSuchMethodException e) {
+            throw new ScriptExecutionException(scriptModel, e);
+        }
+    }
+
+    @Override
+    public Object invokeFunction(String name, Object... args) throws ScriptExecutionException {
+        try {
+            return getInvocableEngine().invokeFunction(name, args);
+        } catch (ScriptException | NoSuchMethodException e) {
+            throw new ScriptExecutionException(scriptModel, e);
+        }
+    }
+
+    @Override
+    public <T> T getInterface(Class<T> clazz) {
+        return getInvocableEngine().getInterface(clazz);
+    }
+
+    @Override
+    public <T> T getInterface(Object thiz, Class<T> clazz) {
+        return getInvocableEngine().getInterface(thiz, clazz);
+    }
+
+    /**
+     * Returns {@literal true} if the {@link ScriptEngine} has a definition with the given {@code name}.
+     *
+     * @param name
+     * @return
+     */
+    public boolean isDefined(String name) {
+
+        Object candidate = scriptEngine.getContext().getAttribute(name);
+
+        return candidate != null;
+    }
+
+    private ScriptEngine loadScriptIntoEngine(ScriptModel script, ScriptEngine engine) {
+
+        try {
+            engine.eval(script.getCode());
+        } catch (ScriptException se) {
+            throw new ScriptExecutionException(script, se);
+        }
+
+        return engine;
+    }
+
+    private Invocable getInvocableEngine() {
+        return (Invocable) scriptEngine;
+    }
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/scripting/Script.java b/server-spi-private/src/main/java/org/keycloak/scripting/Script.java
new file mode 100644
index 0000000..ef86902
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/scripting/Script.java
@@ -0,0 +1,115 @@
+/*
+ * 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.scripting;
+
+import org.keycloak.models.ScriptModel;
+
+/**
+ * A {@link ScriptModel} which holds some meta-data.
+ *
+ * @author <a href="mailto:thomas.darimont@gmail.com">Thomas Darimont</a>
+ */
+public class Script implements ScriptModel {
+
+    private String id;
+
+    private String realmId;
+
+    private String name;
+
+    private String mimeType;
+
+    private String code;
+
+    private String description;
+
+    public Script(String id, String realmId, String name, String mimeType, String code, String description) {
+
+        this.id = id;
+        this.realmId = realmId;
+        this.name = name;
+        this.mimeType = mimeType;
+        this.code = code;
+        this.description = description;
+    }
+
+    @Override
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    @Override
+    public String getRealmId() {
+        return realmId;
+    }
+
+    public void setRealmId(String realmId) {
+        this.realmId = realmId;
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    @Override
+    public String getMimeType() {
+        return mimeType;
+    }
+
+    public void setMimeType(String mimeType) {
+        this.mimeType = mimeType;
+    }
+
+    @Override
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    @Override
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    @Override
+    public String toString() {
+        return "Script{" +
+                "id='" + id + '\'' +
+                ", realmId='" + realmId + '\'' +
+                ", name='" + name + '\'' +
+                ", type='" + mimeType + '\'' +
+                ", code='" + code + '\'' +
+                ", description='" + description + '\'' +
+                '}';
+    }
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/scripting/ScriptBindingsConfigurer.java b/server-spi-private/src/main/java/org/keycloak/scripting/ScriptBindingsConfigurer.java
new file mode 100644
index 0000000..9613eb6
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/scripting/ScriptBindingsConfigurer.java
@@ -0,0 +1,41 @@
+/*
+ * 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.scripting;
+
+import javax.script.Bindings;
+
+/**
+ * Callback interface for customization of {@link Bindings} for a {@link javax.script.ScriptEngine}.
+ * <p>Used by {@link ScriptingProvider}</p>
+ * @author <a href="mailto:thomas.darimont@gmail.com">Thomas Darimont</a>
+ */
+@FunctionalInterface
+public interface ScriptBindingsConfigurer {
+
+    /**
+     * A default {@link ScriptBindingsConfigurer} that provides no Bindings.
+     */
+    ScriptBindingsConfigurer EMPTY = new ScriptBindingsConfigurer() {
+
+        @Override
+        public void configureBindings(Bindings bindings) {
+            //NOOP
+        }
+    };
+
+    void configureBindings(Bindings bindings);
+}
\ No newline at end of file
diff --git a/server-spi-private/src/main/java/org/keycloak/scripting/ScriptExecutionException.java b/server-spi-private/src/main/java/org/keycloak/scripting/ScriptExecutionException.java
new file mode 100644
index 0000000..2063bd2
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/scripting/ScriptExecutionException.java
@@ -0,0 +1,33 @@
+/*
+ * 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.scripting;
+
+import org.keycloak.models.ScriptModel;
+
+import javax.script.ScriptException;
+
+/**
+ * Augments a {@link ScriptException} and adds additional metadata.
+ *
+ * @author <a href="mailto:thomas.darimont@gmail.com">Thomas Darimont</a>
+ */
+public class ScriptExecutionException extends RuntimeException {
+
+    public ScriptExecutionException(ScriptModel script, Exception ex) {
+        super("Could not execute script '" + script.getName() + "' problem was: " + ex.getMessage(), ex);
+    }
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/scripting/ScriptingProvider.java b/server-spi-private/src/main/java/org/keycloak/scripting/ScriptingProvider.java
new file mode 100644
index 0000000..67bad5a
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/scripting/ScriptingProvider.java
@@ -0,0 +1,51 @@
+/*
+ * 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.scripting;
+
+import org.keycloak.models.ScriptModel;
+import org.keycloak.provider.Provider;
+
+import javax.script.ScriptEngine;
+
+/**
+ * A {@link Provider} than provides Scripting capabilities.
+ *
+ * @author <a href="mailto:thomas.darimont@gmail.com">Thomas Darimont</a>
+ */
+public interface ScriptingProvider extends Provider {
+
+    /**
+     * Returns an {@link InvocableScriptAdapter} based on the given {@link ScriptModel}.
+     * <p>The {@code InvocableScriptAdapter} wraps a dedicated {@link ScriptEngine} that was populated with the provided {@link ScriptBindingsConfigurer}</p>
+     *
+     * @param scriptModel        the scriptModel to wrap
+     * @param bindingsConfigurer populates the {@link javax.script.Bindings}
+     * @return
+     */
+    InvocableScriptAdapter prepareInvocableScript(ScriptModel scriptModel, ScriptBindingsConfigurer bindingsConfigurer);
+
+    /**
+     * Creates a new {@link ScriptModel} instance.
+     *
+     * @param realmId
+     * @param scriptName
+     * @param scriptCode
+     * @param scriptDescription
+     * @return
+     */
+    ScriptModel createScript(String realmId, String mimeType, String scriptName, String scriptCode, String scriptDescription);
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/services/managers/BruteForceProtector.java b/server-spi-private/src/main/java/org/keycloak/services/managers/BruteForceProtector.java
new file mode 100755
index 0000000..e884b02
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/services/managers/BruteForceProtector.java
@@ -0,0 +1,34 @@
+/*
+ * 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.services.managers;
+
+import org.keycloak.common.ClientConnection;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.provider.Provider;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface BruteForceProtector extends Provider {
+    void failedLogin(RealmModel realm, UserModel user, ClientConnection clientConnection);
+
+    boolean isTemporarilyDisabled(KeycloakSession session, RealmModel realm, UserModel user);
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/services/managers/BruteForceProtectorFactory.java b/server-spi-private/src/main/java/org/keycloak/services/managers/BruteForceProtectorFactory.java
new file mode 100755
index 0000000..b76981f
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/services/managers/BruteForceProtectorFactory.java
@@ -0,0 +1,27 @@
+/*
+ * 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.services.managers;
+
+import org.keycloak.provider.ProviderFactory;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface BruteForceProtectorFactory extends ProviderFactory<BruteForceProtector> {
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/services/managers/BruteForceProtectorSpi.java b/server-spi-private/src/main/java/org/keycloak/services/managers/BruteForceProtectorSpi.java
new file mode 100755
index 0000000..0d3e24c
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/services/managers/BruteForceProtectorSpi.java
@@ -0,0 +1,49 @@
+/*
+ * 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.services.managers;
+
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.provider.Spi;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class BruteForceProtectorSpi implements Spi {
+
+    @Override
+    public boolean isInternal() {
+        return true;
+    }
+
+    @Override
+    public String getName() {
+        return "bruteForceProtector";
+    }
+
+    @Override
+    public Class<? extends Provider> getProviderClass() {
+        return BruteForceProtector.class;
+    }
+
+    @Override
+    public Class<? extends ProviderFactory> getProviderFactoryClass() {
+        return BruteForceProtectorFactory.class;
+    }
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/services/managers/ClientSessionCode.java b/server-spi-private/src/main/java/org/keycloak/services/managers/ClientSessionCode.java
new file mode 100755
index 0000000..2710174
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/services/managers/ClientSessionCode.java
@@ -0,0 +1,279 @@
+/*
+ * 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.services.managers;
+
+import org.jboss.logging.Logger;
+import org.keycloak.common.util.Base64Url;
+import org.keycloak.common.util.Time;
+import org.keycloak.jose.jws.Algorithm;
+import org.keycloak.jose.jws.crypto.RSAProvider;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.ClientSessionModel;
+import org.keycloak.models.ClientTemplateModel;
+import org.keycloak.models.KeyManager;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.ProtocolMapperModel;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.utils.KeycloakModelUtils;
+
+import java.security.PublicKey;
+import java.security.Signature;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ClientSessionCode {
+
+    private static final Logger logger = Logger.getLogger(ClientSessionCode.class);
+
+    private static final String NEXT_CODE = ClientSessionCode.class.getName() + ".nextCode";
+
+    private KeycloakSession session;
+    private final RealmModel realm;
+    private final ClientSessionModel clientSession;
+
+    public enum ActionType {
+        CLIENT,
+        LOGIN,
+        USER
+    }
+
+    public ClientSessionCode(KeycloakSession session, RealmModel realm, ClientSessionModel clientSession) {
+        this.session = session;
+        this.realm = realm;
+        this.clientSession = clientSession;
+    }
+
+    public static class ParseResult {
+        ClientSessionCode code;
+        boolean clientSessionNotFound;
+        boolean illegalHash;
+        ClientSessionModel clientSession;
+
+        public ClientSessionCode getCode() {
+            return code;
+        }
+
+        public boolean isClientSessionNotFound() {
+            return clientSessionNotFound;
+        }
+
+        public boolean isIllegalHash() {
+            return illegalHash;
+        }
+
+        public ClientSessionModel getClientSession() {
+            return clientSession;
+        }
+    }
+
+    public static ParseResult parseResult(String code, KeycloakSession session, RealmModel realm) {
+        ParseResult result = new ParseResult();
+        if (code == null) {
+            result.illegalHash = true;
+            return result;
+        }
+        try {
+            result.clientSession = getClientSession(code, session, realm);
+            if (result.clientSession == null) {
+                result.clientSessionNotFound = true;
+                return result;
+            }
+
+            if (!verifyCode(code, session, realm, result.clientSession)) {
+                result.illegalHash = true;
+                return result;
+            }
+
+            result.code = new ClientSessionCode(session, realm, result.clientSession);
+            return result;
+        } catch (RuntimeException e) {
+            result.illegalHash = true;
+            return result;
+        }
+    }
+
+    public static ClientSessionCode parse(String code, KeycloakSession session, RealmModel realm) {
+        try {
+            ClientSessionModel clientSession = getClientSession(code, session, realm);
+            if (clientSession == null) {
+                return null;
+            }
+
+            if (!verifyCode(code, session, realm, clientSession)) {
+                return null;
+            }
+
+            return new ClientSessionCode(session, realm, clientSession);
+        } catch (RuntimeException e) {
+            return null;
+        }
+    }
+
+    public static ClientSessionModel getClientSession(String code, KeycloakSession session, RealmModel realm) {
+        String[] parts = code.split("\\.");
+        String id = parts[1];
+        return session.sessions().getClientSession(realm, id);
+    }
+
+    public ClientSessionModel getClientSession() {
+        return clientSession;
+    }
+
+    public boolean isValid(String requestedAction, ActionType actionType) {
+        if (!isValidAction(requestedAction)) return false;
+        return isActionActive(actionType);
+    }
+
+    public boolean isActionActive(ActionType actionType) {
+        int timestamp = clientSession.getTimestamp();
+
+        int lifespan;
+        switch (actionType) {
+            case CLIENT:
+                lifespan = realm.getAccessCodeLifespan();
+                break;
+            case LOGIN:
+                lifespan = realm.getAccessCodeLifespanLogin() > 0 ? realm.getAccessCodeLifespanLogin() : realm.getAccessCodeLifespanUserAction();
+                break;
+            case USER:
+                lifespan = realm.getAccessCodeLifespanUserAction();
+                break;
+            default:
+                throw new IllegalArgumentException();
+        }
+
+        return timestamp + lifespan > Time.currentTime();
+    }
+
+    public boolean isValidAction(String requestedAction) {
+        String action = clientSession.getAction();
+        if (action == null) {
+            return false;
+        }
+        if (!action.equals(requestedAction)) {
+            return false;
+        }
+        return true;
+    }
+
+
+    public Set<RoleModel> getRequestedRoles() {
+        Set<RoleModel> requestedRoles = new HashSet<>();
+        for (String roleId : clientSession.getRoles()) {
+            RoleModel role = realm.getRoleById(roleId);
+            if (role != null) {
+                requestedRoles.add(role);
+            }
+        }
+        return requestedRoles;
+    }
+
+    public Set<ProtocolMapperModel> getRequestedProtocolMappers() {
+        Set<ProtocolMapperModel> requestedProtocolMappers = new HashSet<>();
+        Set<String> protocolMappers = clientSession.getProtocolMappers();
+        ClientModel client = clientSession.getClient();
+        ClientTemplateModel template = client.getClientTemplate();
+        if (protocolMappers != null) {
+            for (String protocolMapperId : protocolMappers) {
+                ProtocolMapperModel protocolMapper = client.getProtocolMapperById(protocolMapperId);
+                if (protocolMapper == null && template != null) {
+                    protocolMapper = template.getProtocolMapperById(protocolMapperId);
+                }
+                if (protocolMapper != null) {
+                    requestedProtocolMappers.add(protocolMapper);
+                }
+            }
+        }
+        return requestedProtocolMappers;
+    }
+
+    public void setAction(String action) {
+        clientSession.setAction(action);
+        clientSession.setTimestamp(Time.currentTime());
+    }
+
+    public String getCode() {
+        String nextCode = (String) session.getAttribute(NEXT_CODE + "." + clientSession.getId());
+        if (nextCode == null) {
+            nextCode = generateCode(session, realm, clientSession);
+            session.setAttribute(NEXT_CODE + "." + clientSession.getId(), nextCode);
+        } else {
+            logger.debug("Code already generated for session, using code from session attributes");
+        }
+        return nextCode;
+    }
+
+    private static String generateCode(KeycloakSession session, RealmModel realm, ClientSessionModel clientSession) {
+        try {
+            KeyManager.ActiveKey keys = session.keys().getActiveKey(realm);
+
+            String secret = KeycloakModelUtils.generateSecret();
+
+            StringBuilder sb = new StringBuilder();
+            sb.append(secret);
+            sb.append('.');
+            sb.append(clientSession.getId());
+
+            String code = sb.toString();
+
+            Signature signature = RSAProvider.getSignature(Algorithm.RS256);
+            signature.initSign(keys.getPrivateKey());
+            signature.update(code.getBytes("utf-8"));
+
+            sb = new StringBuilder();
+
+            sb.append(Base64Url.encode(signature.sign()));
+            sb.append('.');
+            sb.append(keys.getKid());
+
+            clientSession.setNote(ClientSessionModel.ACTION_SIGNATURE, sb.toString());
+
+            return code;
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private static boolean verifyCode(String code, KeycloakSession session, RealmModel realm, ClientSessionModel clientSession) {
+        try {
+            String note = clientSession.getNote(ClientSessionModel.ACTION_SIGNATURE);
+            if (note == null) {
+                logger.debug("Action signature not found in client session");
+                return false;
+            }
+
+            clientSession.removeNote(ClientSessionModel.ACTION_SIGNATURE);
+
+            String[] signed = note.split("\\.");
+
+            PublicKey publicKey = session.keys().getPublicKey(realm, signed[1]);
+
+            Signature verifier = RSAProvider.getSignature(Algorithm.RS256);
+            verifier.initVerify(publicKey);
+            verifier.update(code.getBytes("utf-8"));
+            return verifier.verify(Base64Url.decode(signed[0]));
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/services/resource/RealmResourceProvider.java b/server-spi-private/src/main/java/org/keycloak/services/resource/RealmResourceProvider.java
new file mode 100644
index 0000000..8f615c6
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/services/resource/RealmResourceProvider.java
@@ -0,0 +1,38 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual 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.services.resource;
+
+import org.keycloak.provider.Provider;
+
+/**
+ * <p>A {@link RealmResourceProvider} creates JAX-RS <emphasis>sub-resource</emphasis> instances for paths relative
+ * to Realm's RESTful API that could not be resolved by the server.
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface RealmResourceProvider extends Provider {
+
+    /**
+     * <p>Returns a JAX-RS resource instance.
+     *
+     * @return a JAX-RS sub-resource instance
+     */
+    Object getResource();
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/services/resource/RealmResourceProviderFactory.java b/server-spi-private/src/main/java/org/keycloak/services/resource/RealmResourceProviderFactory.java
new file mode 100644
index 0000000..b39bc12
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/services/resource/RealmResourceProviderFactory.java
@@ -0,0 +1,30 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual 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.services.resource;
+
+import org.keycloak.provider.ProviderFactory;
+
+/**
+ * <p>A factory that creates {@link RealmResourceProvider} instances.
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface RealmResourceProviderFactory extends ProviderFactory<RealmResourceProvider> {
+
+}
\ No newline at end of file
diff --git a/server-spi-private/src/main/java/org/keycloak/services/resource/RealmResourceSPI.java b/server-spi-private/src/main/java/org/keycloak/services/resource/RealmResourceSPI.java
new file mode 100644
index 0000000..04e8f6d
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/services/resource/RealmResourceSPI.java
@@ -0,0 +1,54 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual 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.services.resource;
+
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.provider.Spi;
+
+/**
+ * <p>A {@link Spi} to plug additional sub-resources to Realms' RESTful API.
+ *
+ * <p>Implementors can use this {@link Spi} to provide additional services to the mentioned API and extend Keycloak capabilities by
+ * creating JAX-RS sub-resources for paths not known by the server.
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class RealmResourceSPI implements Spi {
+
+    @Override
+    public boolean isInternal() {
+        return true;
+    }
+
+    @Override
+    public String getName() {
+        return "realm-restapi-extension";
+    }
+
+    @Override
+    public Class<? extends Provider> getProviderClass() {
+        return RealmResourceProvider.class;
+    }
+
+    @Override
+    public Class<? extends ProviderFactory> getProviderFactoryClass() {
+        return RealmResourceProviderFactory.class;
+    }
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/theme/Theme.java b/server-spi-private/src/main/java/org/keycloak/theme/Theme.java
new file mode 100755
index 0000000..283f4d7
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/theme/Theme.java
@@ -0,0 +1,72 @@
+/*
+ * 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.theme;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Locale;
+import java.util.Properties;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public interface Theme {
+
+    public enum Type { LOGIN, ACCOUNT, ADMIN, EMAIL, WELCOME, COMMON };
+
+    public String getName();
+
+    public String getParentName();
+
+    public String getImportName();
+
+    public Type getType();
+
+    public URL getTemplate(String name) throws IOException;
+
+    public InputStream getTemplateAsStream(String name) throws IOException;
+
+    public URL getResource(String path) throws IOException;
+
+    public InputStream getResourceAsStream(String path) throws IOException;
+
+    /**
+     * Same as getMessages(baseBundlename, locale), but uses a default baseBundlename
+     * such as "messages".
+     *
+     * @param locale The locale of the desired message bundle.
+     * @return The localized messages from the bundle.
+     * @throws IOException If bundle can not be read.
+     */
+    public Properties getMessages(Locale locale) throws IOException;
+
+    /**
+     * Retrieve localized messages from a message bundle.
+     *
+     * @param baseBundlename The base name of the bundle, such as "messages" in
+     * messages_en.properties.
+     * @param locale The locale of the desired message bundle.
+     * @return The localized messages from the bundle.
+     * @throws IOException If bundle can not be read.
+     */
+    public Properties getMessages(String baseBundlename, Locale locale) throws IOException;
+
+    public Properties getProperties() throws IOException;
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/theme/ThemeProvider.java b/server-spi-private/src/main/java/org/keycloak/theme/ThemeProvider.java
new file mode 100755
index 0000000..34de97b
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/theme/ThemeProvider.java
@@ -0,0 +1,38 @@
+/*
+ * 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.theme;
+
+import org.keycloak.provider.Provider;
+
+import java.io.IOException;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public interface ThemeProvider extends Provider {
+
+    public int getProviderPriority();
+
+    public Theme getTheme(String name, Theme.Type type) throws IOException;
+
+    public Set<String> nameSet(Theme.Type type);
+
+    public boolean hasTheme(String name, Theme.Type type);
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/theme/ThemeProviderFactory.java b/server-spi-private/src/main/java/org/keycloak/theme/ThemeProviderFactory.java
new file mode 100755
index 0000000..d28fea5
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/theme/ThemeProviderFactory.java
@@ -0,0 +1,26 @@
+/*
+ * 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.theme;
+
+import org.keycloak.provider.ProviderFactory;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public interface ThemeProviderFactory extends ProviderFactory<ThemeProvider> {
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/theme/ThemeSpi.java b/server-spi-private/src/main/java/org/keycloak/theme/ThemeSpi.java
new file mode 100755
index 0000000..b0f263c
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/theme/ThemeSpi.java
@@ -0,0 +1,48 @@
+/*
+ * 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.theme;
+
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.provider.Spi;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class ThemeSpi implements Spi {
+
+    @Override
+    public boolean isInternal() {
+        return true;
+    }
+
+    @Override
+    public String getName() {
+        return "theme";
+    }
+
+    @Override
+    public Class<? extends Provider> getProviderClass() {
+        return ThemeProvider.class;
+    }
+
+    @Override
+    public Class<? extends ProviderFactory> getProviderFactoryClass() {
+        return ThemeProviderFactory.class;
+    }
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/timer/ScheduledTask.java b/server-spi-private/src/main/java/org/keycloak/timer/ScheduledTask.java
new file mode 100644
index 0000000..ba092ac
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/timer/ScheduledTask.java
@@ -0,0 +1,29 @@
+/*
+ * 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.timer;
+
+import org.keycloak.models.KeycloakSession;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public interface ScheduledTask {
+
+    public void run(KeycloakSession session);
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/timer/TimerProvider.java b/server-spi-private/src/main/java/org/keycloak/timer/TimerProvider.java
new file mode 100644
index 0000000..5dbf69b
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/timer/TimerProvider.java
@@ -0,0 +1,33 @@
+/*
+ * 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.timer;
+
+import org.keycloak.provider.Provider;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public interface TimerProvider extends Provider {
+
+    public void schedule(Runnable runnable, long intervalMillis, String taskName);
+
+    public void scheduleTask(ScheduledTask scheduledTask, long intervalMillis, String taskName);
+
+    public void cancelTask(String taskName);
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/timer/TimerProviderFactory.java b/server-spi-private/src/main/java/org/keycloak/timer/TimerProviderFactory.java
new file mode 100644
index 0000000..a676242
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/timer/TimerProviderFactory.java
@@ -0,0 +1,26 @@
+/*
+ * 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.timer;
+
+import org.keycloak.provider.ProviderFactory;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public interface TimerProviderFactory extends ProviderFactory<TimerProvider> {
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/timer/TimerSpi.java b/server-spi-private/src/main/java/org/keycloak/timer/TimerSpi.java
new file mode 100644
index 0000000..b300a6b
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/timer/TimerSpi.java
@@ -0,0 +1,48 @@
+/*
+ * 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.timer;
+
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.provider.Spi;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class TimerSpi implements Spi {
+
+    @Override
+    public boolean isInternal() {
+        return true;
+    }
+
+    @Override
+    public String getName() {
+        return "timer";
+    }
+
+    @Override
+    public Class<? extends Provider> getProviderClass() {
+        return TimerProvider.class;
+    }
+
+    @Override
+    public Class<? extends ProviderFactory> getProviderFactoryClass() {
+        return TimerProviderFactory.class;
+    }
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/transaction/JtaTransactionManagerLookup.java b/server-spi-private/src/main/java/org/keycloak/transaction/JtaTransactionManagerLookup.java
new file mode 100644
index 0000000..ebcf52e
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/transaction/JtaTransactionManagerLookup.java
@@ -0,0 +1,43 @@
+/*
+ * 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.transaction;
+
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderFactory;
+
+import javax.transaction.TransactionManager;
+
+/**
+ * JTA TransactionManager lookup
+ *
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface JtaTransactionManagerLookup extends Provider, ProviderFactory<JtaTransactionManagerLookup> {
+    @Override
+    default void close() {
+
+    }
+
+    @Override
+    default JtaTransactionManagerLookup create(KeycloakSession session) {
+        return this;
+    }
+
+    TransactionManager getTransactionManager();
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/transaction/TransactionManagerLookupSpi.java b/server-spi-private/src/main/java/org/keycloak/transaction/TransactionManagerLookupSpi.java
new file mode 100755
index 0000000..f45d897
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/transaction/TransactionManagerLookupSpi.java
@@ -0,0 +1,49 @@
+/*
+ * 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.transaction;
+
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.provider.Spi;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class TransactionManagerLookupSpi implements Spi {
+
+    @Override
+    public boolean isInternal() {
+        return true;
+    }
+
+    @Override
+    public String getName() {
+        return "jta-lookup";
+    }
+
+    @Override
+    public Class<? extends Provider> getProviderClass() {
+        return JtaTransactionManagerLookup.class;
+    }
+
+    @Override
+    public Class<? extends ProviderFactory> getProviderFactoryClass() {
+        return JtaTransactionManagerLookup.class;
+    }
+
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/truststore/HostnameVerificationPolicy.java b/server-spi-private/src/main/java/org/keycloak/truststore/HostnameVerificationPolicy.java
new file mode 100755
index 0000000..4c4f069
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/truststore/HostnameVerificationPolicy.java
@@ -0,0 +1,36 @@
+/*
+ * 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.truststore;
+
+public enum HostnameVerificationPolicy {
+
+    /**
+     * Hostname verification is not done on the server's certificate
+     */
+    ANY,
+
+    /**
+     * Allows wildcards in subdomain names i.e. *.foo.com
+     */
+    WILDCARD,
+
+    /**
+     * CN must match hostname connecting to
+     */
+    STRICT
+}
\ No newline at end of file
diff --git a/server-spi-private/src/main/java/org/keycloak/truststore/TruststoreProvider.java b/server-spi-private/src/main/java/org/keycloak/truststore/TruststoreProvider.java
new file mode 100755
index 0000000..00b868a
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/truststore/TruststoreProvider.java
@@ -0,0 +1,32 @@
+/*
+ * 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.truststore;
+
+import org.keycloak.provider.Provider;
+
+import java.security.KeyStore;
+
+/**
+ * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
+ */
+public interface TruststoreProvider extends Provider {
+
+    HostnameVerificationPolicy getPolicy();
+
+    KeyStore getTruststore();
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/truststore/TruststoreProviderFactory.java b/server-spi-private/src/main/java/org/keycloak/truststore/TruststoreProviderFactory.java
new file mode 100755
index 0000000..83c79b2
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/truststore/TruststoreProviderFactory.java
@@ -0,0 +1,26 @@
+/*
+ * 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.truststore;
+
+import org.keycloak.provider.ProviderFactory;
+
+/**
+ * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
+ */
+public interface TruststoreProviderFactory extends ProviderFactory<TruststoreProvider> {
+}
diff --git a/server-spi-private/src/main/java/org/keycloak/truststore/TruststoreSpi.java b/server-spi-private/src/main/java/org/keycloak/truststore/TruststoreSpi.java
new file mode 100755
index 0000000..160ccba
--- /dev/null
+++ b/server-spi-private/src/main/java/org/keycloak/truststore/TruststoreSpi.java
@@ -0,0 +1,48 @@
+/*
+ * 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.truststore;
+
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.provider.Spi;
+
+/**
+ * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
+ */
+public class TruststoreSpi implements Spi {
+
+    @Override
+    public boolean isInternal() {
+        return true;
+    }
+
+    @Override
+    public String getName() {
+        return "truststore";
+    }
+
+    @Override
+    public Class<? extends Provider> getProviderClass() {
+        return TruststoreProvider.class;
+    }
+
+    @Override
+    public Class<? extends ProviderFactory> getProviderFactoryClass() {
+        return TruststoreProviderFactory.class;
+    }
+}
diff --git a/server-spi-private/src/main/resources/META-INF/services/org.keycloak.models.session.UserSessionPersisterProviderFactory b/server-spi-private/src/main/resources/META-INF/services/org.keycloak.models.session.UserSessionPersisterProviderFactory
new file mode 100644
index 0000000..3cf430c
--- /dev/null
+++ b/server-spi-private/src/main/resources/META-INF/services/org.keycloak.models.session.UserSessionPersisterProviderFactory
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+org.keycloak.models.session.DisabledUserSessionPersisterProvider
\ No newline at end of file
diff --git a/server-spi-private/src/main/resources/META-INF/services/org.keycloak.policy.PasswordPolicyManagerProviderFactory b/server-spi-private/src/main/resources/META-INF/services/org.keycloak.policy.PasswordPolicyManagerProviderFactory
new file mode 100644
index 0000000..128272d
--- /dev/null
+++ b/server-spi-private/src/main/resources/META-INF/services/org.keycloak.policy.PasswordPolicyManagerProviderFactory
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+org.keycloak.policy.DefaultPasswordPolicyManagerProviderFactory
\ No newline at end of file
diff --git a/server-spi-private/src/main/resources/META-INF/services/org.keycloak.policy.PasswordPolicyProviderFactory b/server-spi-private/src/main/resources/META-INF/services/org.keycloak.policy.PasswordPolicyProviderFactory
new file mode 100644
index 0000000..a436fe9
--- /dev/null
+++ b/server-spi-private/src/main/resources/META-INF/services/org.keycloak.policy.PasswordPolicyProviderFactory
@@ -0,0 +1,28 @@
+#
+# 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.
+#
+
+org.keycloak.policy.DigitsPasswordPolicyProviderFactory
+org.keycloak.policy.ForceExpiredPasswordPolicyProviderFactory
+org.keycloak.policy.HashAlgorithmPasswordPolicyProviderFactory
+org.keycloak.policy.HashIterationsPasswordPolicyProviderFactory
+org.keycloak.policy.HistoryPasswordPolicyProviderFactory
+org.keycloak.policy.LengthPasswordPolicyProviderFactory
+org.keycloak.policy.LowerCasePasswordPolicyProviderFactory
+org.keycloak.policy.NotUsernamePasswordPolicyProviderFactory
+org.keycloak.policy.RegexPatternsPasswordPolicyProviderFactory
+org.keycloak.policy.SpecialCharsPasswordPolicyProviderFactory
+org.keycloak.policy.UpperCasePasswordPolicyProviderFactory
diff --git a/server-spi-private/src/main/resources/META-INF/services/org.keycloak.provider.Spi b/server-spi-private/src/main/resources/META-INF/services/org.keycloak.provider.Spi
new file mode 100755
index 0000000..bbd588e
--- /dev/null
+++ b/server-spi-private/src/main/resources/META-INF/services/org.keycloak.provider.Spi
@@ -0,0 +1,68 @@
+#
+# 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.
+#
+
+org.keycloak.models.UserFederationSpi
+org.keycloak.storage.UserStorageProviderSpi
+org.keycloak.storage.federated.UserFederatedStorageProviderSpi
+org.keycloak.mappers.UserFederationMapperSpi
+org.keycloak.models.RealmSpi
+org.keycloak.models.UserSessionSpi
+org.keycloak.models.UserSpi
+org.keycloak.models.session.UserSessionPersisterSpi
+org.keycloak.models.dblock.DBLockSpi
+org.keycloak.migration.MigrationSpi
+org.keycloak.events.EventListenerSpi
+org.keycloak.events.EventStoreSpi
+org.keycloak.exportimport.ExportSpi
+org.keycloak.exportimport.ImportSpi
+org.keycloak.timer.TimerSpi
+org.keycloak.scripting.ScriptingSpi
+org.keycloak.services.managers.BruteForceProtectorSpi
+org.keycloak.services.resource.RealmResourceSPI
+org.keycloak.protocol.ClientInstallationSpi
+org.keycloak.protocol.LoginProtocolSpi
+org.keycloak.protocol.ProtocolMapperSpi
+org.keycloak.broker.provider.IdentityProviderSpi
+org.keycloak.broker.provider.IdentityProviderMapperSpi
+org.keycloak.broker.social.SocialProviderSpi
+org.keycloak.forms.account.AccountSpi
+org.keycloak.forms.login.LoginFormsSpi
+org.keycloak.email.EmailSenderSpi
+org.keycloak.email.EmailTemplateSpi
+org.keycloak.theme.ThemeSpi
+org.keycloak.truststore.TruststoreSpi
+org.keycloak.connections.httpclient.HttpClientSpi
+org.keycloak.models.cache.CacheRealmProviderSpi
+org.keycloak.models.cache.CacheUserProviderSpi
+org.keycloak.authentication.AuthenticatorSpi
+org.keycloak.authentication.ClientAuthenticatorSpi
+org.keycloak.authentication.RequiredActionSpi
+org.keycloak.authentication.FormAuthenticatorSpi
+org.keycloak.authentication.FormActionSpi
+org.keycloak.cluster.ClusterSpi
+org.keycloak.authorization.policy.provider.PolicySpi
+org.keycloak.authorization.store.StoreFactorySpi
+org.keycloak.authorization.AuthorizationSpi
+org.keycloak.models.cache.authorization.CachedStoreFactorySpi
+org.keycloak.protocol.oidc.TokenIntrospectionSpi
+org.keycloak.policy.PasswordPolicySpi
+org.keycloak.policy.PasswordPolicyManagerSpi
+org.keycloak.transaction.TransactionManagerLookupSpi
+org.keycloak.credential.hash.PasswordHashSpi
+org.keycloak.credential.CredentialSpi
+org.keycloak.keys.PublicKeyStorageSpi
+org.keycloak.keys.KeySpi
\ No newline at end of file
diff --git a/server-spi-private/src/test/java/org/keycloak/models/HmacTest.java b/server-spi-private/src/test/java/org/keycloak/models/HmacTest.java
new file mode 100755
index 0000000..45aaf16
--- /dev/null
+++ b/server-spi-private/src/test/java/org/keycloak/models/HmacTest.java
@@ -0,0 +1,40 @@
+/*
+ * 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.models;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.keycloak.models.utils.Base32;
+import org.keycloak.models.utils.HmacOTP;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class HmacTest {
+
+    @Test
+    public void testHmac() throws Exception {
+        HmacOTP hmacOTP = new HmacOTP(6, HmacOTP.HMAC_SHA1, 10);
+        String secret = "JNSVMMTEKZCUGSKJIVGHMNSQOZBDA5JT";
+        String decoded = new String(Base32.decode(secret));
+        System.out.println(hmacOTP.generateHOTP(decoded, 0));
+        System.out.println(hmacOTP.validateHOTP("550233", decoded, 0));
+        Assert.assertEquals(1, hmacOTP.validateHOTP("550233", decoded, 0));
+    }
+}

services/pom.xml 5(+5 -0)

diff --git a/services/pom.xml b/services/pom.xml
index dc33a3d..0fb68f7 100755
--- a/services/pom.xml
+++ b/services/pom.xml
@@ -64,6 +64,11 @@
             <scope>provided</scope>
         </dependency>
         <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-server-spi-private</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
             <groupId>org.jboss.spec.javax.servlet</groupId>
             <artifactId>jboss-servlet-api_3.0_spec</artifactId>
         </dependency>
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/browser/ConditionalOtpFormAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/browser/ConditionalOtpFormAuthenticator.java
index fdaa481..ef17476 100644
--- a/services/src/main/java/org/keycloak/authentication/authenticators/browser/ConditionalOtpFormAuthenticator.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/browser/ConditionalOtpFormAuthenticator.java
@@ -20,6 +20,7 @@ package org.keycloak.authentication.authenticators.browser;
 import org.keycloak.authentication.AuthenticationFlowContext;
 import org.keycloak.models.RoleModel;
 import org.keycloak.models.UserModel;
+import org.keycloak.models.utils.RoleUtils;
 
 import javax.ws.rs.core.MultivaluedMap;
 import java.util.List;
@@ -30,7 +31,6 @@ import static org.keycloak.authentication.authenticators.browser.ConditionalOtpF
 import static org.keycloak.authentication.authenticators.browser.ConditionalOtpFormAuthenticator.OtpDecision.SHOW_OTP;
 import static org.keycloak.authentication.authenticators.browser.ConditionalOtpFormAuthenticator.OtpDecision.SKIP_OTP;
 import static org.keycloak.models.utils.KeycloakModelUtils.getRoleFromString;
-import static org.keycloak.models.utils.KeycloakModelUtils.hasRole;
 
 /**
  * An {@link OTPFormAuthenticator} that can conditionally require OTP authentication.
@@ -264,6 +264,6 @@ public class ConditionalOtpFormAuthenticator extends OTPFormAuthenticator {
         RoleModel role = getRoleFromString(context.getRealm(), roleName);
         UserModel user = context.getUser();
 
-        return hasRole(user.getRoleMappings(), role);
+        return RoleUtils.hasRole(user.getRoleMappings(), role);
     }
 }
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/browser/ScriptBasedAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/browser/ScriptBasedAuthenticator.java
index 85a217f..9bff3f9 100644
--- a/services/src/main/java/org/keycloak/authentication/authenticators/browser/ScriptBasedAuthenticator.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/browser/ScriptBasedAuthenticator.java
@@ -142,7 +142,7 @@ public class ScriptBasedAuthenticator implements Authenticator {
 
         RealmModel realm = context.getRealm();
 
-        ScriptingProvider scripting = context.getSession().scripting();
+        ScriptingProvider scripting = context.getSession().getProvider(ScriptingProvider.class);
 
         //TODO lookup script by scriptId instead of creating it every time
         ScriptModel script = scripting.createScript(realm.getId(), ScriptModel.TEXT_JAVASCRIPT, scriptName, scriptCode, scriptDescription);
diff --git a/services/src/main/java/org/keycloak/credential/PasswordCredentialProvider.java b/services/src/main/java/org/keycloak/credential/PasswordCredentialProvider.java
index d0558ab..97a92ea 100644
--- a/services/src/main/java/org/keycloak/credential/PasswordCredentialProvider.java
+++ b/services/src/main/java/org/keycloak/credential/PasswordCredentialProvider.java
@@ -140,7 +140,7 @@ public class PasswordCredentialProvider implements CredentialProvider, Credentia
         PasswordHashProvider hash = session.getProvider(PasswordHashProvider.class, policy.getHashAlgorithm());
         if (hash == null) {
             logger.warnv("Realm PasswordPolicy PasswordHashProvider {0} not found", policy.getHashAlgorithm());
-            return session.getProvider(PasswordHashProvider.class, HashAlgorithmPasswordPolicyProviderFactory.DEFAULT_VALUE);
+            return session.getProvider(PasswordHashProvider.class, PasswordPolicy.HASH_ALGORITHM_DEFAULT);
         }
         return hash;
     }
diff --git a/services/src/main/java/org/keycloak/exportimport/util/ImportUtils.java b/services/src/main/java/org/keycloak/exportimport/util/ImportUtils.java
index 1ea4092..2357a65 100755
--- a/services/src/main/java/org/keycloak/exportimport/util/ImportUtils.java
+++ b/services/src/main/java/org/keycloak/exportimport/util/ImportUtils.java
@@ -108,7 +108,8 @@ public class ImportUtils {
             }
         }
 
-        RealmImporter realmManager = session.getContext().getRealmManager();
+        RealmManager realmManager = new RealmManager(session);
+        realmManager.setContextPath(session.getContext().getContextPath());
         realmManager.importRealm(rep);
 
         if (System.getProperty(ExportImportConfig.ACTION) != null) {
diff --git a/services/src/main/java/org/keycloak/keys/AbstractRsaKeyProvider.java b/services/src/main/java/org/keycloak/keys/AbstractRsaKeyProvider.java
index c5f09f1..f6bbaeb 100644
--- a/services/src/main/java/org/keycloak/keys/AbstractRsaKeyProvider.java
+++ b/services/src/main/java/org/keycloak/keys/AbstractRsaKeyProvider.java
@@ -23,7 +23,6 @@ import org.keycloak.models.RealmModel;
 import java.security.KeyPair;
 import java.security.PrivateKey;
 import java.security.PublicKey;
-import java.security.cert.Certificate;
 import java.security.cert.X509Certificate;
 import java.util.Collections;
 import java.util.List;
diff --git a/services/src/main/java/org/keycloak/partialimport/UsersPartialImport.java b/services/src/main/java/org/keycloak/partialimport/UsersPartialImport.java
index 0128e4e..cce0fec 100755
--- a/services/src/main/java/org/keycloak/partialimport/UsersPartialImport.java
+++ b/services/src/main/java/org/keycloak/partialimport/UsersPartialImport.java
@@ -24,7 +24,7 @@ import org.keycloak.models.utils.KeycloakModelUtils;
 import org.keycloak.models.utils.RepresentationToModel;
 import org.keycloak.representations.idm.PartialImportRepresentation;
 import org.keycloak.representations.idm.UserRepresentation;
-import org.keycloak.services.managers.UserManager;
+import org.keycloak.models.UserManager;
 
 import java.util.HashMap;
 import java.util.List;
diff --git a/services/src/main/java/org/keycloak/services/DefaultKeycloakContext.java b/services/src/main/java/org/keycloak/services/DefaultKeycloakContext.java
index 99f2559..07313d8 100755
--- a/services/src/main/java/org/keycloak/services/DefaultKeycloakContext.java
+++ b/services/src/main/java/org/keycloak/services/DefaultKeycloakContext.java
@@ -111,13 +111,6 @@ public class DefaultKeycloakContext implements KeycloakContext {
     }
 
     @Override
-    public RealmImporter getRealmManager() {
-        RealmManager manager = new RealmManager(session);
-        manager.setContextPath(getContextPath());
-        return manager;
-    }
-
-    @Override
     public Locale resolveLocale(UserModel user) {
         return LocaleHelper.getLocale(session, realm, user);
     }
diff --git a/services/src/main/java/org/keycloak/services/DefaultKeycloakSession.java b/services/src/main/java/org/keycloak/services/DefaultKeycloakSession.java
index 7fbd7a3..4cc77a2 100644
--- a/services/src/main/java/org/keycloak/services/DefaultKeycloakSession.java
+++ b/services/src/main/java/org/keycloak/services/DefaultKeycloakSession.java
@@ -59,7 +59,6 @@ public class DefaultKeycloakSession implements KeycloakSession {
     private UserProvider userModel;
     private UserStorageManager userStorageManager;
     private UserCredentialStoreManager userCredentialStorageManager;
-    private ScriptingProvider scriptingProvider;
     private UserSessionProvider sessionProvider;
     private UserFederationManager federationManager;
     private UserFederatedStorageProvider userFederatedStorageProvider;
@@ -275,14 +274,4 @@ public class DefaultKeycloakSession implements KeycloakSession {
             }
         }
     }
-
-    @Override
-    public ScriptingProvider scripting() {
-
-        if (scriptingProvider == null) {
-            scriptingProvider = getProvider(ScriptingProvider.class);
-        }
-
-        return scriptingProvider;
-    }
 }
diff --git a/services/src/main/java/org/keycloak/services/managers/ClientManager.java b/services/src/main/java/org/keycloak/services/managers/ClientManager.java
index b648bbd..eb6fba6 100644
--- a/services/src/main/java/org/keycloak/services/managers/ClientManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/ClientManager.java
@@ -27,6 +27,7 @@ import org.keycloak.models.ClientModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.ProtocolMapperModel;
 import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserManager;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.UserSessionProvider;
 import org.keycloak.models.session.UserSessionPersisterProvider;
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
index f9ae190..7a8964f 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
@@ -66,7 +66,7 @@ import org.keycloak.services.Urls;
 import org.keycloak.services.managers.AuthenticationManager;
 import org.keycloak.services.managers.BruteForceProtector;
 import org.keycloak.services.managers.ClientSessionCode;
-import org.keycloak.services.managers.UserManager;
+import org.keycloak.models.UserManager;
 import org.keycloak.services.managers.UserSessionManager;
 import org.keycloak.services.resources.AccountService;
 import org.keycloak.services.validation.Validation;
diff --git a/testsuite/integration/pom.xml b/testsuite/integration/pom.xml
index d1311b5..873d99d 100755
--- a/testsuite/integration/pom.xml
+++ b/testsuite/integration/pom.xml
@@ -120,7 +120,7 @@
         </dependency>
         <dependency>
             <groupId>org.keycloak</groupId>
-            <artifactId>keycloak-server-spi</artifactId>
+            <artifactId>keycloak-server-spi-private</artifactId>
         </dependency>
         <dependency>
             <groupId>org.keycloak</groupId>
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/FederatedStorageExportImportTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/FederatedStorageExportImportTest.java
index cafe113..6eccb21 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/FederatedStorageExportImportTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/FederatedStorageExportImportTest.java
@@ -79,7 +79,7 @@ public class FederatedStorageExportImportTest {
     protected PasswordHashProvider getHashProvider(KeycloakSession session, PasswordPolicy policy) {
         PasswordHashProvider hash = session.getProvider(PasswordHashProvider.class, policy.getHashAlgorithm());
         if (hash == null) {
-            return session.getProvider(PasswordHashProvider.class, HashAlgorithmPasswordPolicyProviderFactory.DEFAULT_VALUE);
+            return session.getProvider(PasswordHashProvider.class, PasswordPolicy.HASH_ALGORITHM_DEFAULT);
         }
         return hash;
     }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionInitializerTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionInitializerTest.java
index 431bff6..2db24ad 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionInitializerTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionInitializerTest.java
@@ -34,7 +34,7 @@ import org.keycloak.models.UserSessionModel;
 import org.keycloak.models.UserSessionProvider;
 import org.keycloak.models.UserSessionProviderFactory;
 import org.keycloak.protocol.oidc.OIDCLoginProtocol;
-import org.keycloak.services.managers.UserManager;
+import org.keycloak.models.UserManager;
 import org.keycloak.services.managers.UserSessionManager;
 import org.keycloak.testsuite.rule.KeycloakRule;
 
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionPersisterProviderTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionPersisterProviderTest.java
index 074438f..80f663f 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionPersisterProviderTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionPersisterProviderTest.java
@@ -33,7 +33,7 @@ import org.keycloak.models.session.UserSessionPersisterProvider;
 import org.keycloak.protocol.oidc.OIDCLoginProtocol;
 import org.keycloak.services.managers.ClientManager;
 import org.keycloak.services.managers.RealmManager;
-import org.keycloak.services.managers.UserManager;
+import org.keycloak.models.UserManager;
 import org.keycloak.testsuite.rule.KeycloakRule;
 
 import java.util.ArrayList;
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionProviderOfflineTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionProviderOfflineTest.java
index 013f16c..b9f4f2a 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionProviderOfflineTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionProviderOfflineTest.java
@@ -34,7 +34,7 @@ import org.keycloak.models.session.UserSessionPersisterProvider;
 import org.keycloak.protocol.oidc.OIDCLoginProtocol;
 import org.keycloak.services.managers.ClientManager;
 import org.keycloak.services.managers.RealmManager;
-import org.keycloak.services.managers.UserManager;
+import org.keycloak.models.UserManager;
 import org.keycloak.services.managers.UserSessionManager;
 import org.keycloak.testsuite.rule.KeycloakRule;
 import org.keycloak.testsuite.rule.LoggingRule;
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionProviderTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionProviderTest.java
index d75e467..f2fc3aa 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionProviderTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionProviderTest.java
@@ -31,7 +31,7 @@ import org.keycloak.models.UserLoginFailureModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.UserSessionModel;
 import org.keycloak.protocol.oidc.OIDCLoginProtocol;
-import org.keycloak.services.managers.UserManager;
+import org.keycloak.models.UserManager;
 import org.keycloak.testsuite.rule.KeycloakRule;
 
 import java.util.Arrays;
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/org/keycloak/testsuite/integration-arquillian-testsuite-providers/main/module.xml b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/org/keycloak/testsuite/integration-arquillian-testsuite-providers/main/module.xml
index 28e4789..6f20838 100644
--- a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/org/keycloak/testsuite/integration-arquillian-testsuite-providers/main/module.xml
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/org/keycloak/testsuite/integration-arquillian-testsuite-providers/main/module.xml
@@ -28,6 +28,7 @@
         <module name="org.keycloak.keycloak-common"/>
         <module name="org.keycloak.keycloak-core"/>
         <module name="org.keycloak.keycloak-server-spi"/>
+        <module name="org.keycloak.keycloak-server-spi-private"/>
         <module name="org.keycloak.keycloak-services"/>
         <module name="org.keycloak.keycloak-model-infinispan"/>
         <module name="org.keycloak.keycloak-model-jpa"/>
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/JavaKeystoreKeyProviderTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/JavaKeystoreKeyProviderTest.java
index 5c54213..642a872 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/JavaKeystoreKeyProviderTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/JavaKeystoreKeyProviderTest.java
@@ -22,15 +22,10 @@ import org.jboss.arquillian.graphene.page.Page;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
-import org.keycloak.common.util.KeyUtils;
 import org.keycloak.common.util.MultivaluedHashMap;
-import org.keycloak.common.util.PemUtils;
-import org.keycloak.keys.Attributes;
-import org.keycloak.keys.GeneratedRsaKeyProviderFactory;
 import org.keycloak.keys.JavaKeystoreKeyProviderFactory;
 import org.keycloak.keys.KeyMetadata;
 import org.keycloak.keys.KeyProvider;
-import org.keycloak.keys.RsaKeyProviderFactory;
 import org.keycloak.representations.idm.ComponentRepresentation;
 import org.keycloak.representations.idm.ErrorRepresentation;
 import org.keycloak.representations.idm.KeysMetadataRepresentation;
@@ -45,9 +40,6 @@ import javax.ws.rs.core.Response;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.InputStream;
-import java.security.KeyPair;
-import java.security.cert.Certificate;
-import java.security.interfaces.RSAPublicKey;
 import java.util.List;
 
 import static org.junit.Assert.*;
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/RsaKeyProviderTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/RsaKeyProviderTest.java
index 2dc3506..5bfaef2 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/RsaKeyProviderTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/RsaKeyProviderTest.java
@@ -20,17 +20,13 @@ package org.keycloak.testsuite.keys;
 import org.jboss.arquillian.graphene.page.Page;
 import org.junit.Rule;
 import org.junit.Test;
-import org.keycloak.RSATokenVerifier;
-import org.keycloak.common.VerificationException;
 import org.keycloak.common.util.CertificateUtils;
 import org.keycloak.common.util.KeyUtils;
 import org.keycloak.common.util.MultivaluedHashMap;
 import org.keycloak.common.util.PemUtils;
 import org.keycloak.keys.Attributes;
-import org.keycloak.keys.GeneratedRsaKeyProviderFactory;
 import org.keycloak.keys.KeyMetadata;
 import org.keycloak.keys.KeyProvider;
-import org.keycloak.keys.RsaKeyProvider;
 import org.keycloak.keys.RsaKeyProviderFactory;
 import org.keycloak.representations.idm.ComponentRepresentation;
 import org.keycloak.representations.idm.ErrorRepresentation;
@@ -40,16 +36,11 @@ import org.keycloak.testsuite.AbstractKeycloakTest;
 import org.keycloak.testsuite.AssertEvents;
 import org.keycloak.testsuite.admin.ApiUtil;
 import org.keycloak.testsuite.pages.AppPage;
-import org.keycloak.testsuite.pages.AppPage.RequestType;
 import org.keycloak.testsuite.pages.LoginPage;
-import org.keycloak.testsuite.util.OAuthClient;
 
-import javax.ws.rs.WebApplicationException;
 import javax.ws.rs.core.Response;
 import java.security.KeyPair;
-import java.security.PublicKey;
 import java.security.cert.Certificate;
-import java.security.cert.X509Certificate;
 import java.util.List;
 
 import static org.junit.Assert.*;
diff --git a/wildfly/adduser/pom.xml b/wildfly/adduser/pom.xml
index b33eb5f..6a827f4 100755
--- a/wildfly/adduser/pom.xml
+++ b/wildfly/adduser/pom.xml
@@ -36,6 +36,10 @@
         </dependency>
         <dependency>
             <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-server-spi-private</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
             <artifactId>keycloak-common</artifactId>
         </dependency>
         <dependency>
diff --git a/wildfly/extensions/pom.xml b/wildfly/extensions/pom.xml
index 0cafd9c..9b677db 100755
--- a/wildfly/extensions/pom.xml
+++ b/wildfly/extensions/pom.xml
@@ -47,6 +47,11 @@
         </dependency>
         <dependency>
             <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-server-spi-private</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
             <artifactId>keycloak-services</artifactId>
             <scope>provided</scope>
         </dependency>
diff --git a/wildfly/server-subsystem/pom.xml b/wildfly/server-subsystem/pom.xml
index 7710f9f..03ac1a7 100755
--- a/wildfly/server-subsystem/pom.xml
+++ b/wildfly/server-subsystem/pom.xml
@@ -108,7 +108,7 @@
         </dependency>
         <dependency>
             <groupId>org.keycloak</groupId>
-            <artifactId>keycloak-server-spi</artifactId>
+            <artifactId>keycloak-server-spi-private</artifactId>
             <scope>provided</scope>
         </dependency>