keycloak-aplcache

Changes

distribution/demo-dist/src/main/keycloak-server.json 72(+0 -72)

distribution/demo-dist/src/main/providers/README.txt 2(+0 -2)

distribution/demo-dist/src/main/themes/README.txt 3(+0 -3)

distribution/modules/src/main/resources/modules/org/apache/httpcomponents/4.3/module.xml 14(+0 -14)

distribution/modules/src/main/resources/modules/org/keycloak/keycloak-adapter-core/main/module.xml 20(+0 -20)

distribution/modules/src/main/resources/modules/org/keycloak/keycloak-adapter-subsystem/main/module.xml 51(+0 -51)

distribution/modules/src/main/resources/modules/org/keycloak/keycloak-as7-adapter/main/module.xml 25(+0 -25)

distribution/modules/src/main/resources/modules/org/keycloak/keycloak-as7-subsystem/main/module.xml 23(+0 -23)

distribution/modules/src/main/resources/modules/org/keycloak/keycloak-jboss-adapter-core/main/module.xml 17(+0 -17)

distribution/modules/src/main/resources/modules/org/keycloak/keycloak-undertow-adapter/main/module.xml 25(+0 -25)

distribution/modules/src/main/resources/modules/org/keycloak/keycloak-wildfly-adapter/main/module.xml 26(+0 -26)

distribution/modules/src/main/resources/modules/org/keycloak/keycloak-wildfly-extensions/main/module.xml 15(+0 -15)

distribution/server-overlay/src/main/keycloak-server.json 72(+0 -72)

distribution/server-overlay/src/main/providers/README.txt 2(+0 -2)

distribution/server-overlay/src/main/themes/README.txt 3(+0 -3)

distribution/server-overlay/src/main/xslt/standalone.xsl 54(+0 -54)

integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/authserver/AbstractAddOverlayHandler.java 206(+0 -206)

integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/authserver/AddProviderHandler.java 51(+0 -51)

integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/authserver/AuthServerAddHandler.java 74(+0 -74)

integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/authserver/AuthServerDefinition.java 131(+0 -131)

integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/authserver/ListOverlaysHandler.java 74(+0 -74)

integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/authserver/RemoveOverlayHandler.java 78(+0 -78)

pom.xml 8(+7 -1)

testsuite/integration/src/test/java/org/keycloak/testsuite/utils/ListSpi.java 34(+0 -34)

Details

diff --git a/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProviderMapperSpi.java b/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProviderMapperSpi.java
index 44fb65d..b0ac20a 100755
--- a/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProviderMapperSpi.java
+++ b/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProviderMapperSpi.java
@@ -10,8 +10,8 @@ import org.keycloak.provider.Spi;
 public class IdentityProviderMapperSpi implements Spi {
 
     @Override
-    public boolean isPrivate() {
-        return false;
+    public boolean isInternal() {
+        return true;
     }
 
     @Override
diff --git a/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProviderSpi.java b/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProviderSpi.java
index b507e55..3348bd2 100644
--- a/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProviderSpi.java
+++ b/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProviderSpi.java
@@ -29,7 +29,7 @@ public class IdentityProviderSpi implements Spi {
     public static final String IDENTITY_PROVIDER_SPI_NAME = "identity_provider";
 
     @Override
-    public boolean isPrivate() {
+    public boolean isInternal() {
         return false;
     }
 
diff --git a/connections/file/src/main/java/org/keycloak/connections/file/FileConnectionSpi.java b/connections/file/src/main/java/org/keycloak/connections/file/FileConnectionSpi.java
index ec64192..5929a0b 100644
--- a/connections/file/src/main/java/org/keycloak/connections/file/FileConnectionSpi.java
+++ b/connections/file/src/main/java/org/keycloak/connections/file/FileConnectionSpi.java
@@ -10,7 +10,7 @@ import org.keycloak.provider.Spi;
 public class FileConnectionSpi implements Spi {
 
     @Override
-    public boolean isPrivate() {
+    public boolean isInternal() {
         return true;
     }
 
diff --git a/connections/http-client/src/main/java/org/keycloak/connections/httpclient/HttpClientSpi.java b/connections/http-client/src/main/java/org/keycloak/connections/httpclient/HttpClientSpi.java
index 510b164..01cbaa3 100755
--- a/connections/http-client/src/main/java/org/keycloak/connections/httpclient/HttpClientSpi.java
+++ b/connections/http-client/src/main/java/org/keycloak/connections/httpclient/HttpClientSpi.java
@@ -10,7 +10,7 @@ import org.keycloak.provider.Spi;
 public class HttpClientSpi implements Spi {
 
     @Override
-    public boolean isPrivate() {
+    public boolean isInternal() {
         return true;
     }
 
diff --git a/connections/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionSpi.java b/connections/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionSpi.java
index f76c070..a4db87e 100644
--- a/connections/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionSpi.java
+++ b/connections/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionSpi.java
@@ -10,7 +10,7 @@ import org.keycloak.provider.Spi;
 public class InfinispanConnectionSpi implements Spi {
 
     @Override
-    public boolean isPrivate() {
+    public boolean isInternal() {
         return true;
     }
 
diff --git a/connections/jpa/src/main/java/org/keycloak/connections/jpa/JpaConnectionSpi.java b/connections/jpa/src/main/java/org/keycloak/connections/jpa/JpaConnectionSpi.java
index d565357..61eb816 100644
--- a/connections/jpa/src/main/java/org/keycloak/connections/jpa/JpaConnectionSpi.java
+++ b/connections/jpa/src/main/java/org/keycloak/connections/jpa/JpaConnectionSpi.java
@@ -10,7 +10,7 @@ import org.keycloak.provider.Spi;
 public class JpaConnectionSpi implements Spi {
 
     @Override
-    public boolean isPrivate() {
+    public boolean isInternal() {
         return true;
     }
 
diff --git a/connections/jpa/src/main/java/org/keycloak/connections/jpa/updater/JpaUpdaterSpi.java b/connections/jpa/src/main/java/org/keycloak/connections/jpa/updater/JpaUpdaterSpi.java
index c9bd8ee..eaddc27 100644
--- a/connections/jpa/src/main/java/org/keycloak/connections/jpa/updater/JpaUpdaterSpi.java
+++ b/connections/jpa/src/main/java/org/keycloak/connections/jpa/updater/JpaUpdaterSpi.java
@@ -10,7 +10,7 @@ import org.keycloak.provider.Spi;
 public class JpaUpdaterSpi implements Spi {
 
     @Override
-    public boolean isPrivate() {
+    public boolean isInternal() {
         return true;
     }
 
diff --git a/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.3.0.Beta1.xml b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.3.0.Beta1.xml
index 5ce5891..86b9d75 100755
--- a/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.3.0.Beta1.xml
+++ b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.3.0.Beta1.xml
@@ -19,7 +19,7 @@
             <column name="AUTH_USER_ID" type="VARCHAR(255)"/>
             <column name="IP_ADDRESS" type="VARCHAR(255)"/>
             <column name="RESOURCE_PATH" type="VARCHAR(2550)"/>
-            <column name="REPRESENTATION" type="BLOB(25500)"/>
+            <column name="REPRESENTATION" type="TEXT(25500)"/>
             <column name="ERROR" type="VARCHAR(255)"/>
         </createTable>
         <createTable tableName="AUTHENTICATOR">
@@ -28,7 +28,7 @@
             </column>
             <column name="ALIAS" type="VARCHAR(255)"/>
             <column name="REALM_ID" type="VARCHAR(36)"/>
-            <column name="PROVIDER_ID" type="VARCHAR(36)"/>
+            <column name="PROVIDER_ID" type="VARCHAR(255)"/>
         </createTable>
         <createTable tableName="AUTHENTICATION_FLOW">
             <column name="ID" type="VARCHAR(36)">
@@ -94,6 +94,9 @@
             <column name="ADMIN_EVENTS_DETAILS_ENABLED" type="BOOLEAN" defaultValueBoolean="false">
                 <constraints nullable="false"/>
             </column>
+            <column name="EDIT_USERNAME_ALLOWED" type="BOOLEAN" defaultValueBoolean="false">
+                <constraints nullable="false"/>
+            </column>
         </addColumn>
         <createTable tableName="CLIENT_SESSION_AUTH_STATUS">
             <column name="AUTHENTICATOR" type="VARCHAR(36)">
@@ -107,6 +110,19 @@
         <addColumn tableName="CLIENT_SESSION">
             <column name="AUTH_USER_ID" type="VARCHAR(36)"/>
         </addColumn>
+        <addColumn tableName="IDENTITY_PROVIDER">
+            <column name="TRUST_EMAIL" type="BOOLEAN" defaultValueBoolean="false"/>
+            <column name="UPDATE_PROFILE_FIRST_LGN_MD" type="VARCHAR(10)" defaultValue="on">
+                <constraints nullable="false"/>
+            </column>
+        </addColumn>
+        <!-- migrate value from UPDATE_PROFILE_FIRST_LOGIN to UPDATE_PROFILE_FIRST_LGN_MD then drop it -->
+        <update tableName="IDENTITY_PROVIDER">
+            <column name="UPDATE_PROFILE_FIRST_LGN_MD" value="off"/>
+            <where>UPDATE_PROFILE_FIRST_LOGIN = false</where>
+        </update>
+        <dropColumn tableName="IDENTITY_PROVIDER" columnName="UPDATE_PROFILE_FIRST_LOGIN"/>
+        
         <addColumn tableName="USER_REQUIRED_ACTION">
             <column name="REQUIRED_ACTION" type="VARCHAR(36)">
                 <constraints nullable="false"/>
@@ -147,5 +163,7 @@
         <addForeignKeyConstraint baseColumnNames="REALM_ID" baseTableName="USER_FEDERATION_MAPPER" constraintName="FK_FEDMAPPERPM_REALM" referencedColumnNames="ID" referencedTableName="REALM"/>
         <addForeignKeyConstraint baseColumnNames="FEDERATION_PROVIDER_ID" baseTableName="USER_FEDERATION_MAPPER" constraintName="FK_FEDMAPPERPM_FEDPRV" referencedColumnNames="ID" referencedTableName="USER_FEDERATION_PROVIDER"/>
         <addForeignKeyConstraint baseColumnNames="USER_FEDERATION_MAPPER_ID" baseTableName="USER_FEDERATION_MAPPER_CONFIG" constraintName="FK_FEDMAPPER_CFG" referencedColumnNames="ID" referencedTableName="USER_FEDERATION_MAPPER"/>
+
+        <dropColumn tableName="REALM" columnName="PASSWORD_CRED_GRANT_ALLOWED"/>
     </changeSet>
 </databaseChangeLog>
diff --git a/connections/mongo/src/main/java/org/keycloak/connections/mongo/DefaultMongoConnectionFactoryProvider.java b/connections/mongo/src/main/java/org/keycloak/connections/mongo/DefaultMongoConnectionFactoryProvider.java
index ed6844c..dab99e0 100755
--- a/connections/mongo/src/main/java/org/keycloak/connections/mongo/DefaultMongoConnectionFactoryProvider.java
+++ b/connections/mongo/src/main/java/org/keycloak/connections/mongo/DefaultMongoConnectionFactoryProvider.java
@@ -43,7 +43,10 @@ public class DefaultMongoConnectionFactoryProvider implements MongoConnectionPro
             "org.keycloak.models.entities.ProtocolMapperEntity",
             "org.keycloak.models.entities.IdentityProviderMapperEntity",
             "org.keycloak.models.mongo.keycloak.entities.MongoUserConsentEntity",
-            "org.keycloak.models.mongo.keycloak.entities.MongoMigrationModelEntity"
+            "org.keycloak.models.mongo.keycloak.entities.MongoMigrationModelEntity",
+            "org.keycloak.models.entities.AuthenticationExecutionEntity",
+            "org.keycloak.models.entities.AuthenticationFlowEntity",
+            "org.keycloak.models.entities.AuthenticatorEntity",
     };
 
     private static final Logger logger = Logger.getLogger(DefaultMongoConnectionFactoryProvider.class);
diff --git a/connections/mongo/src/main/java/org/keycloak/connections/mongo/MongoConnectionSpi.java b/connections/mongo/src/main/java/org/keycloak/connections/mongo/MongoConnectionSpi.java
index f391dfd..9c5c532 100644
--- a/connections/mongo/src/main/java/org/keycloak/connections/mongo/MongoConnectionSpi.java
+++ b/connections/mongo/src/main/java/org/keycloak/connections/mongo/MongoConnectionSpi.java
@@ -10,7 +10,7 @@ import org.keycloak.provider.Spi;
 public class MongoConnectionSpi implements Spi {
 
     @Override
-    public boolean isPrivate() {
+    public boolean isInternal() {
         return true;
     }
 
diff --git a/connections/mongo/src/main/java/org/keycloak/connections/mongo/updater/MongoUpdaterSpi.java b/connections/mongo/src/main/java/org/keycloak/connections/mongo/updater/MongoUpdaterSpi.java
index 830aaa3..ed92458 100644
--- a/connections/mongo/src/main/java/org/keycloak/connections/mongo/updater/MongoUpdaterSpi.java
+++ b/connections/mongo/src/main/java/org/keycloak/connections/mongo/updater/MongoUpdaterSpi.java
@@ -10,7 +10,7 @@ import org.keycloak.provider.Spi;
 public class MongoUpdaterSpi implements Spi {
 
     @Override
-    public boolean isPrivate() {
+    public boolean isInternal() {
         return true;
     }
 
diff --git a/connections/mongo-update/src/main/java/org/keycloak/connections/mongo/updater/impl/DefaultMongoUpdaterProvider.java b/connections/mongo-update/src/main/java/org/keycloak/connections/mongo/updater/impl/DefaultMongoUpdaterProvider.java
index 551d0e6..c8097f6 100644
--- a/connections/mongo-update/src/main/java/org/keycloak/connections/mongo/updater/impl/DefaultMongoUpdaterProvider.java
+++ b/connections/mongo-update/src/main/java/org/keycloak/connections/mongo/updater/impl/DefaultMongoUpdaterProvider.java
@@ -6,11 +6,7 @@ import com.mongodb.DBCollection;
 import com.mongodb.DBCursor;
 import org.jboss.logging.Logger;
 import org.keycloak.connections.mongo.updater.MongoUpdaterProvider;
-import org.keycloak.connections.mongo.updater.impl.updates.Update;
-import org.keycloak.connections.mongo.updater.impl.updates.Update1_0_0_Final;
-import org.keycloak.connections.mongo.updater.impl.updates.Update1_1_0_Beta1;
-import org.keycloak.connections.mongo.updater.impl.updates.Update1_2_0_Beta1;
-import org.keycloak.connections.mongo.updater.impl.updates.Update1_2_0_CR1;
+import org.keycloak.connections.mongo.updater.impl.updates.*;
 import org.keycloak.models.KeycloakSession;
 
 import java.util.Date;
@@ -30,7 +26,8 @@ public class DefaultMongoUpdaterProvider implements MongoUpdaterProvider {
             Update1_0_0_Final.class,
             Update1_1_0_Beta1.class,
             Update1_2_0_Beta1.class,
-            Update1_2_0_CR1.class
+            Update1_2_0_CR1.class,
+            Update1_3_0_Beta1.class
     };
 
     @Override
diff --git a/connections/mongo-update/src/main/java/org/keycloak/connections/mongo/updater/impl/updates/Update.java b/connections/mongo-update/src/main/java/org/keycloak/connections/mongo/updater/impl/updates/Update.java
index f05e79c..cc7a2d2 100644
--- a/connections/mongo-update/src/main/java/org/keycloak/connections/mongo/updater/impl/updates/Update.java
+++ b/connections/mongo-update/src/main/java/org/keycloak/connections/mongo/updater/impl/updates/Update.java
@@ -53,6 +53,10 @@ public abstract class Update {
         log.debugv("Deleted entries from {0}", collection);
     }
 
+    protected void removeField(String collection, String field) {
+        db.getCollection(collection).update(new BasicDBObject(), new BasicDBObject("$unset" , new BasicDBObject(field, 1)), false, true);
+    }
+
     protected void renameCollection(String collection, String newName) {
         db.getCollection(collection).rename(newName);
     }
diff --git a/connections/mongo-update/src/main/java/org/keycloak/connections/mongo/updater/impl/updates/Update1_3_0_Beta1.java b/connections/mongo-update/src/main/java/org/keycloak/connections/mongo/updater/impl/updates/Update1_3_0_Beta1.java
new file mode 100644
index 0000000..f834d22
--- /dev/null
+++ b/connections/mongo-update/src/main/java/org/keycloak/connections/mongo/updater/impl/updates/Update1_3_0_Beta1.java
@@ -0,0 +1,59 @@
+package org.keycloak.connections.mongo.updater.impl.updates;
+
+import com.mongodb.BasicDBList;
+import com.mongodb.BasicDBObject;
+import com.mongodb.DBCollection;
+import com.mongodb.DBCursor;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.representations.idm.IdentityProviderRepresentation;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class Update1_3_0_Beta1 extends Update {
+
+    @Override
+    public String getId() {
+        return "1.3.0.Beta1";
+    }
+
+    @Override
+    public void update(KeycloakSession session) {
+        deleteEntries("clientSessions");
+        deleteEntries("sessions");
+
+        removeField("realms", "passwordCredentialGrantAllowed");
+
+        updateIdentityProviders();
+    }
+
+    private void updateIdentityProviders() {
+        DBCollection realms = db.getCollection("realms");
+        DBCursor realmsCursor = realms.find();
+
+        try {
+            while (realmsCursor.hasNext()) {
+                BasicDBObject realm = (BasicDBObject) realmsCursor.next();
+
+                BasicDBList identityProviders = (BasicDBList) realm.get("identityProviders");
+                if (identityProviders != null) {
+                    for (Object ipObj : identityProviders) {
+                        BasicDBObject identityProvider = (BasicDBObject) ipObj;
+
+                        boolean updateProfileFirstLogin = identityProvider.getBoolean("updateProfileFirstLogin");
+                        String upflMode = updateProfileFirstLogin ? IdentityProviderRepresentation.UPFLM_ON : IdentityProviderRepresentation.UPFLM_OFF;
+                        identityProvider.put("updateProfileFirstLoginMode", upflMode);
+                        identityProvider.removeField("updateProfileFirstLogin");
+
+                        identityProvider.put("trustEmail", false);
+                    }
+                }
+
+                realms.save(realm);
+            }
+        } finally {
+            realmsCursor.close();
+        }
+    }
+
+}
diff --git a/core/src/main/java/org/keycloak/representations/idm/IdentityProviderRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/IdentityProviderRepresentation.java
index c456355..1e74002 100755
--- a/core/src/main/java/org/keycloak/representations/idm/IdentityProviderRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/IdentityProviderRepresentation.java
@@ -29,7 +29,26 @@ public class IdentityProviderRepresentation {
     protected String internalId;
     protected String providerId;
     protected boolean enabled = true;
-    protected boolean updateProfileFirstLogin = true;
+
+    public static final String UPFLM_ON = "on";
+    public static final String UPFLM_MISSING = "missing";
+    public static final String UPFLM_OFF = "off";
+
+    /**
+     * Mode of profile update after first login when user is created over this identity provider. Possible values:
+     * <ul>
+     * <li><code>on</code> - update profile page is presented for all users
+     * <li><code>missing</code> - update profile page is presented for users with missing some of mandatory user profile fields
+     * <li><code>off</code> - update profile page is newer shown after first login
+     * </ul>
+     * 
+     * @see #UPFLM_ON
+     * @see #UPFLM_MISSING
+     * @see #UPFLM_OFF
+     */
+    protected String updateProfileFirstLoginMode = UPFLM_ON;
+
+    protected boolean trustEmail;
     protected boolean storeToken;
     protected boolean addReadTokenRoleOnCreate;
     protected boolean authenticateByDefault;
@@ -75,12 +94,29 @@ public class IdentityProviderRepresentation {
         this.enabled = enabled;
     }
 
-    public boolean isUpdateProfileFirstLogin() {
-        return this.updateProfileFirstLogin;
+    /**
+     * 
+     * Deprecated because replaced by {@link #updateProfileFirstLoginMode}. Kept here to allow import of old realms.
+     * 
+     * @deprecated {@link #setUpdateProfileFirstLoginMode(String)}
+     */
+    @Deprecated
+    public void setUpdateProfileFirstLogin(boolean updateProfileFirstLogin) {
+        this.updateProfileFirstLoginMode = updateProfileFirstLogin ? UPFLM_ON : UPFLM_OFF;
     }
 
-    public void setUpdateProfileFirstLogin(boolean updateProfileFirstLogin) {
-        this.updateProfileFirstLogin = updateProfileFirstLogin;
+    /**
+     * @return see {@link #updateProfileFirstLoginMode}
+     */
+    public String getUpdateProfileFirstLoginMode() {
+        return updateProfileFirstLoginMode;
+    }
+
+    /**
+     * @param updateProfileFirstLoginMode see {@link #updateProfileFirstLoginMode}
+     */
+    public void setUpdateProfileFirstLoginMode(String updateProfileFirstLoginMode) {
+        this.updateProfileFirstLoginMode = updateProfileFirstLoginMode;
     }
 
     public boolean isAuthenticateByDefault() {
@@ -106,4 +142,13 @@ public class IdentityProviderRepresentation {
     public void setAddReadTokenRoleOnCreate(boolean addReadTokenRoleOnCreate) {
         this.addReadTokenRoleOnCreate = addReadTokenRoleOnCreate;
     }
+
+    public boolean isTrustEmail() {
+        return trustEmail;
+    }
+
+    public void setTrustEmail(boolean trustEmail) {
+        this.trustEmail = trustEmail;
+    }
+
 }
diff --git a/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java
index 6ff027c..dabc8db 100755
--- a/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java
@@ -18,12 +18,14 @@ public class RealmRepresentation {
     protected Integer accessCodeLifespanLogin;
     protected Boolean enabled;
     protected String sslRequired;
+    @Deprecated
     protected Boolean passwordCredentialGrantAllowed;
     protected Boolean registrationAllowed;
     protected Boolean registrationEmailAsUsername;
     protected Boolean rememberMe;
     protected Boolean verifyEmail;
     protected Boolean resetPasswordAllowed;
+    protected Boolean editUsernameAllowed;
 
     protected Boolean userCacheEnabled;
     protected Boolean realmCacheEnabled;
@@ -268,10 +270,6 @@ public class RealmRepresentation {
         return passwordCredentialGrantAllowed;
     }
 
-    public void setPasswordCredentialGrantAllowed(Boolean passwordCredentialGrantAllowed) {
-        this.passwordCredentialGrantAllowed = passwordCredentialGrantAllowed;
-    }
-
     public Boolean isRegistrationAllowed() {
         return registrationAllowed;
     }
@@ -328,6 +326,14 @@ public class RealmRepresentation {
         this.resetPasswordAllowed = resetPassword;
     }
 
+    public Boolean isEditUsernameAllowed() {
+        return editUsernameAllowed;
+    }
+
+    public void setEditUsernameAllowed(Boolean editUsernameAllowed) {
+        this.editUsernameAllowed = editUsernameAllowed;
+    }
+
     @Deprecated
     public Boolean isSocial() {
         return social;
diff --git a/core/src/main/java/org/keycloak/util/HtmlUtils.java b/core/src/main/java/org/keycloak/util/HtmlUtils.java
old mode 100644
new mode 100755
index 7da97b7..2387482
--- a/core/src/main/java/org/keycloak/util/HtmlUtils.java
+++ b/core/src/main/java/org/keycloak/util/HtmlUtils.java
@@ -34,7 +34,17 @@ public class HtmlUtils {
         for (int i = 0; i < value.length(); i++) {
             char chr = value.charAt(i);
 
-            if (chr != '\'' && chr != '"' && chr != '<' && chr != '>' && chr != '/') {
+            if (chr == '<') {
+                escaped.append("&lt;");
+            } else if (chr == '>') {
+                escaped.append("&gt;");
+            } else if (chr == '"') {
+                escaped.append("&quot;");
+            } else if (chr == '\'') {
+                escaped.append("&apos;");
+            } else if (chr == '&') {
+                escaped.append("&amp;");
+            } else {
                 escaped.append(chr);
             }
         }
diff --git a/distribution/demo-dist/assembly.xml b/distribution/demo-dist/assembly.xml
index f00bfea..5a6be78 100755
--- a/distribution/demo-dist/assembly.xml
+++ b/distribution/demo-dist/assembly.xml
@@ -14,7 +14,6 @@
             <outputDirectory>keycloak</outputDirectory>
             <excludes>
                 <exclude>**/*.sh</exclude>
-                <exclude>standalone/configuration/standalone-keycloak.xml</exclude>
             </excludes>
         </fileSet>
         <fileSet>
@@ -26,6 +25,20 @@
             <fileMode>0755</fileMode>
         </fileSet>
         <fileSet>
+            <directory>${project.build.directory}/unpacked/keycloak-server-overlay-${project.version}</directory>
+            <outputDirectory>keycloak</outputDirectory>
+            <excludes>
+                <exclude>standalone/configuration/standalone-keycloak.xml</exclude>
+            </excludes>
+        </fileSet>
+        <fileSet>
+            <directory>${project.build.directory}/unpacked/keycloak-wf9-adapter-${project.version}</directory>
+            <outputDirectory>keycloak</outputDirectory>
+            <excludes>
+                <exclude>standalone/configuration/standalone-keycloak.xml</exclude>
+            </excludes>
+        </fileSet>
+        <fileSet>
             <directory>${project.build.directory}/unpacked/keycloak-docs-${project.version}</directory>
             <outputDirectory>docs</outputDirectory>
         </fileSet>
@@ -34,5 +47,11 @@
             <outputDirectory>examples</outputDirectory>
         </fileSet>
     </fileSets>
+    <files>
+        <file>
+            <source>${project.build.directory}/unpacked/standalone.xml</source>
+            <outputDirectory>keycloak/standalone/configuration</outputDirectory>
+        </file>
+    </files>
 
 </assembly>
diff --git a/distribution/demo-dist/pom.xml b/distribution/demo-dist/pom.xml
index 37e4bdc..e5394f1 100755
--- a/distribution/demo-dist/pom.xml
+++ b/distribution/demo-dist/pom.xml
@@ -16,7 +16,12 @@
     <dependencies>
         <dependency>
             <groupId>org.keycloak</groupId>
-            <artifactId>keycloak-server-dist</artifactId>
+            <artifactId>keycloak-server-overlay</artifactId>
+            <type>zip</type>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-wf9-adapter-dist</artifactId>
             <type>zip</type>
         </dependency>
         <dependency>
@@ -63,7 +68,7 @@
                         </configuration>
                     </execution>
                     <execution>
-                        <id>unpack-server-overlay</id>
+                        <id>unpack-server</id>
                         <phase>prepare-package</phase>
                         <goals>
                             <goal>unpack</goal>
@@ -74,7 +79,24 @@
                                     <groupId>org.keycloak</groupId>
                                     <artifactId>keycloak-server-overlay</artifactId>
                                     <type>zip</type>
-                                    <outputDirectory>${project.build.directory}/unpacked/wildfly-${wildfly.version}</outputDirectory>
+                                    <outputDirectory>${project.build.directory}/unpacked/keycloak-server-overlay-${project.version}</outputDirectory>
+                                </artifactItem>
+                            </artifactItems>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>unpack-adapter</id>
+                        <phase>prepare-package</phase>
+                        <goals>
+                            <goal>unpack</goal>
+                        </goals>
+                        <configuration>
+                            <artifactItems>
+                                <artifactItem>
+                                    <groupId>org.keycloak</groupId>
+                                    <artifactId>keycloak-wf9-adapter-dist</artifactId>
+                                    <type>zip</type>
+                                    <outputDirectory>${project.build.directory}/unpacked/keycloak-wf9-adapter-${project.version}</outputDirectory>
                                 </artifactItem>
                             </artifactItems>
                         </configuration>
@@ -134,7 +156,7 @@
                                     <includes>
                                         <include>standalone.xml</include>
                                     </includes>
-                                    <outputDir>${project.build.directory}/unpacked/wildfly-${wildfly.version}/standalone/configuration</outputDir>
+                                    <outputDir>${project.build.directory}/unpacked/</outputDir>
                                 </transformationSet>
                             </transformationSets>
                         </configuration>
diff --git a/distribution/demo-dist/src/main/xslt/standalone.xsl b/distribution/demo-dist/src/main/xslt/standalone.xsl
index 5de72af..bc0233a 100755
--- a/distribution/demo-dist/src/main/xslt/standalone.xsl
+++ b/distribution/demo-dist/src/main/xslt/standalone.xsl
@@ -39,11 +39,9 @@
         <xsl:copy>
             <xsl:apply-templates select="node()|@*"/>
             <subsystem xmlns="urn:jboss:domain:keycloak-server:1.1">
-                <auth-server name="main-auth-server">
-                    <enabled>true</enabled>
-                    <web-context>auth</web-context>
-                </auth-server>
+                <web-context>auth</web-context>
             </subsystem>
+            <subsystem xmlns="urn:jboss:domain:keycloak:1.1"/>
         </xsl:copy>
     </xsl:template>
 
diff --git a/distribution/feature-packs/server-feature-pack/pom.xml b/distribution/feature-packs/server-feature-pack/pom.xml
index a737427..9925f5f 100644
--- a/distribution/feature-packs/server-feature-pack/pom.xml
+++ b/distribution/feature-packs/server-feature-pack/pom.xml
@@ -126,7 +126,7 @@
                                     <version>${project.version}</version>
                                     <type>war</type>
                                     <overWrite>true</overWrite>
-                                    <outputDirectory>${project.build.directory}/${project.build.finalName}/modules/system/layers/base/org/keycloak/keycloak-server-subsystem/main/auth-server</outputDirectory>
+                                    <outputDirectory>${project.build.directory}/${project.build.finalName}/modules/system/layers/base/org/keycloak/keycloak-server-subsystem/main/server-war</outputDirectory>
                                 </artifactItem>
                             </artifactItems>
                         </configuration>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/de/idyl/winzipaes/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/de/idyl/winzipaes/main/module.xml
index 10f1103..14d7dff 100644
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/de/idyl/winzipaes/main/module.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/de/idyl/winzipaes/main/module.xml
@@ -4,7 +4,7 @@
 
 <module xmlns="urn:jboss:module:1.1" name="de.idyl.winzipaes">
     <resources>
-        <!-- Insert resources here -->
+        <artifact name="${de.idyl:winzipaes}"/>
     </resources>
     <dependencies>
         <module name="javax.api"/>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-server-subsystem/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-server-subsystem/main/module.xml
index 5233767..0d0c336 100644
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-server-subsystem/main/module.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/base/org/keycloak/keycloak-server-subsystem/main/module.xml
@@ -25,7 +25,7 @@
 <module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-server-subsystem">
     <properties>
         <property name="keycloak-version" value="${project.version}"/>
-        <property name="auth-server-exploded" value="false"/>
+        <property name="server-war-exploded" value="false"/>
     </properties>
 
     <resources>
diff --git a/distribution/modules/build.xml b/distribution/modules/build.xml
index d97c9f9..fb8971d 100755
--- a/distribution/modules/build.xml
+++ b/distribution/modules/build.xml
@@ -46,11 +46,6 @@
             <maven-resource group="net.iharder" artifact="base64"/>
         </module-def>
 
-        <module-def name="org.bouncycastle">
-            <maven-resource group="org.bouncycastle" artifact="bcprov-jdk15on"/>
-            <maven-resource group="org.bouncycastle" artifact="bcpkix-jdk15on"/>
-        </module-def>
-
         <module-def name="org.keycloak.keycloak-broker-core">
             <maven-resource group="org.keycloak" artifact="keycloak-broker-core"/>
         </module-def>
@@ -71,10 +66,6 @@
             <maven-resource group="org.keycloak" artifact="keycloak-services"/>
         </module-def>
 
-        <module-def name="org.keycloak.keycloak-wildfly-extensions">
-            <maven-resource group="org.keycloak" artifact="keycloak-wildfly-extensions"/>
-        </module-def>
-
         <module-def name="com.google.zxing.core">
             <maven-resource group="com.google.zxing" artifact="core"/>
         </module-def>
@@ -315,40 +306,9 @@
 
         <module-def name="org.keycloak.keycloak-server"></module-def>
 
-        <module-def name="org.keycloak.keycloak-adapter-core">
-            <maven-resource group="org.keycloak" artifact="keycloak-adapter-core"/>
-        </module-def>
-
-        <module-def name="org.keycloak.keycloak-jboss-adapter-core">
-            <maven-resource group="org.keycloak" artifact="keycloak-jboss-adapter-core"/>
-        </module-def>
-
-        <module-def name="org.keycloak.keycloak-as7-adapter">
-            <maven-resource group="org.keycloak" artifact="keycloak-as7-adapter"/>
-            <maven-resource group="org.keycloak" artifact="keycloak-tomcat-core-adapter"/>
-        </module-def>
-
-        <module-def name="org.keycloak.keycloak-undertow-adapter">
-            <maven-resource group="org.keycloak" artifact="keycloak-undertow-adapter"/>
-        </module-def>
-
-        <module-def name="org.keycloak.keycloak-wildfly-adapter">
-            <maven-resource group="org.keycloak" artifact="keycloak-wildfly-adapter"/>
-        </module-def>
-
         <module-def name="org.keycloak.keycloak-server-subsystem">
             <maven-resource group="org.keycloak" artifact="keycloak-wildfly-server-subsystem"/>
         </module-def>
-        <module-def name="org.keycloak.keycloak-as7-subsystem">
-            <maven-resource group="org.keycloak" artifact="keycloak-as7-subsystem"/>
-        </module-def>
-
-        <module-def name="org.apache.httpcomponents" slot="4.3">
-            <maven-resource group="org.apache.httpcomponents" artifact="httpclient"/>
-            <maven-resource group="org.apache.httpcomponents" artifact="httpcore"/>
-            <maven-resource group="org.apache.httpcomponents" artifact="httpmime"/>
-        </module-def>
-
     </target>
 
     <target name="clean-target">
diff --git a/distribution/modules/pom.xml b/distribution/modules/pom.xml
index b073f57..c4fffdb 100755
--- a/distribution/modules/pom.xml
+++ b/distribution/modules/pom.xml
@@ -36,26 +36,6 @@
         </dependency>
         <dependency>
             <groupId>org.keycloak</groupId>
-            <artifactId>keycloak-adapter-core</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.keycloak</groupId>
-            <artifactId>keycloak-jboss-adapter-core</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.keycloak</groupId>
-            <artifactId>keycloak-as7-adapter</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.keycloak</groupId>
-            <artifactId>keycloak-undertow-adapter</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.keycloak</groupId>
-            <artifactId>keycloak-wildfly-adapter</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.keycloak</groupId>
             <artifactId>keycloak-wildfly-server-subsystem</artifactId>
             <version>${project.version}</version>
         </dependency>
@@ -64,18 +44,6 @@
             <artifactId>keycloak-server</artifactId>
             <type>war</type>
         </dependency>
-        <dependency>
-            <groupId>org.keycloak</groupId>
-            <artifactId>keycloak-as7-subsystem</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.httpcomponents</groupId>
-            <artifactId>httpmime</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.httpcomponents</groupId>
-            <artifactId>httpcore</artifactId>
-        </dependency>
     </dependencies>
 
     <build>
diff --git a/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-connections-http-client/main/module.xml b/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-connections-http-client/main/module.xml
index 1d35246..7739aa3 100755
--- a/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-connections-http-client/main/module.xml
+++ b/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-connections-http-client/main/module.xml
@@ -14,7 +14,7 @@
         <module name="org.keycloak.keycloak-model-api"/>
         <module name="org.jboss.logging"/>
         <module name="javax.api"/>
-        <module name="org.apache.httpcomponents" slot="4.3" />
+        <module name="org.apache.httpcomponents"/>
     </dependencies>
 
 </module>
diff --git a/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-saml-protocol/main/module.xml b/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-saml-protocol/main/module.xml
index 655a8c0..45512ac 100755
--- a/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-saml-protocol/main/module.xml
+++ b/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-saml-protocol/main/module.xml
@@ -16,7 +16,7 @@
         <module name="org.keycloak.keycloak-login-api"/>
         <module name="org.keycloak.keycloak-services"/>
         <module name="org.keycloak.keycloak-forms-common-freemarker"/>
-        <module name="org.apache.httpcomponents" slot="4.3" />
+        <module name="org.apache.httpcomponents"/>
         <module name="org.jboss.logging"/>
         <module name="javax.ws.rs.api"/>
         <module name="org.jboss.resteasy.resteasy-jaxrs"/>
diff --git a/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-server/main/module.xml b/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-server/main/module.xml
index 9a7229f..fd8e190 100755
--- a/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-server/main/module.xml
+++ b/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-server/main/module.xml
@@ -9,10 +9,6 @@
     <dependencies>
         <module name="org.keycloak.keycloak-account-api" services="import"/>
         <module name="org.keycloak.keycloak-account-freemarker" services="import"/>
-        <module name="org.keycloak.keycloak-adapter-core" services="import"/>
-        <module name="org.keycloak.keycloak-adapter-subsystem" services="import"/>
-        <module name="org.keycloak.keycloak-as7-adapter" services="import"/>
-        <module name="org.keycloak.keycloak-as7-subsystem" services="import"/>
         <module name="org.keycloak.keycloak-connections-infinispan" services="import"/>
         <module name="org.keycloak.keycloak-connections-jpa" services="import"/>
         <module name="org.keycloak.keycloak-connections-jpa-liquibase" services="import"/>
@@ -36,7 +32,6 @@
         <module name="org.keycloak.keycloak-forms-common-themes" services="import"/>
         <module name="org.keycloak.keycloak-invalidation-cache-infinispan" services="import"/>
         <module name="org.keycloak.keycloak-invalidation-cache-model" services="import"/>
-        <module name="org.keycloak.keycloak-jboss-adapter-core" services="import"/>
         <module name="org.keycloak.keycloak-js-adapter" services="import"/>
         <module name="org.keycloak.keycloak-kerberos-federation" services="import"/>
         <module name="org.keycloak.keycloak-ldap-federation" services="import"/>
@@ -61,8 +56,6 @@
         <module name="org.keycloak.keycloak-server-subsystem" services="import"/>
         <module name="org.keycloak.keycloak-timer-api" services="import"/>
         <module name="org.keycloak.keycloak-timer-basic" services="import"/>
-        <module name="org.keycloak.keycloak-undertow-adapter" services="import"/>
-        <module name="org.keycloak.keycloak-wildfly-adapter" services="import"/>
     </dependencies>
 
 </module>
diff --git a/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-server-subsystem/main/module.xml b/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-server-subsystem/main/module.xml
index e877fe4..21f917e 100755
--- a/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-server-subsystem/main/module.xml
+++ b/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-server-subsystem/main/module.xml
@@ -46,7 +46,6 @@
         <module name="org.jboss.as.web-common" optional="true"/>
         <module name="org.jboss.as.web" optional="true"/>
         <module name="org.jboss.as.version" optional="true"/>
-        <module name="org.keycloak.keycloak-as7-adapter" optional="true"/>
         <module name="org.jboss.metadata"/>
     </dependencies>
 </module>
diff --git a/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-services/main/module.xml b/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-services/main/module.xml
index 55a5518..0ee8056 100755
--- a/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-services/main/module.xml
+++ b/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-services/main/module.xml
@@ -36,7 +36,6 @@
         <module name="org.keycloak.keycloak-forms-common-themes" services="import"/>
         <module name="org.keycloak.keycloak-invalidation-cache-infinispan" services="import"/>
         <module name="org.keycloak.keycloak-invalidation-cache-model" services="import"/>
-        <module name="org.keycloak.keycloak-jboss-adapter-core" services="import"/>
         <module name="org.keycloak.keycloak-js-adapter" services="import"/>
         <module name="org.keycloak.keycloak-kerberos-federation" services="import"/>
         <module name="org.keycloak.keycloak-ldap-federation" services="import"/>
@@ -50,7 +49,6 @@
         <module name="org.keycloak.keycloak-model-sessions-jpa" services="import"/>
         <module name="org.keycloak.keycloak-model-sessions-mem" services="import"/>
         <module name="org.keycloak.keycloak-model-sessions-mongo" services="import"/>
-        <module name="org.keycloak.keycloak-wildfly-extensions" services="import"/>
 
         <module name="org.keycloak.keycloak-saml-protocol" services="import"/>
         <module name="org.keycloak.keycloak-services" export="true" services="import"/>
@@ -78,7 +76,7 @@
         <module name="net.iharder.base64"/>
         <module name="javax.api"/>
         <module name="javax.activation.api"/>
-        <module name="org.apache.httpcomponents" slot="4.3" />
+        <module name="org.apache.httpcomponents"/>
     </dependencies>
 
 </module>
diff --git a/distribution/pom.xml b/distribution/pom.xml
index 3b7a66f..68f19b5 100755
--- a/distribution/pom.xml
+++ b/distribution/pom.xml
@@ -28,13 +28,13 @@
 
     <modules>
         <module>adapters</module>
-        <!--<module>demo-dist</module>-->
+        <module>demo-dist</module>
         <module>docs-dist</module>
         <module>examples-dist</module>
         <module>modules</module>
         <module>proxy-dist</module>
         <module>server-dist</module>
-        <!--<module>server-overlay</module>-->
+        <module>server-overlay</module>
         <module>src-dist</module>
         <module>subsystem-war</module>
         <module>feature-packs</module>
diff --git a/distribution/server-overlay/assembly.xml b/distribution/server-overlay/assembly.xml
index f8424b1..6efb409 100755
--- a/distribution/server-overlay/assembly.xml
+++ b/distribution/server-overlay/assembly.xml
@@ -10,46 +10,58 @@
 
     <fileSets>
         <fileSet>
-            <directory>${project.build.directory}/unpacked/modules</directory>
-            <outputDirectory>modules</outputDirectory>
+            <directory>${project.build.directory}/unpacked/keycloak-${project.version}/modules/system/layers/base</directory>
+            <outputDirectory>modules/system/layers/base</outputDirectory>
+            <includes>
+                <include>com/google/zxing/**</include>
+                <include>de/idyl/winzipaes/**</include>
+                <include>net/iharder/**</include>
+                <include>org/freemarker/**</include>
+                <include>org/keycloak/**</include>
+                <include>org/liquibase/**</include>
+                <include>org/mongodb/**</include>
+                <include>org/twitter4j/**</include>
+                <include>sun/jdk/jgss/**</include>
+            </includes>
         </fileSet>
         <fileSet>
-            <directory>${project.build.directory}/unpacked/content</directory>
+            <directory>${project.build.directory}/unpacked/keycloak-${project.version}/content</directory>
             <outputDirectory></outputDirectory>
         </fileSet>
         <fileSet>
-            <directory>../../forms/common-themes/src/main/resources/theme</directory>
+            <directory>${project.build.directory}/unpacked/keycloak-${project.version}/standalone/configuration/themes</directory>
             <outputDirectory>standalone/configuration/themes</outputDirectory>
             <includes>
                 <include>**/**</include>
             </includes>
         </fileSet>
         <fileSet>
+            <directory>${project.build.directory}/unpacked/keycloak-${project.version}/standalone/configuration/providers</directory>
+            <outputDirectory>standalone/configuration/providers</outputDirectory>
+            <includes>
+                <include>**/**</include>
+            </includes>
+        </fileSet>
+        <fileSet>
             <directory>../../</directory>
             <includes>
                 <include>License.html</include>
             </includes>
             <outputDirectory></outputDirectory>
         </fileSet>
+
     </fileSets>
 
     <files>
         <file>
-            <source>${project.build.directory}/unpacked/wildfly-${wildfly.version}/standalone/configuration/standalone.xml</source>
+            <source>${project.build.directory}/unpacked/keycloak-${project.version}/standalone/configuration/standalone.xml</source>
             <outputDirectory>standalone/configuration</outputDirectory>
             <destName>standalone-keycloak.xml</destName>
         </file>
         <file>
-            <source>src/main/keycloak-server.json</source>
+            <source>${project.build.directory}/unpacked/keycloak-${project.version}/standalone/configuration/keycloak-server.json</source>
             <outputDirectory>standalone/configuration</outputDirectory>
         </file>
-        <file>
-            <source>src/main/themes/README.txt</source>
-            <outputDirectory>standalone/configuration/themes</outputDirectory>
-        </file>
-        <file>
-            <source>src/main/providers/README.txt</source>
-            <outputDirectory>standalone/configuration/providers</outputDirectory>
-        </file>
     </files>
+
 </assembly>
diff --git a/distribution/server-overlay/pom.xml b/distribution/server-overlay/pom.xml
index a066b2c..7ab8862 100755
--- a/distribution/server-overlay/pom.xml
+++ b/distribution/server-overlay/pom.xml
@@ -10,49 +10,27 @@
 
     <artifactId>keycloak-server-overlay</artifactId>
     <packaging>pom</packaging>
-    <name>Keycloak Server Overlay</name>
+    <name>Keycloak Server Overlay Distribution</name>
     <description/>
 
     <dependencies>
         <dependency>
             <groupId>org.keycloak</groupId>
-            <artifactId>keycloak-jboss-modules</artifactId>
-            <type>zip</type>
-        </dependency>
-        <dependency>
-            <groupId>org.wildfly</groupId>
-            <artifactId>wildfly-dist</artifactId>
+            <artifactId>keycloak-server-dist</artifactId>
             <type>zip</type>
         </dependency>
     </dependencies>
 
     <build>
         <finalName>keycloak-overlay-${project.version}</finalName>
+
         <plugins>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-dependency-plugin</artifactId>
                 <executions>
                     <execution>
-                        <id>unpack-standalone-xml</id>
-                        <phase>prepare-package</phase>
-                        <goals>
-                            <goal>unpack</goal>
-                        </goals>
-                        <configuration>
-                            <artifactItems>
-                                <artifactItem>
-                                    <groupId>org.wildfly</groupId>
-                                    <artifactId>wildfly-dist</artifactId>
-                                    <type>zip</type>
-                                    <outputDirectory>${project.build.directory}/unpacked</outputDirectory>
-                                </artifactItem>
-                            </artifactItems>
-                            <includes>*/standalone/configuration/standalone.xml</includes>
-                        </configuration>
-                    </execution>
-                    <execution>
-                        <id>unpack-module</id>
+                        <id>unpack-server-dist</id>
                         <phase>prepare-package</phase>
                         <goals>
                             <goal>unpack</goal>
@@ -61,9 +39,9 @@
                             <artifactItems>
                                 <artifactItem>
                                     <groupId>org.keycloak</groupId>
-                                    <artifactId>keycloak-jboss-modules</artifactId>
+                                    <artifactId>keycloak-server-dist</artifactId>
                                     <type>zip</type>
-                                    <outputDirectory>${project.build.directory}/unpacked/modules</outputDirectory>
+                                    <outputDirectory>${project.build.directory}/unpacked</outputDirectory>
                                 </artifactItem>
                             </artifactItems>
                         </configuration>
@@ -71,32 +49,7 @@
                 </executions>
             </plugin>
             <plugin>
-                <groupId>org.codehaus.mojo</groupId>
-                <artifactId>xml-maven-plugin</artifactId>
-                <version>1.0</version>
-                <executions>
-                    <execution>
-                        <id>generate-resources</id>
-                        <phase>package</phase>
-                        <goals>
-                            <goal>transform</goal>
-                        </goals>
-                        <configuration>
-                            <transformationSets>
-                                <transformationSet>
-                                    <dir>${project.build.directory}/unpacked/wildfly-${wildfly.version}/standalone/configuration</dir>
-                                    <stylesheet>src/main/xslt/standalone.xsl</stylesheet>
-                                    <includes>
-                                        <include>standalone.xml</include>
-                                    </includes>
-                                    <outputDir>${project.build.directory}/unpacked/wildfly-${wildfly.version}/standalone/configuration</outputDir>
-                                </transformationSet>
-                            </transformationSets>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
-            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-assembly-plugin</artifactId>
                 <executions>
                     <execution>
@@ -109,9 +62,11 @@
                             <descriptors>
                                 <descriptor>assembly.xml</descriptor>
                             </descriptors>
-                            <outputDirectory>target</outputDirectory>
-                            <workDirectory>target/assembly/work</workDirectory>
+                            <recompressZippedFiles>true</recompressZippedFiles>
+                            <finalName>${project.build.finalName}</finalName>
                             <appendAssemblyId>false</appendAssemblyId>
+                            <outputDirectory>${project.build.directory}</outputDirectory>
+                            <workDirectory>${project.build.directory}/assembly/work</workDirectory>
                             <tarLongFileMode>gnu</tarLongFileMode>
                         </configuration>
                     </execution>
diff --git a/docbook/reference/en/en-US/master.xml b/docbook/reference/en/en-US/master.xml
index 218a1aa..d379ac8 100755
--- a/docbook/reference/en/en-US/master.xml
+++ b/docbook/reference/en/en-US/master.xml
@@ -35,6 +35,7 @@
                 <!ENTITY UserFederation SYSTEM "modules/user-federation.xml">
                 <!ENTITY Kerberos SYSTEM "modules/kerberos.xml">
                 <!ENTITY ExportImport SYSTEM "modules/export-import.xml">
+                <!ENTITY AdminRecovery SYSTEM "modules/admin-recovery.xml">
                 <!ENTITY ServerCache SYSTEM "modules/cache.xml">
                 <!ENTITY SecurityVulnerabilities SYSTEM "modules/security-vulnerabilities.xml">
                 <!ENTITY Clustering SYSTEM "modules/clustering.xml">
@@ -126,6 +127,7 @@ This one is short
     &UserFederation;
     &Kerberos;
     &ExportImport;
+    &AdminRecovery;
     &ServerCache;
     &SAML;
     &SecurityVulnerabilities;
diff --git a/docbook/reference/en/en-US/modules/admin-recovery.xml b/docbook/reference/en/en-US/modules/admin-recovery.xml
new file mode 100755
index 0000000..9412848
--- /dev/null
+++ b/docbook/reference/en/en-US/modules/admin-recovery.xml
@@ -0,0 +1,15 @@
+<chapter id="admin-recovery">
+    <title>Recovering the Master Admin User</title>
+    <para>
+        It is possible for the "admin" user in the master realm to become inoperable.  This may be because it was
+        accidentally deleted, its role mappings were removed, or the password was simply forgotten.
+    </para>
+    <para>
+        To recover the master admin user, just start the server with the following system properties:
+        <programlisting><![CDATA[
+bin/standalone.sh -Dkeycloak.recover-admin=true -Dkeycloak.temp-admin-password=temppassword
+]]></programlisting>
+        Then you can log in to the master admin account with your temporary password.  You will then be
+        prompted to immediately change this password.
+    </para>
+</chapter>
\ No newline at end of file
diff --git a/docbook/reference/en/en-US/modules/direct-access.xml b/docbook/reference/en/en-US/modules/direct-access.xml
index b21f82b..e7a189b 100755
--- a/docbook/reference/en/en-US/modules/direct-access.xml
+++ b/docbook/reference/en/en-US/modules/direct-access.xml
@@ -3,8 +3,7 @@
     <para>
         Keycloak allows you to make direct REST invocations to obtain an access token.
         (See <ulink url="http://tools.ietf.org/html/rfc6749#section-4.3">Resource Owner Password Credentials Grant</ulink>
-        from OAuth 2.0 spec).  To use it, Direct Access Grants must be allowed by your realm.  This is a configuration switch
-        in the admin console under Settings->General, specifically the "Direct Grant API" switch.  You must also have
+        from OAuth 2.0 spec).  To use it you must also have
         registered a valid Client to use as the "client_id" for this grant request.
     </para>
     <warning>
@@ -12,7 +11,9 @@
             It is highly recommended that you do not use Direct Access Grants to write your own login pages for your application.
             You will lose a lot of features that Keycloak has if you do this.  Specifically all the account management, remember me,
             lost password, account reset features of Keycloak.  Instead, if you want to tailor the look and feel of Keycloak login
-            pages, you should create your own <link linkend="themes">theme</link>.
+            pages, you should create your own <link linkend="themes">theme</link>. There are also security implications
+            to using Direct Access Grants compared to the redirect based flows as you are exposing plain text passwords
+            to applications directly.
         </para>
         <para>
             It is even highly recommended that you use the browser to log in for native mobile applications!  Android
diff --git a/docbook/reference/en/en-US/modules/identity-broker.xml b/docbook/reference/en/en-US/modules/identity-broker.xml
index 6eb5320..75df2c7 100755
--- a/docbook/reference/en/en-US/modules/identity-broker.xml
+++ b/docbook/reference/en/en-US/modules/identity-broker.xml
@@ -299,14 +299,26 @@
                         </entry>
                         <entry>
                             Allows you to force users to update their profile right after the authentication finishes and
-                            before the account is actually created in Keycloak. When enabled, users will be presented with the
+                            before the account is actually created in Keycloak. When "On", users will be always presented with the
                             <emphasis>update profile page</emphasis> asking for additional information in order to federate their identities.
-                            If disabled, the account will be created with the minimal information obtained from the identity provider
+                            When "On missing info", users will be presented with the <emphasis>update profile page</emphasis> only if some 
+                            mandatory information (email, first name, last name) is not provided by identity provider.
+                            If "Off", the account will be created with the minimal information obtained from the identity provider
                             during the authentication process.
                         </entry>
                     </row>
                     <row>
                         <entry>
+                            <literal>Trust email</literal>
+                        </entry>
+                        <entry>
+                            Allows you to trust email address returned from the social provider. If enabled then email address returned by the provider 
+                            is marked as 'verified' in the Keycloak user profile. This means that email verification step is skipped even 
+                            if "Verify email" feature is enabled in realm settings.
+                        </entry>
+                    </row>
+                    <row>
+                        <entry>
                             <literal>GUI order</literal>
                         </entry>
                         <entry>
diff --git a/docbook/reference/en/en-US/modules/MigrationFromOlderVersions.xml b/docbook/reference/en/en-US/modules/MigrationFromOlderVersions.xml
index ada2a89..68e48b4 100755
--- a/docbook/reference/en/en-US/modules/MigrationFromOlderVersions.xml
+++ b/docbook/reference/en/en-US/modules/MigrationFromOlderVersions.xml
@@ -80,6 +80,30 @@
     <section>
         <title>Version specific migration</title>
         <section>
+            <title>Migrating to 1.3.0.Final</title>
+            <simplesect>
+                <title>Direct Grant API always enabled</title>
+                <para>
+                    In the past Direct Grant API (or Resource Owner Password Credentials) was disabled by default and
+                    there was an option on a realm to enable it. The Direct Grant API is now always enabled and the
+                    option to enable/disable for a realm is removed.
+                </para>
+            </simplesect>
+            <simplesect>
+                <title>Database changed</title>
+                <para>
+                    There are again few database changes. Remember to backup your database prior to upgrading.
+                </para>
+            </simplesect>
+            <simplesect>
+                <title>UserFederationProvider changed</title>
+                <para>
+                    There are few minor changes in UserFederationProvider interface. You may need to sync your implementation when upgrade
+                    to newer version and upgrade few methods, which has changed signature. Changes are really minor, but were needed to improve performance of federation.
+                </para>
+            </simplesect>
+        </section>
+        <section>
             <title>Migrating from 1.2.0.Beta1 to 1.2.0.RC1</title>
             <simplesect>
                 <title>Distribution changes</title>
diff --git a/docbook/reference/en/en-US/modules/user-federation.xml b/docbook/reference/en/en-US/modules/user-federation.xml
index a8e6c17..c8e9856 100755
--- a/docbook/reference/en/en-US/modules/user-federation.xml
+++ b/docbook/reference/en/en-US/modules/user-federation.xml
@@ -24,7 +24,8 @@
     <section>
         <title>LDAP and Active Directory Plugin</title>
         <para>
-            Keycloak comes with a built-in LDAP/AD plugin.  Currently it is set up only to import username, email, first and last name.
+            Keycloak comes with a built-in LDAP/AD plugin.  By default, it is set up only to import username, email, first and last name, but you are free
+            to configure <link linkend='ldap_mappers'>mappers</link> and add more attributes or delete default ones.
             It supports password validation via LDAP/AD protocols and different user metadata synchronization modes.  To configure
             a federated LDAP store go to the admin console.  Click on the <literal>Users</literal> menu option to get you
             to the user management page.  Then click on the <literal>Federation</literal> submenu option.  When
@@ -41,7 +42,7 @@
                         <term>READONLY</term>
                         <listitem>
                             <para>
-                                Username, email, first and last name will be unchangable.  Keycloak will show an error
+                                Username, email, first and last name and other mapped attributes will be unchangeable.  Keycloak will show an error
                                 anytime anybody tries to update these fields.  Also, password updates will not be supported.
                             </para>
                         </listitem>
@@ -50,7 +51,7 @@
                         <term>WRITABLE</term>
                         <listitem>
                             <para>
-                                Username, email, first and last name, and passwords can all be updated and will
+                                Username, email, first and last name, other mapped attributes and passwords can all be updated and will
                                 be synchronized automatically with your LDAP store.
                             </para>
                         </listitem>
@@ -158,6 +159,56 @@
         </para>
         <para>In admin console, you can trigger sync directly or you can enable periodic changed or full sync.</para>
     </section>
+    <section id="ldap_mappers">
+        <title>LDAP/Federation mappers</title>
+        <para>
+            LDAP mappers are <literal>listeners</literal>, which are triggered by LDAP Federation provider at various points and provide
+            another extension point to LDAP integration. They are triggered during import LDAP user into Keycloak, registration Keycloak user back to LDAP or when querying LDAP user from Keycloak.
+            When you create LDAP Federation provider, Keycloak will automatically provide set of builtin <literal>mappers</literal> for this provider.
+            You are free to change this set and create new mapper or update/delete existing ones.
+        </para>
+        <para>
+            By default, we have those implementation of LDAP federation mapper:
+            <variablelist>
+                <varlistentry>
+                    <term>User Attribute Mapper</term>
+                    <listitem>
+                        <para>
+                            This allows to specify which LDAP attribute is mapped to which attribute of Keycloak User. So for example you can configure
+                            that LDAP attribute <literal>mail</literal> is supposed to be mapped to the UserModel attribute <literal>email</literal> in Keycloak database.
+                            For this mapper implementation, there is always one-to-one mapping (one LDAP attribute mapped to one Keycloak UserModel attribute)
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>FullName Mapper</term>
+                    <listitem>
+                        <para>
+                            This allows to specify that fullname of user, which is saved in some LDAP attribute (usualy <literal>cn</literal> ) will be mapped to
+                            <literal>firstName</literal> and <literal>lastname</literal> attributes of UserModel. Having <literal>cn</literal> to contain full name of user
+                            is common case for some LDAP deployments.
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>Role Mapper</term>
+                    <listitem>
+                        <para>
+                            This allows to configure role mappings from LDAP into Keycloak role mappings. One Role mapper can be used to map LDAP roles
+                            (usually groups from particular branch of LDAP tree) into roles corresponding to either realm roles or client roles of specified client.
+                            It's not a problem to configure more Role mappers for same LDAP provider. So for example you can specify that role mappings from groups under
+                            <literal>ou=main,dc=example,dc=org</literal> will be mapped to realm role mappings and role mappings from
+                            groups under <literal>ou=finance,dc=example,dc=org</literal> will be mapped to client role mappings of client <literal>finance</literal> .
+                        </para>
+                    </listitem>
+                </varlistentry>
+            </variablelist>
+        </para>
+        <para>By default, there is set of User Attribute mappers to map basic UserModel attributes username, first name, lastname and email to corresponding LDAP attributes. You are free to extend this and provide
+            more attribute mappings (For example to street, postalCode etc), delete firstName/lastname mapper and put fullName mapper instead, add role mappers etc.
+            Admin console provides tooltips, which should help on how to configure corresponding mappers.
+        </para>
+    </section>
     <section>
         <title>Writing your own User Federation Provider</title>
         <para>
diff --git a/events/api/src/main/java/org/keycloak/events/Details.java b/events/api/src/main/java/org/keycloak/events/Details.java
index cee7475..4a0a1ad 100755
--- a/events/api/src/main/java/org/keycloak/events/Details.java
+++ b/events/api/src/main/java/org/keycloak/events/Details.java
@@ -24,5 +24,12 @@ public interface Details {
     String NODE_HOST = "node_host";
     String REASON = "reason";
     String REVOKED_CLIENT = "revoked_client";
+    String CLIENT_SESSION_STATE = "client_session_state";
+    String CLIENT_SESSION_HOST = "client_session_host";
+
+    String CONSENT = "consent";
+    String CONSENT_VALUE_NO_CONSENT_REQUIRED = "no_consent_required"; // No consent is required by client
+    String CONSENT_VALUE_CONSENT_GRANTED = "consent_granted";         // Consent granted by user
+    String CONSENT_VALUE_PERSISTED_CONSENT = "persistent_consent";    // Persistent consent used (was already granted by user before)
 
 }
diff --git a/events/api/src/main/java/org/keycloak/events/EventListenerSpi.java b/events/api/src/main/java/org/keycloak/events/EventListenerSpi.java
index a16ad46..a3eedd1 100644
--- a/events/api/src/main/java/org/keycloak/events/EventListenerSpi.java
+++ b/events/api/src/main/java/org/keycloak/events/EventListenerSpi.java
@@ -10,7 +10,7 @@ import org.keycloak.provider.Spi;
 public class EventListenerSpi implements Spi {
 
     @Override
-    public boolean isPrivate() {
+    public boolean isInternal() {
         return false;
     }
 
diff --git a/events/api/src/main/java/org/keycloak/events/EventStoreSpi.java b/events/api/src/main/java/org/keycloak/events/EventStoreSpi.java
index af5f59f..256b7e4 100644
--- a/events/api/src/main/java/org/keycloak/events/EventStoreSpi.java
+++ b/events/api/src/main/java/org/keycloak/events/EventStoreSpi.java
@@ -10,7 +10,7 @@ import org.keycloak.provider.Spi;
 public class EventStoreSpi implements Spi {
 
     @Override
-    public boolean isPrivate() {
+    public boolean isInternal() {
         return true;
     }
 
diff --git a/events/mongo/src/main/java/org/keycloak/events/mongo/MongoAdminEventQuery.java b/events/mongo/src/main/java/org/keycloak/events/mongo/MongoAdminEventQuery.java
index 4fdb922..612294e 100644
--- a/events/mongo/src/main/java/org/keycloak/events/mongo/MongoAdminEventQuery.java
+++ b/events/mongo/src/main/java/org/keycloak/events/mongo/MongoAdminEventQuery.java
@@ -76,13 +76,17 @@ public class MongoAdminEventQuery implements AdminEventQuery{
 
     @Override
     public AdminEventQuery fromTime(Date fromTime) {
-        query.put("time", BasicDBObjectBuilder.start("$gte", fromTime.getTime()).get());
+        BasicDBObject time = query.containsField("time") ? (BasicDBObject) query.get("time") : new BasicDBObject();
+        time.append("$gte", fromTime.getTime());
+        query.put("time", time);
         return this;
     }
 
     @Override
     public AdminEventQuery toTime(Date toTime) {
-        query.put("time", BasicDBObjectBuilder.start("$lte", toTime.getTime()).get());
+        BasicDBObject time = query.containsField("time") ? (BasicDBObject) query.get("time") : new BasicDBObject();
+        time.append("$lte", toTime.getTime());
+        query.put("time", time);
         return this;
     }
 
diff --git a/examples/admin-client/example-realm.json b/examples/admin-client/example-realm.json
index 3ce2eaa..5676c55 100755
--- a/examples/admin-client/example-realm.json
+++ b/examples/admin-client/example-realm.json
@@ -3,7 +3,6 @@
     "enabled": true,
     "sslRequired": "external",
     "registrationAllowed": true,
-    "passwordCredentialGrantAllowed": true,
     "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
     "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
     "requiredCredentials": [ "password" ],
diff --git a/examples/basic-auth/basicauthrealm.json b/examples/basic-auth/basicauthrealm.json
index b8b2acd..b17e7d8 100644
--- a/examples/basic-auth/basicauthrealm.json
+++ b/examples/basic-auth/basicauthrealm.json
@@ -6,7 +6,6 @@
     "accessCodeLifespanUserAction": 300,
     "ssoSessionIdleTimeout": 600,
     "ssoSessionMaxLifespan": 36000,
-    "passwordCredentialGrantAllowed": true,
     "sslRequired": "external",
     "registrationAllowed": false,
     "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
diff --git a/examples/broker/twitter-authentication/twitter-identity-provider-realm.json b/examples/broker/twitter-authentication/twitter-identity-provider-realm.json
index a450ead..691fd61 100644
--- a/examples/broker/twitter-authentication/twitter-identity-provider-realm.json
+++ b/examples/broker/twitter-authentication/twitter-identity-provider-realm.json
@@ -2,7 +2,6 @@
     "realm": "twitter-identity-provider-realm",
     "enabled": true,
     "sslRequired": "external",
-    "passwordCredentialGrantAllowed": true,
     "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
     "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
     "defaultRoles": [ "user" ],
diff --git a/examples/demo-template/customer-app/src/main/webapp/customers/view.jsp b/examples/demo-template/customer-app/src/main/webapp/customers/view.jsp
index 04a54bb..440a9e9 100755
--- a/examples/demo-template/customer-app/src/main/webapp/customers/view.jsp
+++ b/examples/demo-template/customer-app/src/main/webapp/customers/view.jsp
@@ -33,7 +33,7 @@ Servlet User Principal <b><%=request.getUserPrincipal().getName()%>
     try {
         list = CustomerDatabaseClient.getCustomers(request);
     } catch (CustomerDatabaseClient.Failure failure) {
-        out.println("There was a failure processing request.  You either didn't configure Keycloak properly, or maybe" +
+        out.println("There was a failure processing request.  You either didn't configure Keycloak properly, or maybe " +
                 "you just forgot to secure the database service?");
         out.println("Status from database service invocation was: " + failure.getStatus());
         return;
diff --git a/examples/demo-template/testrealm.json b/examples/demo-template/testrealm.json
index 92643aa..9b83dfa 100755
--- a/examples/demo-template/testrealm.json
+++ b/examples/demo-template/testrealm.json
@@ -6,7 +6,6 @@
     "accessCodeLifespanUserAction": 300,
     "ssoSessionIdleTimeout": 600,
     "ssoSessionMaxLifespan": 36000,
-    "passwordCredentialGrantAllowed": true,
     "sslRequired": "external",
     "registrationAllowed": false,
     "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
diff --git a/examples/fuse/testrealm.json b/examples/fuse/testrealm.json
index f1b21ee..ed112bc 100644
--- a/examples/fuse/testrealm.json
+++ b/examples/fuse/testrealm.json
@@ -6,7 +6,6 @@
     "accessCodeLifespanUserAction": 300,
     "ssoSessionIdleTimeout": 600,
     "ssoSessionMaxLifespan": 36000,
-    "passwordCredentialGrantAllowed": true,
     "sslRequired": "external",
     "registrationAllowed": false,
     "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
diff --git a/examples/multi-tenant/tenant1-realm.json b/examples/multi-tenant/tenant1-realm.json
index 8140b51..9dcaa00 100644
--- a/examples/multi-tenant/tenant1-realm.json
+++ b/examples/multi-tenant/tenant1-realm.json
@@ -7,7 +7,6 @@
     "accessCodeLifespanUserAction": 6000,
     "sslRequired": "external",
     "registrationAllowed": false,
-    "passwordCredentialGrantAllowed": true,
     "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
     "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
     "requiredCredentials": [ "password" ],
diff --git a/examples/multi-tenant/tenant2-realm.json b/examples/multi-tenant/tenant2-realm.json
index 2cd0e61..643d550 100644
--- a/examples/multi-tenant/tenant2-realm.json
+++ b/examples/multi-tenant/tenant2-realm.json
@@ -7,7 +7,6 @@
     "accessCodeLifespanUserAction": 6000,
     "sslRequired": "external",
     "registrationAllowed": false,
-    "passwordCredentialGrantAllowed": true,
     "updateProfileOnInitialSocialLogin": false,
     "privateKey": "MIICXQIBAAKBgQDA0oJjgPQJhnVhOo51KauQGfLLreMFu64OJdKXRnfvAQJQTuKNwc5JrR63l/byyW1B6FgclABF818TtLvMCAkn4EuFwQZCZhg3x3+lFGiB/IzC6UAt4Bi0JQrTbdh83/U97GIPegvaDqiqEiQESEkbCZWxM6sh/34hQaAhCaFpMwIDAQABAoGADwFSvEOQuh0IjWRtKZjwjOo4BrmlbRDJ3rf6x2LoemTttSouXzGxx/H87fSZdxNNuU9HbBHoY4ko4POzmZEWhS0gV6UjM7VArc4YjID6Hh2tfU9vCbuuKZrRs7RjxL70b51WxycKc49PQ4JiR3g04punrpq2UzToPrm66zI+ICECQQD2Jauo6cXXoxHR0QychQf4dityZwFXUoR/8oI/YFiu9XwcWgSMwrFKUdWWNKYmrIRNqCBzrGyeiGdaAjsw41T3AkEAyIpn+XL7bek/uLno5/7ULauf2dFI6MEaHJixQJD7S6Tfo/CGuDK93H4K0GAdjgR0LA0tCnB09yyPCd5NmAYKpQJBAO7+BH4s/PsyScr+vs/6GpMTqXuap6KxbBUO0YfXdEPr9mVQwboqDxmp+0esNua1+n+sDlZBw/TpW+/42p/NGmECQF0sOQyjyH+TfGCmN7j6I7ioYZeA7h/9/9TDeK8n7SmDC8kOanlQUfgMs5eG4JRoK1WANaoA/8cLc9XA7EoynGUCQQDx/Gjg6qyWheVujxjKufH1XkqDNiQHClDRM1ntChCmGq/RmpVmce+mYeOYZ9eofv7UJUCBdamllRlB+056Ld2h",
     "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDA0oJjgPQJhnVhOo51KauQGfLLreMFu64OJdKXRnfvAQJQTuKNwc5JrR63l/byyW1B6FgclABF818TtLvMCAkn4EuFwQZCZhg3x3+lFGiB/IzC6UAt4Bi0JQrTbdh83/U97GIPegvaDqiqEiQESEkbCZWxM6sh/34hQaAhCaFpMwIDAQAB",
diff --git a/examples/saml/testsaml.json b/examples/saml/testsaml.json
index 7cf4a8e..4d9e7d4 100755
--- a/examples/saml/testsaml.json
+++ b/examples/saml/testsaml.json
@@ -3,7 +3,6 @@
     "realm": "saml-demo",
     "enabled": true,
     "sslRequired": "external",
-    "passwordCredentialGrantAllowed": true,
     "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
     "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
     "requiredCredentials": [ "password" ],
diff --git a/export-import/export-import-api/src/main/java/org/keycloak/exportimport/ExportSpi.java b/export-import/export-import-api/src/main/java/org/keycloak/exportimport/ExportSpi.java
index 208cc6a..bcc91b4 100644
--- a/export-import/export-import-api/src/main/java/org/keycloak/exportimport/ExportSpi.java
+++ b/export-import/export-import-api/src/main/java/org/keycloak/exportimport/ExportSpi.java
@@ -10,7 +10,7 @@ import org.keycloak.provider.Spi;
 public class ExportSpi implements Spi {
 
     @Override
-    public boolean isPrivate() {
+    public boolean isInternal() {
         return true;
     }
 
diff --git a/export-import/export-import-api/src/main/java/org/keycloak/exportimport/ImportSpi.java b/export-import/export-import-api/src/main/java/org/keycloak/exportimport/ImportSpi.java
index 90cb6ac..f6f5968 100644
--- a/export-import/export-import-api/src/main/java/org/keycloak/exportimport/ImportSpi.java
+++ b/export-import/export-import-api/src/main/java/org/keycloak/exportimport/ImportSpi.java
@@ -10,7 +10,7 @@ import org.keycloak.provider.Spi;
 public class ImportSpi implements Spi {
 
     @Override
-    public boolean isPrivate() {
+    public boolean isInternal() {
         return true;
     }
 
diff --git a/federation/ldap/src/main/java/org/keycloak/federation/ldap/idm/query/internal/OrCondition.java b/federation/ldap/src/main/java/org/keycloak/federation/ldap/idm/query/internal/OrCondition.java
index 436355b..d898ffd 100644
--- a/federation/ldap/src/main/java/org/keycloak/federation/ldap/idm/query/internal/OrCondition.java
+++ b/federation/ldap/src/main/java/org/keycloak/federation/ldap/idm/query/internal/OrCondition.java
@@ -1,7 +1,5 @@
 package org.keycloak.federation.ldap.idm.query.internal;
 
-import java.util.List;
-
 import org.keycloak.federation.ldap.idm.query.Condition;
 import org.keycloak.federation.ldap.idm.query.QueryParameter;
 
diff --git a/federation/ldap/src/main/java/org/keycloak/federation/ldap/idm/store/ldap/LDAPIdentityStore.java b/federation/ldap/src/main/java/org/keycloak/federation/ldap/idm/store/ldap/LDAPIdentityStore.java
index 7ba1692..3dbfd0a 100644
--- a/federation/ldap/src/main/java/org/keycloak/federation/ldap/idm/store/ldap/LDAPIdentityStore.java
+++ b/federation/ldap/src/main/java/org/keycloak/federation/ldap/idm/store/ldap/LDAPIdentityStore.java
@@ -71,11 +71,12 @@ public class LDAPIdentityStore implements IdentityStore {
     public void add(LDAPObject ldapObject) {
         // id will be assigned by the ldap server
         if (ldapObject.getUuid() != null) {
-            throw new IllegalStateException("Can't add object with already assigned uuid");
+            throw new ModelException("Can't add object with already assigned uuid");
         }
 
         String entryDN = ldapObject.getDn().toString();
-        this.operationManager.createSubContext(entryDN, extractAttributes(ldapObject, true));
+        BasicAttributes ldapAttributes = extractAttributes(ldapObject, true);
+        this.operationManager.createSubContext(entryDN, ldapAttributes);
         ldapObject.setUuid(getEntryIdentifier(ldapObject));
 
         if (logger.isTraceEnabled()) {
@@ -108,20 +109,20 @@ public class LDAPIdentityStore implements IdentityStore {
 
     @Override
     public List<LDAPObject> fetchQueryResults(LDAPIdentityQuery identityQuery) {
+        if (identityQuery.getSorting() != null && !identityQuery.getSorting().isEmpty()) {
+            throw new ModelException("LDAP Identity Store does not yet support sorted queries.");
+        }
+
         List<LDAPObject> results = new ArrayList<>();
 
         try {
-            if (identityQuery.getSorting() != null && !identityQuery.getSorting().isEmpty()) {
-                throw new ModelException("LDAP Identity Store does not yet support sorted queries.");
-            }
-
             String baseDN = identityQuery.getSearchDn();
 
             for (Condition condition : identityQuery.getConditions()) {
 
                 // Check if we are searching by ID
                 String uuidAttrName = getConfig().getUuidLDAPAttributeName();
-                if (condition.getParameter() != null && condition.getParameter().getName().equals(uuidAttrName)) {
+                if (condition.getParameter() != null && condition.getParameter().getName().equalsIgnoreCase(uuidAttrName)) {
                     if (EqualCondition.class.isInstance(condition)) {
                         EqualCondition equalCondition = (EqualCondition) condition;
                         SearchResult search = this.operationManager
@@ -147,7 +148,7 @@ public class LDAPIdentityStore implements IdentityStore {
             }
 
             for (SearchResult result : search) {
-                if (!result.getNameInNamespace().equals(baseDN)) {
+                if (!result.getNameInNamespace().equalsIgnoreCase(baseDN)) {
                     results.add(populateAttributedType(result, identityQuery.getReturningReadOnlyLdapAttributes()));
                 }
             }
@@ -180,8 +181,8 @@ public class LDAPIdentityStore implements IdentityStore {
     public boolean validatePassword(LDAPObject user, String password) {
         String userDN = user.getDn().toString();
 
-        if (logger.isDebugEnabled()) {
-            logger.debugf("Using DN [%s] for authentication of user", userDN);
+        if (logger.isTraceEnabled()) {
+            logger.tracef("Using DN [%s] for authentication of user", userDN);
         }
 
         if (operationManager.authenticate(userDN, password)) {
@@ -258,7 +259,9 @@ public class LDAPIdentityStore implements IdentityStore {
         filter.append(getObjectClassesFilter(identityQuery.getObjectClasses()));
         filter.append(")");
 
-        logger.infof("Using filter for LDAP search: %s", filter);
+        if (logger.isTraceEnabled()) {
+            logger.tracef("Using filter for LDAP search: %s . Searching in DN: %s", filter, identityQuery.getSearchDn());
+        }
         return filter;
     }
 
@@ -278,7 +281,7 @@ public class LDAPIdentityStore implements IdentityStore {
 
         QueryParameter queryParameter = condition.getParameter();
 
-        if (!getConfig().getUuidLDAPAttributeName().equals(queryParameter.getName())) {
+        if (!getConfig().getUuidLDAPAttributeName().equalsIgnoreCase(queryParameter.getName())) {
             String attributeName = queryParameter.getName();
 
             if (attributeName != null) {
@@ -377,10 +380,6 @@ public class LDAPIdentityStore implements IdentityStore {
             ldapObject.setDn(dn);
             ldapObject.setRdnAttributeName(dn.getFirstRdnAttrName());
 
-            if (logger.isTraceEnabled()) {
-                logger.tracef("Populating LDAP Object from DN [%s]", entryDN);
-            }
-
             NamingEnumeration<? extends Attribute> ldapAttributes = attributes.getAll();
 
             // Exact name of attributes might be different
@@ -400,7 +399,7 @@ public class LDAPIdentityStore implements IdentityStore {
 
                 String ldapAttributeName = ldapAttribute.getID();
 
-                if (ldapAttributeName.toLowerCase().equals(getConfig().getUuidLDAPAttributeName().toLowerCase())) {
+                if (ldapAttributeName.equalsIgnoreCase(getConfig().getUuidLDAPAttributeName())) {
                     Object uuidValue = ldapAttribute.get();
                     ldapObject.setUuid(this.operationManager.decodeEntryUUID(uuidValue));
                 } else {
@@ -411,12 +410,9 @@ public class LDAPIdentityStore implements IdentityStore {
                         attrValues.add(attrVal);
                     }
 
-                    if (ldapAttributeName.toLowerCase().equals(LDAPConstants.OBJECT_CLASS)) {
+                    if (ldapAttributeName.equalsIgnoreCase(LDAPConstants.OBJECT_CLASS)) {
                         ldapObject.setObjectClasses(attrValues);
                     } else {
-                        if (logger.isTraceEnabled()) {
-                            logger.tracef("Populating ldap attribute [%s] with value [%s] for DN [%s].", ldapAttributeName, attrValues.toString(), entryDN);
-                        }
                         if (attrValues.size() == 1) {
                             ldapObject.setAttribute(ldapAttributeName, attrValues.iterator().next());
                         } else {
@@ -430,6 +426,9 @@ public class LDAPIdentityStore implements IdentityStore {
                 }
             }
 
+            if (logger.isTraceEnabled()) {
+                logger.tracef("Found ldap object [%s] and populated with the attributes [%s]. Read-only attributes are [%s]", ldapObject.getDn().toString(), ldapObject.getAttributes(), ldapObject.getReadOnlyAttributeNames());
+            }
             return ldapObject;
 
         } catch (Exception e) {
@@ -444,7 +443,7 @@ public class LDAPIdentityStore implements IdentityStore {
         for (Map.Entry<String, Object> attrEntry : ldapObject.getAttributes().entrySet()) {
             String attrName = attrEntry.getKey();
             Object attrValue = attrEntry.getValue();
-            if (!ldapObject.getReadOnlyAttributeNames().contains(attrName) && (isCreate || !ldapObject.getRdnAttributeName().equals(attrName))) {
+            if (!ldapObject.getReadOnlyAttributeNames().contains(attrName) && (isCreate || !ldapObject.getRdnAttributeName().equalsIgnoreCase(attrName))) {
 
                 if (String.class.isInstance(attrValue)) {
                     if (attrValue.toString().trim().length() == 0) {
@@ -461,7 +460,7 @@ public class LDAPIdentityStore implements IdentityStore {
                 } else if (attrValue == null || attrValue.toString().trim().length() == 0) {
                     entryAttributes.put(attrName, LDAPConstants.EMPTY_ATTRIBUTE_VALUE);
                 } else {
-                    throw new IllegalArgumentException("Unexpected type of value of argument " + attrName + ". Value is " + attrValue);
+                    throw new ModelException("Unexpected type of value of argument " + attrName + ". Value is " + attrValue);
                 }
             }
         }
@@ -473,10 +472,10 @@ public class LDAPIdentityStore implements IdentityStore {
             for (String objectClassValue : ldapObject.getObjectClasses()) {
                 objectClassAttribute.add(objectClassValue);
 
-                if (objectClassValue.equals(LDAPConstants.GROUP_OF_NAMES)
-                        || objectClassValue.equals(LDAPConstants.GROUP_OF_ENTRIES)
-                        || objectClassValue.equals(LDAPConstants.GROUP_OF_UNIQUE_NAMES)) {
-                    entryAttributes.put(LDAPConstants.MEMBER, LDAPConstants.EMPTY_ATTRIBUTE_VALUE);
+                if (objectClassValue.equalsIgnoreCase(LDAPConstants.GROUP_OF_NAMES)
+                        || objectClassValue.equalsIgnoreCase(LDAPConstants.GROUP_OF_ENTRIES)
+                        || objectClassValue.equalsIgnoreCase(LDAPConstants.GROUP_OF_UNIQUE_NAMES)) {
+                    entryAttributes.put(LDAPConstants.MEMBER, LDAPConstants.EMPTY_MEMBER_ATTRIBUTE_VALUE);
                 }
             }
 
diff --git a/federation/ldap/src/main/java/org/keycloak/federation/ldap/idm/store/ldap/LDAPOperationManager.java b/federation/ldap/src/main/java/org/keycloak/federation/ldap/idm/store/ldap/LDAPOperationManager.java
index c097e4e..8d934f3 100644
--- a/federation/ldap/src/main/java/org/keycloak/federation/ldap/idm/store/ldap/LDAPOperationManager.java
+++ b/federation/ldap/src/main/java/org/keycloak/federation/ldap/idm/store/ldap/LDAPOperationManager.java
@@ -128,8 +128,8 @@ public class LDAPOperationManager {
             execute(new LdapOperation<SearchResult>() {
                 @Override
                 public SearchResult execute(LdapContext context) throws NamingException {
-                    if (logger.isDebugEnabled()) {
-                        logger.debugf("Removing entry with DN [%s]", entryDn);
+                    if (logger.isTraceEnabled()) {
+                        logger.tracef("Removing entry with DN [%s]", entryDn);
                     }
                     destroySubcontext(context, entryDn);
                     return null;
@@ -357,8 +357,8 @@ public class LDAPOperationManager {
 
     public void modifyAttributes(final String dn, final ModificationItem[] mods) {
         try {
-            if (logger.isDebugEnabled()) {
-                logger.debugf("Modifying attributes for entry [%s]: [", dn);
+            if (logger.isTraceEnabled()) {
+                logger.tracef("Modifying attributes for entry [%s]: [", dn);
 
                 for (ModificationItem item : mods) {
                     Object values;
@@ -369,10 +369,10 @@ public class LDAPOperationManager {
                         values = "No values";
                     }
 
-                    logger.debugf("  Op [%s]: %s = %s", item.getModificationOp(), item.getAttribute().getID(), values);
+                    logger.tracef("  Op [%s]: %s = %s", item.getModificationOp(), item.getAttribute().getID(), values);
                 }
 
-                logger.debugf("]");
+                logger.tracef("]");
             }
 
             execute(new LdapOperation<Void>() {
@@ -389,18 +389,18 @@ public class LDAPOperationManager {
 
     public void createSubContext(final String name, final Attributes attributes) {
         try {
-            if (logger.isDebugEnabled()) {
-                logger.debugf("Creating entry [%s] with attributes: [", name);
+            if (logger.isTraceEnabled()) {
+                logger.tracef("Creating entry [%s] with attributes: [", name);
 
                 NamingEnumeration<? extends Attribute> all = attributes.getAll();
 
                 while (all.hasMore()) {
                     Attribute attribute = all.next();
 
-                    logger.debugf("  %s = %s", attribute.getID(), attribute.get());
+                    logger.tracef("  %s = %s", attribute.getID(), attribute.get());
                 }
 
-                logger.debugf("]");
+                logger.tracef("]");
             }
 
             execute(new LdapOperation<Void>() {
@@ -513,7 +513,6 @@ public class LDAPOperationManager {
             context = createLdapContext();
             return operation.execute(context);
         } catch (NamingException ne) {
-            logger.error("Could not create Ldap context or operation execution error.", ne);
             throw ne;
         } finally {
             if (context != null) {
diff --git a/federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPConfig.java b/federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPConfig.java
index 983de98..3317b9d 100644
--- a/federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPConfig.java
+++ b/federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPConfig.java
@@ -1,8 +1,6 @@
 package org.keycloak.federation.ldap;
 
-import java.util.Arrays;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Properties;
@@ -50,7 +48,14 @@ public class LDAPConfig {
     }
 
     public String getUsersDn() {
-        return config.get(LDAPConstants.USERS_DN);
+        String usersDn = config.get(LDAPConstants.USERS_DN);
+
+        if (usersDn == null) {
+            // Just for the backwards compatibility 1.2 -> 1.3 . Should be removed later.
+            usersDn = config.get("userDnSuffix");
+        }
+
+        return usersDn;
     }
 
     public Collection<String> getUserObjectClasses() {
@@ -103,31 +108,13 @@ public class LDAPConfig {
         if (uuidAttrName == null) {
             // Differences of unique attribute among various vendors
             String vendor = getVendor();
-            if (vendor != null) {
-                switch (vendor) {
-                    case LDAPConstants.VENDOR_RHDS:
-                        uuidAttrName = "nsuniqueid";
-                        break;
-                    case LDAPConstants.VENDOR_TIVOLI:
-                        uuidAttrName = "uniqueidentifier";
-                        break;
-                    case LDAPConstants.VENDOR_NOVELL_EDIRECTORY:
-                        uuidAttrName = "guid";
-                        break;
-                    case LDAPConstants.VENDOR_ACTIVE_DIRECTORY:
-                        uuidAttrName = LDAPConstants.OBJECT_GUID;
-                }
-            }
-
-            if (uuidAttrName == null) {
-                uuidAttrName = LDAPConstants.ENTRY_UUID;
-            }
+            uuidAttrName = LDAPConstants.getUuidAttributeName(vendor);
         }
 
         return uuidAttrName;
     }
 
-    // TODO: Remove and use mapper instead
+    // TODO: Remove and use mapper instead?
     public boolean isUserAccountControlsAfterPasswordUpdate() {
         String userAccountCtrls = config.get(LDAPConstants.USER_ACCOUNT_CONTROLS_AFTER_PASSWORD_UPDATE);
         return userAccountCtrls==null ? false : Boolean.parseBoolean(userAccountCtrls);
@@ -150,6 +137,12 @@ public class LDAPConfig {
         String rdn = config.get(LDAPConstants.RDN_LDAP_ATTRIBUTE);
         if (rdn == null) {
             rdn = getUsernameLdapAttribute();
+
+            if (rdn.equalsIgnoreCase(LDAPConstants.SAM_ACCOUNT_NAME)) {
+                // Just for the backwards compatibility 1.2 -> 1.3 . Should be removed later.
+                rdn = LDAPConstants.CN;
+            }
+
         }
         return rdn;
     }
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 4524d48..7ad05d3 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
@@ -308,8 +308,7 @@ public class LDAPFederationProvider implements UserFederationProvider {
 
     @Override
     public void preRemove(RealmModel realm, RoleModel role) {
-        // complete I don't think we have to do anything here
-        // TODO: requires implementation... Maybe mappers callback to ensure role deletion propagated to LDAP by RoleLDAPFederationMapper
+        // TODO: Maybe mappers callback to ensure role deletion propagated to LDAP by RoleLDAPFederationMapper?
     }
 
     public boolean validPassword(RealmModel realm, UserModel user, String password) {
diff --git a/federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPFederationProviderFactory.java b/federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPFederationProviderFactory.java
index c020f51..876a96d 100755
--- a/federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPFederationProviderFactory.java
+++ b/federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPFederationProviderFactory.java
@@ -41,7 +41,7 @@ import java.util.Set;
  */
 public class LDAPFederationProviderFactory extends UserFederationEventAwareProviderFactory {
     private static final Logger logger = Logger.getLogger(LDAPFederationProviderFactory.class);
-    public static final String PROVIDER_NAME = "ldap";
+    public static final String PROVIDER_NAME = LDAPConstants.LDAP_PROVIDER;
 
     private LDAPIdentityStoreRegistry ldapStoreRegistry;
 
@@ -79,7 +79,7 @@ public class LDAPFederationProviderFactory extends UserFederationEventAwareProvi
 
     // Best effort to create appropriate mappers according to our LDAP config
     @Override
-    protected void onProviderModelCreated(RealmModel realm, UserFederationProviderModel newProviderModel) {
+    public void onProviderModelCreated(RealmModel realm, UserFederationProviderModel newProviderModel) {
         LDAPConfig ldapConfig = new LDAPConfig(newProviderModel.getConfig());
 
         boolean activeDirectory = ldapConfig.isActiveDirectory();
@@ -94,12 +94,42 @@ public class LDAPFederationProviderFactory extends UserFederationEventAwareProvi
                 UserAttributeLDAPFederationMapper.READ_ONLY, readOnly);
         realm.addUserFederationMapper(mapperModel);
 
-        // For AD deployments with sAMAccountName is probably more common to map "cn" to full name of user
-        if (activeDirectory && usernameLdapAttribute.equalsIgnoreCase(LDAPConstants.SAM_ACCOUNT_NAME)) {
-            mapperModel = KeycloakModelUtils.createUserFederationMapperModel("full name", newProviderModel.getId(), FullNameLDAPFederationMapperFactory.PROVIDER_ID,
-                    FullNameLDAPFederationMapper.LDAP_FULL_NAME_ATTRIBUTE, LDAPConstants.CN,
-                    UserAttributeLDAPFederationMapper.READ_ONLY, readOnly);
-            realm.addUserFederationMapper(mapperModel);
+        // CN is typically used as RDN for Active Directory deployments
+        if (ldapConfig.getRdnLdapAttribute().equalsIgnoreCase(LDAPConstants.CN)) {
+
+            if (usernameLdapAttribute.equalsIgnoreCase(LDAPConstants.CN)) {
+
+                // For AD deployments with "cn" as username, we will map "givenName" to first name
+                mapperModel = KeycloakModelUtils.createUserFederationMapperModel("first name", newProviderModel.getId(), UserAttributeLDAPFederationMapperFactory.PROVIDER_ID,
+                        UserAttributeLDAPFederationMapper.USER_MODEL_ATTRIBUTE, UserModel.FIRST_NAME,
+                        UserAttributeLDAPFederationMapper.LDAP_ATTRIBUTE, LDAPConstants.GIVENNAME,
+                        UserAttributeLDAPFederationMapper.READ_ONLY, readOnly);
+                realm.addUserFederationMapper(mapperModel);
+
+            } else {
+                if (editMode == UserFederationProvider.EditMode.WRITABLE) {
+
+                    // For AD deployments with "sAMAccountName" as username and writable, we need to map "cn" as username as well (this is needed so we can register new users from KC into LDAP) and we will map "givenName" to first name.
+                    mapperModel = KeycloakModelUtils.createUserFederationMapperModel("first name", newProviderModel.getId(), UserAttributeLDAPFederationMapperFactory.PROVIDER_ID,
+                            UserAttributeLDAPFederationMapper.USER_MODEL_ATTRIBUTE, UserModel.FIRST_NAME,
+                            UserAttributeLDAPFederationMapper.LDAP_ATTRIBUTE, LDAPConstants.GIVENNAME,
+                            UserAttributeLDAPFederationMapper.READ_ONLY, readOnly);
+                    realm.addUserFederationMapper(mapperModel);
+
+                    mapperModel = KeycloakModelUtils.createUserFederationMapperModel("username-cn", newProviderModel.getId(), UserAttributeLDAPFederationMapperFactory.PROVIDER_ID,
+                            UserAttributeLDAPFederationMapper.USER_MODEL_ATTRIBUTE, UserModel.USERNAME,
+                            UserAttributeLDAPFederationMapper.LDAP_ATTRIBUTE, LDAPConstants.CN,
+                            UserAttributeLDAPFederationMapper.READ_ONLY, readOnly);
+                    realm.addUserFederationMapper(mapperModel);
+                } else {
+
+                    // For read-only LDAP, we map "cn" as full name
+                    mapperModel = KeycloakModelUtils.createUserFederationMapperModel("full name", newProviderModel.getId(), FullNameLDAPFederationMapperFactory.PROVIDER_ID,
+                            FullNameLDAPFederationMapper.LDAP_FULL_NAME_ATTRIBUTE, LDAPConstants.CN,
+                            UserAttributeLDAPFederationMapper.READ_ONLY, readOnly);
+                    realm.addUserFederationMapper(mapperModel);
+                }
+            }
         } else {
             mapperModel = KeycloakModelUtils.createUserFederationMapperModel("first name", newProviderModel.getId(), UserAttributeLDAPFederationMapperFactory.PROVIDER_ID,
                     UserAttributeLDAPFederationMapper.USER_MODEL_ATTRIBUTE, UserModel.FIRST_NAME,
diff --git a/federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPIdentityStoreRegistry.java b/federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPIdentityStoreRegistry.java
index 97f347b..c9d7bb2 100644
--- a/federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPIdentityStoreRegistry.java
+++ b/federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPIdentityStoreRegistry.java
@@ -24,7 +24,7 @@ public class LDAPIdentityStoreRegistry {
         // Ldap config might have changed for the realm. In this case, we must re-initialize
         Map<String, String> config = model.getConfig();
         if (context == null || !config.equals(context.config)) {
-            logLDAPConfig(model.getId(), config);
+            logLDAPConfig(model.getDisplayName(), config);
 
             LDAPIdentityStore store = createLdapIdentityStore(config);
             context = new LDAPIdentityStoreContext(config, store);
@@ -34,10 +34,10 @@ public class LDAPIdentityStoreRegistry {
     }
 
     // Don't log LDAP password
-    private void logLDAPConfig(String fedProviderId, Map<String, String> ldapConfig) {
+    private void logLDAPConfig(String fedProviderDisplayName, Map<String, String> ldapConfig) {
         Map<String, String> copy = new HashMap<String, String>(ldapConfig);
         copy.remove(LDAPConstants.BIND_CREDENTIAL);
-        logger.infof("Creating new LDAP based partition manager for the Federation provider: " + fedProviderId + ", LDAP Configuration: " + copy);
+        logger.infof("Creating new LDAP based partition manager for the Federation provider: " + fedProviderDisplayName + ", LDAP Configuration: " + copy);
     }
 
     /**
@@ -55,23 +55,6 @@ public class LDAPIdentityStoreRegistry {
         checkSystemProperty("com.sun.jndi.ldap.connect.pool.protocol", "plain");
         checkSystemProperty("com.sun.jndi.ldap.connect.pool.debug", "off");
 
-        /*String ldapLoginNameMapping = ldapConfig.get(LDAPConstants.USERNAME_LDAP_ATTRIBUTE);
-        if (ldapLoginNameMapping == null) {
-            ldapLoginNameMapping = activeDirectory ? LDAPConstants.CN : LDAPConstants.UID;
-        }
-
-        String ldapFirstNameMapping = activeDirectory ?  "givenName" : LDAPConstants.CN;
-        String createTimestampMapping = activeDirectory ? "whenCreated" : LDAPConstants.CREATE_TIMESTAMP;
-        String modifyTimestampMapping = activeDirectory ? "whenChanged" : LDAPConstants.MODIFY_TIMESTAMP;
-        String[] userObjectClasses = getUserObjectClasses(ldapConfig);  */
-
-
-/*        if (activeDirectory && ldapLoginNameMapping.equals("sAMAccountName")) {
-            ldapUserMappingConfig.setBindingDnPropertyName("fullName");
-            ldapUserMappingConfig.addAttributeMapping("fullName", LDAPConstants.CN);
-            logger.infof("Using 'cn' attribute for DN of user and 'sAMAccountName' for username");
-        }    */
-
         return new LDAPIdentityStore(cfg);
     }
 
diff --git a/federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPUtils.java b/federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPUtils.java
index c350818..396d997 100755
--- a/federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPUtils.java
+++ b/federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPUtils.java
@@ -45,16 +45,6 @@ public class LDAPUtils {
         return ldapUser;
     }
 
-    public static void removeAllUsers(LDAPFederationProvider ldapProvider, RealmModel realm) {
-        LDAPIdentityStore ldapStore = ldapProvider.getLdapIdentityStore();
-        LDAPIdentityQuery ldapQuery = LDAPUtils.createQueryForUserSearch(ldapProvider, realm);
-        List<LDAPObject> allUsers = ldapQuery.getResultList();
-
-        for (LDAPObject ldapUser : allUsers) {
-            ldapStore.remove(ldapUser);
-        }
-    }
-
     public static LDAPIdentityQuery createQueryForUserSearch(LDAPFederationProvider ldapProvider, RealmModel realm) {
         LDAPIdentityQuery ldapQuery = new LDAPIdentityQuery(ldapProvider);
         LDAPConfig config = ldapProvider.getLdapIdentityStore().getConfig();
diff --git a/federation/ldap/src/main/java/org/keycloak/federation/ldap/mappers/FullNameLDAPFederationMapper.java b/federation/ldap/src/main/java/org/keycloak/federation/ldap/mappers/FullNameLDAPFederationMapper.java
index 109b0b0..7466778 100644
--- a/federation/ldap/src/main/java/org/keycloak/federation/ldap/mappers/FullNameLDAPFederationMapper.java
+++ b/federation/ldap/src/main/java/org/keycloak/federation/ldap/mappers/FullNameLDAPFederationMapper.java
@@ -1,24 +1,19 @@
 package org.keycloak.federation.ldap.mappers;
 
 import java.util.HashSet;
-import java.util.List;
 import java.util.Set;
 
 import org.keycloak.federation.ldap.LDAPFederationProvider;
-import org.keycloak.federation.ldap.LDAPUtils;
 import org.keycloak.federation.ldap.idm.model.LDAPObject;
 import org.keycloak.federation.ldap.idm.query.Condition;
 import org.keycloak.federation.ldap.idm.query.QueryParameter;
 import org.keycloak.federation.ldap.idm.query.internal.EqualCondition;
 import org.keycloak.federation.ldap.idm.query.internal.LDAPIdentityQuery;
-import org.keycloak.mappers.UserFederationMapper;
-import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.LDAPConstants;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserFederationMapperModel;
 import org.keycloak.models.UserFederationProvider;
 import org.keycloak.models.UserModel;
-import org.keycloak.provider.ProviderConfigProperty;
 
 /**
  * Mapper useful for the LDAP deployments when some attribute (usually CN) is mapped to full name of user
@@ -35,7 +30,7 @@ public class FullNameLDAPFederationMapper extends AbstractLDAPFederationMapper {
         String ldapFullNameAttrName = getLdapFullNameAttrName(mapperModel);
         String fullName = ldapUser.getAttributeAsString(ldapFullNameAttrName);
         fullName = fullName.trim();
-        if (fullName != null) {
+        if (fullName != null && !fullName.trim().isEmpty()) {
             int lastSpaceIndex = fullName.lastIndexOf(" ");
             if (lastSpaceIndex == -1) {
                 user.setLastName(fullName);
@@ -130,7 +125,7 @@ public class FullNameLDAPFederationMapper extends AbstractLDAPFederationMapper {
             fullName = firstNameCondition.getValue() + " " + lastNameCondition.getValue();
         } else if (firstNameCondition != null) {
             fullName = (String) firstNameCondition.getValue();
-        } else if (firstNameCondition != null) {
+        } else if (lastNameCondition != null) {
             fullName = (String) lastNameCondition.getValue();
         } else {
             return;
diff --git a/federation/ldap/src/main/java/org/keycloak/federation/ldap/mappers/RoleLDAPFederationMapper.java b/federation/ldap/src/main/java/org/keycloak/federation/ldap/mappers/RoleLDAPFederationMapper.java
index 763ca3c..165309c 100644
--- a/federation/ldap/src/main/java/org/keycloak/federation/ldap/mappers/RoleLDAPFederationMapper.java
+++ b/federation/ldap/src/main/java/org/keycloak/federation/ldap/mappers/RoleLDAPFederationMapper.java
@@ -1,14 +1,11 @@
 package org.keycloak.federation.ldap.mappers;
 
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 import java.util.TreeSet;
 
-import javax.naming.directory.SearchControls;
-
 import org.jboss.logging.Logger;
 import org.keycloak.federation.ldap.LDAPFederationProvider;
 import org.keycloak.federation.ldap.idm.model.LDAPDn;
@@ -82,8 +79,7 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper {
                 RoleContainerModel roleContainer = getTargetRoleContainer(mapperModel, realm);
                 RoleModel role = roleContainer.getRole(roleName);
 
-                // TODO: debug
-                logger.infof("Granting role [%s] to user [%s] during import from LDAP", roleName, user.getUsername());
+                logger.debugf("Granting role [%s] to user [%s] during import from LDAP", roleName, user.getUsername());
                 user.grantRole(role);
             }
         }
@@ -97,6 +93,8 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper {
     // Sync roles from LDAP tree and create them in local Keycloak DB (if they don't exist here yet)
     protected void syncRolesFromLDAP(UserFederationMapperModel mapperModel, LDAPFederationProvider ldapProvider, RealmModel realm) {
         if (!rolesSyncedModels.contains(mapperModel.getId())) {
+            logger.debugf("Syncing roles from LDAP into Keycloak DB. Mapper is [%s], LDAP provider is [%s]", mapperModel.getName(), ldapProvider.getModel().getDisplayName());
+
             LDAPIdentityQuery ldapQuery = createRoleQuery(mapperModel, ldapProvider);
 
             // Send query
@@ -108,7 +106,6 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper {
                 String roleName = ldapRole.getAttributeAsString(rolesRdnAttr);
 
                 if (roleContainer.getRole(roleName) == null) {
-                    // TODO: rather change to debug
                     logger.infof("Syncing role [%s] from LDAP to keycloak DB", roleName);
                     roleContainer.addRole(roleName);
                 }
@@ -127,7 +124,7 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper {
         String rolesDn = getRolesDn(mapperModel);
         ldapQuery.setSearchDn(rolesDn);
 
-        Collection<String> roleObjectClasses = getRoleObjectClasses(mapperModel);
+        Collection<String> roleObjectClasses = getRoleObjectClasses(mapperModel, ldapProvider);
         ldapQuery.addObjectClasses(roleObjectClasses);
 
         String rolesRdnAttr = getRoleNameLdapAttribute(mapperModel);
@@ -145,11 +142,11 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper {
         } else {
             String clientId = mapperModel.getConfig().get(CLIENT_ID);
             if (clientId == null) {
-                throw new IllegalStateException("Using client roles mapping is requested, but parameter client.id not found!");
+                throw new ModelException("Using client roles mapping is requested, but parameter client.id not found!");
             }
             ClientModel client = realm.getClientByClientId(clientId);
             if (client == null) {
-                throw new IllegalStateException("Can't found requested client with clientId: " + clientId);
+                throw new ModelException("Can't found requested client with clientId: " + clientId);
             }
             return client;
         }
@@ -158,7 +155,7 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper {
     protected String getRolesDn(UserFederationMapperModel mapperModel) {
         String rolesDn = mapperModel.getConfig().get(ROLES_DN);
         if (rolesDn == null) {
-            throw new IllegalStateException("Roles DN is null! Check your configuration");
+            throw new ModelException("Roles DN is null! Check your configuration");
         }
         return rolesDn;
     }
@@ -173,10 +170,11 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper {
         return membershipAttrName!=null ? membershipAttrName : LDAPConstants.MEMBER;
     }
 
-    protected Collection<String> getRoleObjectClasses(UserFederationMapperModel mapperModel) {
+    protected Collection<String> getRoleObjectClasses(UserFederationMapperModel mapperModel, LDAPFederationProvider ldapProvider) {
         String objectClasses = mapperModel.getConfig().get(ROLE_OBJECT_CLASSES);
         if (objectClasses == null) {
-            objectClasses = "groupOfNames";
+            // For Active directory, the default is 'group' . For other servers 'groupOfNames'
+            objectClasses = ldapProvider.getLdapIdentityStore().getConfig().isActiveDirectory() ? LDAPConstants.GROUP : LDAPConstants.GROUP_OF_NAMES;
         }
         String[] objClasses = objectClasses.split(",");
 
@@ -192,26 +190,25 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper {
 
     private Mode getMode(UserFederationMapperModel mapperModel) {
         String modeString = mapperModel.getConfig().get(MODE);
-        if (modeString == null || modeString.trim().length() == 0) {
-            return Mode.LDAP_ONLY;
+        if (modeString == null || modeString.isEmpty()) {
+            throw new ModelException("Mode is missing! Check your configuration");
         }
 
         return Enum.valueOf(Mode.class, modeString.toUpperCase());
     }
 
-    protected LDAPObject createLDAPRole(UserFederationMapperModel mapperModel, String roleName, LDAPFederationProvider ldapProvider) {
+    public LDAPObject createLDAPRole(UserFederationMapperModel mapperModel, String roleName, LDAPFederationProvider ldapProvider) {
         LDAPObject ldapObject = new LDAPObject();
         String roleNameAttribute = getRoleNameLdapAttribute(mapperModel);
         ldapObject.setRdnAttributeName(roleNameAttribute);
-        ldapObject.setObjectClasses(getRoleObjectClasses(mapperModel));
+        ldapObject.setObjectClasses(getRoleObjectClasses(mapperModel, ldapProvider));
         ldapObject.setAttribute(roleNameAttribute, roleName);
 
         LDAPDn roleDn = LDAPDn.fromString(getRolesDn(mapperModel));
         roleDn.addFirst(roleNameAttribute, roleName);
         ldapObject.setDn(roleDn);
 
-        // TODO: debug
-        logger.infof("Creating role to [%s] to LDAP with DN [%s]", roleName, roleDn.toString());
+        logger.infof("Creating role [%s] to LDAP with DN [%s]", roleName, roleDn.toString());
         ldapProvider.getLdapIdentityStore().add(ldapObject);
         return ldapObject;
     }
@@ -233,9 +230,9 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper {
         Set<String> memberships = getExistingMemberships(mapperModel, ldapRole);
         memberships.remove(ldapUser.getDn().toString());
 
-        // Some membership placeholder needs to be always here as "member" is mandatory attribute on some LDAP servers
-        if (memberships.size() == 0) {
-            memberships.add(LDAPConstants.EMPTY_ATTRIBUTE_VALUE);
+        // Some membership placeholder needs to be always here as "member" is mandatory attribute on some LDAP servers. But on active directory! (Empty membership is not allowed here)
+        if (memberships.size() == 0 && !ldapProvider.getLdapIdentityStore().getConfig().isActiveDirectory()) {
+            memberships.add(LDAPConstants.EMPTY_MEMBER_ATTRIBUTE_VALUE);
         }
 
         ldapRole.setAttribute(getMembershipLdapAttribute(mapperModel), memberships);
@@ -280,23 +277,6 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper {
         return ldapQuery.getResultList();
     }
 
-    protected Set<RoleModel> getLDAPRoleMappingsConverted(UserFederationMapperModel mapperModel, LDAPFederationProvider ldapProvider, LDAPObject ldapUser, RoleContainerModel roleContainer) {
-        List<LDAPObject> ldapRoles = getLDAPRoleMappings(mapperModel, ldapProvider, ldapUser);
-
-        Set<RoleModel> roles = new HashSet<RoleModel>();
-        String roleNameLdapAttr = getRoleNameLdapAttribute(mapperModel);
-        for (LDAPObject role : ldapRoles) {
-            String roleName = role.getAttributeAsString(roleNameLdapAttr);
-            RoleModel modelRole = roleContainer.getRole(roleName);
-            if (modelRole == null) {
-                // Add role to local DB
-                modelRole = roleContainer.addRole(roleName);
-            }
-            roles.add(modelRole);
-        }
-        return roles;
-    }
-
     @Override
     public UserModel proxy(UserFederationMapperModel mapperModel, LDAPFederationProvider ldapProvider, LDAPObject ldapUser, UserModel delegate, RealmModel realm) {
         final Mode mode = getMode(mapperModel);
@@ -323,6 +303,9 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper {
         private final RealmModel realm;
         private final Mode mode;
 
+        // Avoid loading role mappings from LDAP more times per-request
+        private Set<RoleModel> cachedLDAPRoleMappings;
+
         public LDAPRoleMappingsUserDelegate(UserModel user, UserFederationMapperModel mapperModel, LDAPFederationProvider ldapProvider, LDAPObject ldapUser,
                                             RealmModel realm, Mode mode) {
             super(user);
@@ -387,6 +370,7 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper {
                 if (role.getContainer().equals(roleContainer)) {
 
                     // We need to create new role mappings in LDAP
+                    cachedLDAPRoleMappings = null;
                     addRoleMappingInLDAP(mapperModel, role.getName(), ldapProvider, ldapUser);
                 } else {
                     super.grantRole(role);
@@ -417,6 +401,30 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper {
             return modelRoleMappings;
         }
 
+        protected Set<RoleModel> getLDAPRoleMappingsConverted(UserFederationMapperModel mapperModel, LDAPFederationProvider ldapProvider, LDAPObject ldapUser, RoleContainerModel roleContainer) {
+            if (cachedLDAPRoleMappings != null) {
+                return new HashSet<>(cachedLDAPRoleMappings);
+            }
+
+            List<LDAPObject> ldapRoles = getLDAPRoleMappings(mapperModel, ldapProvider, ldapUser);
+
+            Set<RoleModel> roles = new HashSet<RoleModel>();
+            String roleNameLdapAttr = getRoleNameLdapAttribute(mapperModel);
+            for (LDAPObject role : ldapRoles) {
+                String roleName = role.getAttributeAsString(roleNameLdapAttr);
+                RoleModel modelRole = roleContainer.getRole(roleName);
+                if (modelRole == null) {
+                    // Add role to local DB
+                    modelRole = roleContainer.addRole(roleName);
+                }
+                roles.add(modelRole);
+            }
+
+            cachedLDAPRoleMappings = new HashSet<>(roles);
+
+            return roles;
+        }
+
         @Override
         public void deleteRoleMapping(RoleModel role) {
             RoleContainerModel roleContainer = getTargetRoleContainer(mapperModel, realm);
@@ -440,6 +448,7 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper {
                         throw new ModelException("Not possible to delete LDAP role mappings as mapper mode is READ_ONLY");
                     } else {
                         // Delete ldap role mappings
+                        cachedLDAPRoleMappings = null;
                         deleteRoleMappingInLDAP(mapperModel, ldapProvider, ldapUser, ldapRole);
                     }
                 }
diff --git a/federation/ldap/src/main/java/org/keycloak/federation/ldap/mappers/RoleLDAPFederationMapperFactory.java b/federation/ldap/src/main/java/org/keycloak/federation/ldap/mappers/RoleLDAPFederationMapperFactory.java
index b02e2d3..2d6d24c 100644
--- a/federation/ldap/src/main/java/org/keycloak/federation/ldap/mappers/RoleLDAPFederationMapperFactory.java
+++ b/federation/ldap/src/main/java/org/keycloak/federation/ldap/mappers/RoleLDAPFederationMapperFactory.java
@@ -1,25 +1,33 @@
 package org.keycloak.federation.ldap.mappers;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.Map;
 
+import org.jboss.logging.Logger;
+import org.keycloak.federation.ldap.LDAPFederationProvider;
 import org.keycloak.mappers.MapperConfigValidationException;
 import org.keycloak.mappers.UserFederationMapper;
-import org.keycloak.models.ClientModel;
 import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
 import org.keycloak.models.LDAPConstants;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserFederationMapperModel;
+import org.keycloak.models.UserFederationProvider;
+import org.keycloak.models.UserFederationProviderFactory;
+import org.keycloak.models.UserFederationProviderModel;
+import org.keycloak.models.utils.KeycloakModelUtils;
 import org.keycloak.provider.ProviderConfigProperty;
+import org.keycloak.provider.ProviderEvent;
+import org.keycloak.provider.ProviderEventListener;
 
 /**
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
  */
 public class RoleLDAPFederationMapperFactory extends AbstractLDAPFederationMapperFactory {
 
+    private static final Logger logger = Logger.getLogger(RoleLDAPFederationMapperFactory.class);
+
     public static final String PROVIDER_ID = "role-ldap-mapper";
 
     protected static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
@@ -40,8 +48,8 @@ public class RoleLDAPFederationMapperFactory extends AbstractLDAPFederationMappe
         configProperties.add(membershipLDAPAttribute);
 
         ProviderConfigProperty roleObjectClasses = createConfigProperty(RoleLDAPFederationMapper.ROLE_OBJECT_CLASSES, "Role Object Classes",
-                "Object classes of the role object divided by comma (if more values needed). In typical LDAP deployment it could be 'groupOfNames' or 'groupOfEntries' ",
-                ProviderConfigProperty.STRING_TYPE, LDAPConstants.GROUP_OF_NAMES);
+                "Object class (or classes) of the role object. It's divided by comma if more classes needed. In typical LDAP deployment it could be 'groupOfNames' . In Active Directory it's usually 'group' ",
+                ProviderConfigProperty.STRING_TYPE, null);
         configProperties.add(roleObjectClasses);
 
         List<String> modes = new LinkedList<String>();
@@ -90,9 +98,46 @@ public class RoleLDAPFederationMapperFactory extends AbstractLDAPFederationMappe
         return PROVIDER_ID;
     }
 
+    // Sync roles from LDAP to Keycloak DB during creation or update of mapperModel
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+        factory.register(new ProviderEventListener() {
+
+            @Override
+            public void onEvent(ProviderEvent event) {
+                if (event instanceof RealmModel.UserFederationMapperEvent) {
+                    RealmModel.UserFederationMapperEvent mapperEvent = (RealmModel.UserFederationMapperEvent)event;
+                    UserFederationMapperModel mapperModel = mapperEvent.getFederationMapper();
+                    RealmModel realm = mapperEvent.getRealm();
+                    KeycloakSession session = mapperEvent.getSession();
+
+                    if (mapperModel.getFederationMapperType().equals(PROVIDER_ID)) {
+                        try {
+                            String federationProviderId = mapperModel.getFederationProviderId();
+                            UserFederationProviderModel providerModel = KeycloakModelUtils.findUserFederationProviderById(federationProviderId, realm);
+                            if (providerModel == null) {
+                                throw new IllegalStateException("Can't find federation provider with ID [" + federationProviderId + "] in realm " + realm.getName());
+                            }
+
+                            UserFederationProviderFactory ldapFactory = (UserFederationProviderFactory) session.getKeycloakSessionFactory().getProviderFactory(UserFederationProvider.class, providerModel.getProviderName());
+                            LDAPFederationProvider ldapProvider = (LDAPFederationProvider) ldapFactory.getInstance(session, providerModel);
+
+                            // Sync roles
+                            new RoleLDAPFederationMapper().syncRolesFromLDAP(mapperModel, ldapProvider, realm);
+                        } catch (Exception e) {
+                            logger.warn("Exception during initial sync of roles from LDAP.", e);
+                        }
+                    }
+                }
+            }
+
+        });
+    }
+
     @Override
     public void validateConfig(UserFederationMapperModel mapperModel) throws MapperConfigValidationException {
         checkMandatoryConfigAttribute(RoleLDAPFederationMapper.ROLES_DN, "LDAP Roles DN", mapperModel);
+        checkMandatoryConfigAttribute(RoleLDAPFederationMapper.MODE, "Mode", mapperModel);
 
         String realmMappings = mapperModel.getConfig().get(RoleLDAPFederationMapper.USE_REALM_ROLES_MAPPING);
         boolean useRealmMappings = Boolean.parseBoolean(realmMappings);
diff --git a/federation/ldap/src/main/java/org/keycloak/federation/ldap/mappers/UserAttributeLDAPFederationMapper.java b/federation/ldap/src/main/java/org/keycloak/federation/ldap/mappers/UserAttributeLDAPFederationMapper.java
index c4c3029..dd139b0 100644
--- a/federation/ldap/src/main/java/org/keycloak/federation/ldap/mappers/UserAttributeLDAPFederationMapper.java
+++ b/federation/ldap/src/main/java/org/keycloak/federation/ldap/mappers/UserAttributeLDAPFederationMapper.java
@@ -1,18 +1,13 @@
 package org.keycloak.federation.ldap.mappers;
 
-import java.io.Serializable;
 import java.lang.reflect.Method;
-import java.util.List;
 import java.util.Map;
 
 import org.keycloak.federation.ldap.LDAPFederationProvider;
-import org.keycloak.federation.ldap.LDAPUtils;
 import org.keycloak.federation.ldap.idm.model.LDAPObject;
 import org.keycloak.federation.ldap.idm.query.Condition;
 import org.keycloak.federation.ldap.idm.query.QueryParameter;
 import org.keycloak.federation.ldap.idm.query.internal.LDAPIdentityQuery;
-import org.keycloak.mappers.UserFederationMapper;
-import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserFederationMapperModel;
 import org.keycloak.models.UserFederationProvider;
@@ -20,7 +15,6 @@ import org.keycloak.models.UserModel;
 import org.keycloak.models.utils.reflection.Property;
 import org.keycloak.models.utils.reflection.PropertyCriteria;
 import org.keycloak.models.utils.reflection.PropertyQueries;
-import org.keycloak.provider.ProviderConfigProperty;
 
 /**
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@@ -55,7 +49,7 @@ public class UserAttributeLDAPFederationMapper extends AbstractLDAPFederationMap
         String ldapAttrName = mapperModel.getConfig().get(LDAP_ATTRIBUTE);
 
         Object ldapAttrValue = ldapUser.getAttribute(ldapAttrName);
-        if (ldapAttrValue != null) {
+        if (ldapAttrValue != null && !ldapAttrValue.toString().trim().isEmpty()) {
             Property<Object> userModelProperty = userModelProperties.get(userModelAttrName);
 
             if (userModelProperty != null) {
@@ -124,7 +118,7 @@ public class UserAttributeLDAPFederationMapper extends AbstractLDAPFederationMap
                 }
 
                 protected void setLDAPAttribute(String modelAttrName, String value) {
-                    if (modelAttrName.equals(userModelAttrName)) {
+                    if (modelAttrName.equalsIgnoreCase(userModelAttrName)) {
                         if (logger.isTraceEnabled()) {
                             logger.tracef("Pushing user attribute to LDAP. Model attribute name: %s, LDAP attribute name: %s, Attribute value: %s", modelAttrName, ldapAttrName, value);
                         }
@@ -157,7 +151,7 @@ public class UserAttributeLDAPFederationMapper extends AbstractLDAPFederationMap
         // Change conditions and use ldapAttribute instead of userModel
         for (Condition condition : query.getConditions()) {
             QueryParameter param = condition.getParameter();
-            if (param != null && param.getName().equals(userModelAttrName)) {
+            if (param != null && param.getName().equalsIgnoreCase(userModelAttrName)) {
                 param.setName(ldapAttrName);
             }
         }
diff --git a/forms/account-api/src/main/java/org/keycloak/account/AccountSpi.java b/forms/account-api/src/main/java/org/keycloak/account/AccountSpi.java
index 2c9843e..3d2072a 100644
--- a/forms/account-api/src/main/java/org/keycloak/account/AccountSpi.java
+++ b/forms/account-api/src/main/java/org/keycloak/account/AccountSpi.java
@@ -10,7 +10,7 @@ import org.keycloak.provider.Spi;
 public class AccountSpi implements Spi {
 
     @Override
-    public boolean isPrivate() {
+    public boolean isInternal() {
         return true;
     }
 
diff --git a/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/model/AccountBean.java b/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/model/AccountBean.java
index 242225b..2032370 100755
--- a/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/model/AccountBean.java
+++ b/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/model/AccountBean.java
@@ -38,7 +38,7 @@ public class AccountBean {
     }
 
     public String getUsername() {
-        return user.getUsername();
+        return profileFormData != null ? profileFormData.getFirst("username") : user.getUsername();
     }
 
     public String getEmail() {
diff --git a/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/model/RealmBean.java b/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/model/RealmBean.java
index b0a5eb4..05a84c9 100755
--- a/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/model/RealmBean.java
+++ b/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/model/RealmBean.java
@@ -46,4 +46,8 @@ public class RealmBean {
         return realm.getSupportedLocales();
     }
 
+    public boolean isEditUsernameAllowed() {
+        return realm.isEditUsernameAllowed();
+    }
+
 }
diff --git a/forms/common-freemarker/src/main/java/org/keycloak/freemarker/ThemeSpi.java b/forms/common-freemarker/src/main/java/org/keycloak/freemarker/ThemeSpi.java
index 94db863..9e97cb9 100644
--- a/forms/common-freemarker/src/main/java/org/keycloak/freemarker/ThemeSpi.java
+++ b/forms/common-freemarker/src/main/java/org/keycloak/freemarker/ThemeSpi.java
@@ -10,7 +10,7 @@ import org.keycloak.provider.Spi;
 public class ThemeSpi implements Spi {
 
     @Override
-    public boolean isPrivate() {
+    public boolean isInternal() {
         return true;
     }
 
diff --git a/forms/common-themes/src/main/resources/theme/base/account/account.ftl b/forms/common-themes/src/main/resources/theme/base/account/account.ftl
index 922d9c5..d2a6af1 100755
--- a/forms/common-themes/src/main/resources/theme/base/account/account.ftl
+++ b/forms/common-themes/src/main/resources/theme/base/account/account.ftl
@@ -16,11 +16,11 @@
 
         <div class="form-group ${messagesPerField.printIfExists('username','has-error')}">
             <div class="col-sm-2 col-md-2">
-                <label for="username" class="control-label">${msg("username")}</label>
+                <label for="username" class="control-label">${msg("username")}</label> <#if realm.editUsernameAllowed><span class="required">*</span></#if>
             </div>
 
             <div class="col-sm-10 col-md-10">
-                <input type="text" class="form-control" id="username" name="username" disabled="disabled" value="${(account.username!'')?html}"/>
+                <input type="text" class="form-control" id="username" name="username" <#if !realm.editUsernameAllowed>disabled="disabled"</#if> value="${(account.username!'')?html}"/>
             </div>
         </div>
 
diff --git a/forms/common-themes/src/main/resources/theme/base/account/messages/messages_de.properties b/forms/common-themes/src/main/resources/theme/base/account/messages/messages_de.properties
index add9daa..ad3f459 100644
--- a/forms/common-themes/src/main/resources/theme/base/account/messages/messages_de.properties
+++ b/forms/common-themes/src/main/resources/theme/base/account/messages/messages_de.properties
@@ -80,7 +80,7 @@ totpStep1=Installieren Sie <a href="https://fedorahosted.org/freeotp/" target="_
 totpStep2=\u00D6ffnen Sie die Applikation und scannen Sie den Barcode oder geben sie den Code ein.
 totpStep3=Geben Sie den One-time Code welcher die Applikation generiert hat ein und klicken Sie auf Speichern.
 
-
+missingUsernameMessage=Bitte geben Sie einen Benutzernamen ein.
 missingFirstNameMessage=Bitte geben Sie einen Vornamen ein.
 missingEmailMessage=Bitte geben Sie eine E-Mail Adresse ein.
 missingLastNameMessage=Bitte geben Sie einen Nachnamen ein.
diff --git a/forms/common-themes/src/main/resources/theme/base/account/messages/messages_en.properties b/forms/common-themes/src/main/resources/theme/base/account/messages/messages_en.properties
index 7eb971b..f783b49 100755
--- a/forms/common-themes/src/main/resources/theme/base/account/messages/messages_en.properties
+++ b/forms/common-themes/src/main/resources/theme/base/account/messages/messages_en.properties
@@ -96,6 +96,7 @@ totpStep1=Install <a href="https://fedorahosted.org/freeotp/" target="_blank">Fr
 totpStep2=Open the application and scan the barcode or enter the key.
 totpStep3=Enter the one-time code provided by the application and click Save to finish the setup.
 
+missingUsernameMessage=Please specify username.
 missingFirstNameMessage=Please specify first name.
 invalidEmailMessage=Invalid email address.
 missingLastNameMessage=Please specify last name.
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js
index f60e20e..53ad7ae 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js
@@ -597,7 +597,7 @@ module.controller('RealmIdentityProviderCtrl', function($scope, $filter, $upload
         if (instance && instance.alias) {
 
         } else {
-            $scope.identityProvider.updateProfileFirstLogin = false;
+            $scope.identityProvider.updateProfileFirstLoginMode = "on";
         }
 
     };
@@ -645,7 +645,7 @@ module.controller('RealmIdentityProviderCtrl', function($scope, $filter, $upload
 
         } else {
             $scope.identityProvider.config.nameIDPolicyFormat = $scope.nameIdFormats[0].format;
-            $scope.identityProvider.updateProfileFirstLogin = false;
+            $scope.identityProvider.updateProfileFirstLoginMode = "off";
         }
     }
 
@@ -663,7 +663,7 @@ module.controller('RealmIdentityProviderCtrl', function($scope, $filter, $upload
         $scope.identityProvider.alias = providerFactory.id;
         $scope.identityProvider.providerId = providerFactory.id;
         $scope.identityProvider.enabled = true;
-        $scope.identityProvider.updateProfileFirstLogin = false;
+        $scope.identityProvider.updateProfileFirstLoginMode = "off";
         $scope.identityProvider.authenticateByDefault = false;
         $scope.newIdentityProvider = true;
     }
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/users.js b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/users.js
index 2561692..92e5db2 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/users.js
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/users.js
@@ -198,6 +198,7 @@ module.controller('UserListCtrl', function($scope, realm, User) {
 module.controller('UserDetailCtrl', function($scope, realm, user, User, UserFederationInstances, $location, Dialog, Notifications) {
     $scope.realm = realm;
     $scope.create = !user.id;
+    $scope.editUsername = $scope.create || $scope.realm.editUsernameAllowed;
 
     if ($scope.create) {
         $scope.user = { enabled: true, attributes: {} }
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/services.js b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/services.js
index af9b3a2..763d57f 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/services.js
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/services.js
@@ -559,7 +559,7 @@ function roleControl($scope, realm, role, roles, clients,
                         $scope.realmMappings.push(role);
                     }
                 }
-                $scope.selectRealmRoles = [];
+                $scope.selectedRealmRoles = [];
             });
     };
 
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-default-roles.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-default-roles.html
index 5a27f56..732aeea 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-default-roles.html
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-default-roles.html
@@ -17,7 +17,7 @@
                         <select id="available" class="form-control" multiple size="5"
                                 ng-multiple="true"
                                 ng-model="selectedRealmRoles"
-                                ng-options="r for r in availableRealmRoles">
+                                ng-options="r for r in availableRealmRoles | orderBy:'toString()'">
                         </select>
                         <button class="btn btn-default" type="submit" ng-click="addRealmDefaultRole()" tooltip="Assign role" tooltip-placement="right">
                             Add selected <i class="fa fa-angle-double-right"></i>
@@ -29,7 +29,7 @@
                         <select id="assigned" class="form-control" multiple size=5
                                 ng-multiple="true"
                                 ng-model="selectedRealmDefRoles"
-                                ng-options="r for r in realm.defaultRoles">
+                                ng-options="r for r in realm.defaultRoles | orderBy:'toString()'">
                         </select>
                         <button class="btn btn-default" type="submit" ng-click="deleteRealmDefaultRole()" tooltip="Unassign role" tooltip-placement="left">
                             <i class="fa fa-angle-double-left"></i> Remove selected
@@ -55,7 +55,7 @@
                         <select id="available-client" class="form-control" multiple size="5"
                                 ng-multiple="true"
                                 ng-model="selectedClientRoles"
-                                ng-options="r for r in availableClientRoles">
+                                ng-options="r for r in availableClientRoles | orderBy:'toString()'">
                         </select>
                         <button class="btn btn-default" type="submit" ng-click="addClientDefaultRole()" tooltip="Assign role" tooltip-placement="right">
                             Add selected <i class="fa fa-angle-double-right"></i>
@@ -67,7 +67,7 @@
                         <select id="assigned-client" class="form-control" multiple size=5
                                 ng-multiple="true"
                                 ng-model="selectedClientDefRoles"
-                                ng-options="r for r in client.defaultRoles">
+                                ng-options="r for r in client.defaultRoles | orderBy:'toString()'">
                         </select>
                         <button class="btn btn-default" type="submit" ng-click="rmClientDefaultRole()" tooltip="Unassign role" tooltip-placement="left">
                             <i class="fa fa-angle-double-left"></i> Remove selected
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider.html
index c826a16..9a2a28f 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider.html
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider.html
@@ -8,7 +8,7 @@
                     <caption class="hidden">Table of identity providers</caption>
                     <thead>
                     <tr>
-                        <th colspan="3" class="kc-table-actions">
+                        <th colspan="4" class="kc-table-actions">
                             <div class="dropdown pull-right">
                                 <select class="form-control" ng-model="provider"
                                         ng-options="p.name group by p.groupName for p in allProviders track by p.id"
@@ -21,6 +21,7 @@
                     <tr ng-show="configuredProviders.length > 0">
                         <th>Name</th>
                         <th>Provider</th>
+                        <th>Enabled</th>
                         <th width="15%">GUI order</th>
                     </tr>
                     </thead>
@@ -30,6 +31,7 @@
                             <a href="#/realms/{{realm.realm}}/identity-provider-settings/provider/{{identityProvider.providerId}}/{{identityProvider.alias}}">{{identityProvider.alias}}</a>
                         </td>
                         <td>{{identityProvider.providerId}}</td>
+                        <td>{{identityProvider.enabled}}</td>
                         <td>{{identityProvider.config.guiOrder}}</td>
                     </tr>
                     </tbody>
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-oidc.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-oidc.html
index ed3b063..d2a267b 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-oidc.html
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-oidc.html
@@ -59,11 +59,24 @@
                 <kc-tooltip>Enable/disable new users can read any stored tokens.  This assigns the broker.read-token role.</kc-tooltip>
             </div>
             <div class="form-group">
-                <label class="col-md-2 control-label" for="updateProfileFirstLogin">Update Profile on First Login</label>
+                <label class="col-md-2 control-label" for="updateProfileFirstLoginMode">Update Profile on First Login</label>
+                <div class="col-md-2">
+                		<div>
+                        <select id="updateProfileFirstLoginMode" ng-model="identityProvider.updateProfileFirstLoginMode" class="form-control">
+                            <option value="on">On</option>
+                            <option value="missing">On missing info</option>
+                            <option value="off">Off</option>
+                        </select>
+                    </div>
+                </div>
+                <kc-tooltip>Define under which conditions must user update his profile right after the first login.</kc-tooltip>
+            </div>
+            <div class="form-group">
+                <label class="col-md-2 control-label" for="trustEmail">Trust email</label>
                 <div class="col-md-6">
-                    <input ng-model="identityProvider.updateProfileFirstLogin" name="identityProvider.updateProfileFirstLogin" id="updateProfileFirstLogin" onoffswitch />
+                    <input ng-model="identityProvider.trustEmail" name="identityProvider.trustEmail" id="trustEmail" onoffswitch />
                 </div>
-                <kc-tooltip>Indicates if user must update his profile right after the first login.</kc-tooltip>
+                <kc-tooltip>If enabled then email provided by this provider is not verified even if verification is enabled for the realm.</kc-tooltip>
             </div>
             <div class="form-group">
                 <label class="col-md-2 control-label" for="guiOrder">GUI order</label>
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-saml.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-saml.html
index 8d9bd9d..d2aaf4e 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-saml.html
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-saml.html
@@ -60,11 +60,24 @@
                 <kc-tooltip>Enable/disable new users can read any stored tokens.  This assigns the broker.read-token role.</kc-tooltip>
             </div>
             <div class="form-group">
-                <label class="col-md-2 control-label" for="updateProfileFirstLogin">Update Profile on First Login</label>
+                <label class="col-md-2 control-label" for="updateProfileFirstLoginMode">Update Profile on First Login</label>
+                <div class="col-md-2">
+                		<div>
+                        <select id="updateProfileFirstLoginMode" ng-model="identityProvider.updateProfileFirstLoginMode" class="form-control">
+                            <option value="on">On</option>
+                            <option value="missing">On missing info</option>
+                            <option value="off">Off</option>
+                        </select>
+                    </div>
+                </div>
+                <kc-tooltip>Define under which conditions must user update his profile right after the first login.</kc-tooltip>
+            </div>
+            <div class="form-group">
+                <label class="col-md-2 control-label" for="trustEmail">Trust email</label>
                 <div class="col-md-6">
-                    <input ng-model="identityProvider.updateProfileFirstLogin" name="identityProvider.updateProfileFirstLogin" id="updateProfileFirstLogin" onoffswitch />
+                    <input ng-model="identityProvider.trustEmail" name="identityProvider.trustEmail" id="trustEmail" onoffswitch />
                 </div>
-                <kc-tooltip>Indicates if user must update his profile right after the first login.</kc-tooltip>
+                <kc-tooltip>If enabled then email provided by this provider is not verified even if verification is enabled for the realm.</kc-tooltip>
             </div>
             <div class="form-group">
                 <label class="col-md-2 control-label" for="guiOrder">GUI order</label>
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-social.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-social.html
index 73427e5..623bcf0 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-social.html
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-social.html
@@ -70,11 +70,24 @@
                 <kc-tooltip>Enable/disable this identity provider.</kc-tooltip>
             </div>
             <div class="form-group">
-                <label class="col-md-2 control-label" for="updateProfileFirstLogin">Update Profile on First Login</label>
+                <label class="col-md-2 control-label" for="updateProfileFirstLoginMode">Update Profile on First Login</label>
+                <div class="col-md-2">
+                		<div>
+                        <select id="updateProfileFirstLoginMode" ng-model="identityProvider.updateProfileFirstLoginMode" class="form-control">
+                            <option value="on">On</option>
+                            <option value="missing">On missing info</option>
+                            <option value="off">Off</option>
+                        </select>
+                    </div>
+                </div>
+                <kc-tooltip>Define under which conditions must user update his profile right after the first login.</kc-tooltip>
+            </div>
+            <div class="form-group">
+                <label class="col-md-2 control-label" for="trustEmail">Trust email</label>
                 <div class="col-md-6">
-                    <input ng-model="identityProvider.updateProfileFirstLogin" name="identityProvider.updateProfileFirstLogin" id="updateProfileFirstLogin" onoffswitch />
+                    <input ng-model="identityProvider.trustEmail" name="identityProvider.trustEmail" id="trustEmail" onoffswitch />
                 </div>
-                <kc-tooltip>Indicates if user must update his profile right after the first login.</kc-tooltip>
+                <kc-tooltip>If enabled then email provided by this provider is not verified even if verification is enabled for the realm.</kc-tooltip>
             </div>
             <div class="form-group">
                 <label class="col-md-2 control-label" for="authenticateByDefault">Authenticate By Default</label>
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-login-settings.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-login-settings.html
index 1a1b90d..34679ae 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-login-settings.html
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-login-settings.html
@@ -20,6 +20,13 @@
                 <kc-tooltip>If enabled then username field is hidden from registration form and email is used as username for new user.</kc-tooltip>
             </div>
             <div class="form-group">
+                <label for="editUsernameAllowed" class="col-md-2 control-label">Edit username</label>
+                <div class="col-md-6">
+                    <input ng-model="realm.editUsernameAllowed" name="editUsernameAllowed" id="editUsernameAllowed" onoffswitch />
+                </div>
+                <kc-tooltip>If enabled, the username field is editable, readonly otherwise.</kc-tooltip>
+            </div>
+            <div class="form-group">
                 <label for="resetPasswordAllowed" class="col-md-2 control-label">Forget password</label>
                 <div class="col-md-6">
                     <input ng-model="realm.resetPasswordAllowed" name="resetPasswordAllowed" id="resetPasswordAllowed" onoffswitch />
@@ -41,13 +48,6 @@
                 <kc-tooltip>Require the user to verify their email address the first time they login.</kc-tooltip>
             </div>
             <div class="form-group">
-                <label for="passwordCredentialGrantAllowed" class="col-md-2 control-label">Direct Grant API</label>
-                <div class="col-md-6">
-                    <input ng-model="realm.passwordCredentialGrantAllowed" name="passwordCredentialGrantAllowed" id="passwordCredentialGrantAllowed" onoffswitch />
-                </div>
-                <kc-tooltip>Enable/disable REST API for login/token grant access</kc-tooltip>
-            </div>
-            <div class="form-group">
                 <label for="sslRequired" class="col-md-2 control-label">Require SSL</label>
                 <div class="col-md-2">
                     <div>
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/role-detail.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/role-detail.html
index 0ba6cb0..aa21bd8 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/role-detail.html
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/role-detail.html
@@ -64,7 +64,7 @@
                             <select id="available" class="form-control" multiple size="5"
                                     ng-multiple="true"
                                     ng-model="selectedRealmRoles"
-                                    ng-options="r.name for r in realmRoles">
+                                    ng-options="r.name for r in realmRoles | orderBy:'name'">
                             </select>
                             <button class="btn btn-default" type="submit" ng-click="addRealmRole()" tooltip="Associate role" tooltip-placement="right">
                                 Add selected <i class="fa fa-angle-double-right"></i>
@@ -76,7 +76,7 @@
                             <select id="assigned" class="form-control" multiple size=5
                                     ng-multiple="true"
                                     ng-model="selectedRealmMappings"
-                                    ng-options="r.name for r in realmMappings">
+                                    ng-options="r.name for r in realmMappings | orderBy:'name'">
                             </select>
                             <button class="btn btn-default" type="submit" ng-click="deleteRealmRole()" tooltip="Disassociate role" tooltip-placement="left">
                                 <i class="fa fa-angle-double-left"></i> Remove selected
@@ -103,7 +103,7 @@
                             <select id="available-client" class="form-control" multiple size="5"
                                     ng-multiple="true"
                                     ng-model="selectedClientRoles"
-                                    ng-options="r.name for r in clientRoles">
+                                    ng-options="r.name for r in clientRoles | orderBy:'name'">
                             </select>
                             <button class="btn btn-default" type="submit" ng-click="addClientRole()" tooltip="Associate role" tooltip-placement="right">
                                 Add selected <i class="fa fa-angle-right"></i>
@@ -115,7 +115,7 @@
                             <select id="assigned-client" class="form-control" multiple size=5
                                     ng-multiple="true"
                                     ng-model="selectedClientMappings"
-                                    ng-options="r.name for r in clientMappings">
+                                    ng-options="r.name for r in clientMappings | orderBy:'name'">
                             </select>
                             <button class="btn btn-default" type="submit" ng-click="deleteClientRole()" tooltip="Disassociate role" tooltip-placement="left">
                                 <i class="fa fa-angle-left"></i> Remove selected
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/role-list.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/role-list.html
index 316704e..010b29e 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/role-list.html
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/role-list.html
@@ -33,7 +33,7 @@
         </tr>
         </thead>
         <tbody>
-        <tr ng-repeat="role in roles | filter:{name: searchQuery}">
+        <tr ng-repeat="role in roles | orderBy:'name' | filter:{name: searchQuery}">
             <td><a href="#/realms/{{realm.realm}}/roles/{{role.id}}">{{role.name}}</a></td>
             <td>{{role.composite}}</td>
             <td>{{role.description}}</td>
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info.html
index ff818a2..c0d6600 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info.html
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/server-info.html
@@ -14,7 +14,35 @@
 
     <fieldset>
         <legend collapsed>Providers</legend>
+
         <div class="form-group">
+            <h3>Public SPIs</h3>
+            <kc-tooltip>For public SPIs there are built-in providers, but it's also supported to write your own custom providers.</kc-tooltip>
+
+            <table class="table table-striped table-bordered">
+                <thead>
+                <tr>
+                    <th>SPI</th>
+                    <th>Providers</th>
+                </tr>
+                </thead>
+                <tbody>
+                <tr data-ng-repeat="spi in (serverInfo.providers | filter:{internal:false} | orderBy:'name')">
+                    <td>{{spi.name}}</td>
+                    <td>
+                        <div data-ng-repeat="provider in (spi.implementations | orderBy:'toString()')">
+                            {{provider}}
+                        </div>
+                    </td>
+                </tr>
+                </tbody>
+            </table>
+        </div>
+
+        <div class="form-group">
+            <h3>Internal SPIs</h3>
+            <kc-tooltip>For internal SPIs there are only built-in providers. It's not recommended to write your own custom providers as internal SPIs may change or be removed without notice.</kc-tooltip>
+
             <table class="table table-striped table-bordered">
                 <thead>
                 <tr>
@@ -23,10 +51,10 @@
                 </tr>
                 </thead>
                 <tbody>
-                <tr data-ng-repeat="(spi, providers) in serverInfo.providers">
-                    <td>{{spi}}</td>
+                <tr data-ng-repeat="spi in (serverInfo.providers | filter:{internal:true} | orderBy:'name')">
+                    <td>{{spi.name}}</td>
                     <td>
-                        <div data-ng-repeat="provider in providers">
+                        <div data-ng-repeat="provider in (spi.implementations | orderBy:'toString()')">
                             {{provider}}
                         </div>
                     </td>
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/user-detail.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/user-detail.html
index 35b5645..1dcadd4 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/user-detail.html
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/user-detail.html
@@ -25,10 +25,11 @@
                 <div class="col-md-6">
                     <!-- Characters >,<,/,\ are forbidden in username -->
                     <input class="form-control" type="text" id="username" name="username" data-ng-model="user.username" autofocus
-                           required ng-pattern="/^[^\<\>\\\/]*$/" data-ng-readonly="!create">
+                           required ng-pattern="/^[^\<\>\\\/]*$/" data-ng-readonly="!editUsername">
                 </div>
             </div>
 
+
             <div class="form-group">
                 <label class="col-md-2 control-label" for="email">Email</label>
 
diff --git a/forms/common-themes/src/main/resources/theme/base/login/login-totp.ftl b/forms/common-themes/src/main/resources/theme/base/login/login-totp.ftl
index b696ef1..b085eeb 100755
--- a/forms/common-themes/src/main/resources/theme/base/login/login-totp.ftl
+++ b/forms/common-themes/src/main/resources/theme/base/login/login-totp.ftl
@@ -11,7 +11,7 @@
 
             <div class="${properties.kcFormGroupClass!}">
                 <div class="${properties.kcLabelWrapperClass!}">
-                    <label for="totp" class="${properties.kcLabelClass!}">${msg("doLogIn")}</label>
+                    <label for="totp" class="${properties.kcLabelClass!}">${msg("loginTotpOneTime")}</label>
                 </div>
 
                 <div class="${properties.kcInputWrapperClass!}">
diff --git a/forms/common-themes/src/main/resources/theme/keycloak/email/html/email-verification.ftl b/forms/common-themes/src/main/resources/theme/keycloak/email/html/email-verification.ftl
new file mode 100644
index 0000000..eb7682a
--- /dev/null
+++ b/forms/common-themes/src/main/resources/theme/keycloak/email/html/email-verification.ftl
@@ -0,0 +1,5 @@
+<html>
+<body>
+${msg("emailVerificationBodyHtml",link, linkExpiration, realmName)}
+</body>
+</html>
diff --git a/forms/common-themes/src/main/resources/theme/keycloak/email/html/event-login_error.ftl b/forms/common-themes/src/main/resources/theme/keycloak/email/html/event-login_error.ftl
new file mode 100644
index 0000000..d314103
--- /dev/null
+++ b/forms/common-themes/src/main/resources/theme/keycloak/email/html/event-login_error.ftl
@@ -0,0 +1,5 @@
+<html>
+<body>
+${msg("eventLoginErrorBodyHtml",event.date,event.ipAddress)}
+</body>
+</html>
diff --git a/forms/common-themes/src/main/resources/theme/keycloak/email/html/event-remove_totp.ftl b/forms/common-themes/src/main/resources/theme/keycloak/email/html/event-remove_totp.ftl
new file mode 100644
index 0000000..91699ea
--- /dev/null
+++ b/forms/common-themes/src/main/resources/theme/keycloak/email/html/event-remove_totp.ftl
@@ -0,0 +1,5 @@
+<html>
+<body>
+${msg("eventRemoveTotpBodyHtml",event.date, event.ipAddress)}
+</body>
+</html>
diff --git a/forms/common-themes/src/main/resources/theme/keycloak/email/html/event-update_password.ftl b/forms/common-themes/src/main/resources/theme/keycloak/email/html/event-update_password.ftl
new file mode 100644
index 0000000..8a6da60
--- /dev/null
+++ b/forms/common-themes/src/main/resources/theme/keycloak/email/html/event-update_password.ftl
@@ -0,0 +1,5 @@
+<html>
+<body>
+${msg("eventUpdatePasswordBodyHtml",event.date, event.ipAddress)}
+</body>
+</html>
diff --git a/forms/common-themes/src/main/resources/theme/keycloak/email/html/event-update_totp.ftl b/forms/common-themes/src/main/resources/theme/keycloak/email/html/event-update_totp.ftl
new file mode 100644
index 0000000..c0190c7
--- /dev/null
+++ b/forms/common-themes/src/main/resources/theme/keycloak/email/html/event-update_totp.ftl
@@ -0,0 +1,5 @@
+<html>
+<body>
+${msg("eventUpdateTotpBodyHtml",event.date, event.ipAddress)}
+</body>
+</html>
diff --git a/forms/common-themes/src/main/resources/theme/keycloak/email/html/password-reset.ftl b/forms/common-themes/src/main/resources/theme/keycloak/email/html/password-reset.ftl
new file mode 100644
index 0000000..846b45d
--- /dev/null
+++ b/forms/common-themes/src/main/resources/theme/keycloak/email/html/password-reset.ftl
@@ -0,0 +1,5 @@
+<html>
+<body>
+${msg("passwordResetBodyHtml",link, linkExpiration, realmName)}
+</body>
+</html>
\ No newline at end of file
diff --git a/forms/common-themes/src/main/resources/theme/keycloak/email/messages/messages_de.properties b/forms/common-themes/src/main/resources/theme/keycloak/email/messages/messages_de.properties
index 0256640..91337c4 100644
--- a/forms/common-themes/src/main/resources/theme/keycloak/email/messages/messages_de.properties
+++ b/forms/common-themes/src/main/resources/theme/keycloak/email/messages/messages_de.properties
@@ -1,12 +1,18 @@
 emailVerificationSubject=E-Mail verifizieren
 passwordResetSubject=Passwort zur\u00FCckzusetzen
 passwordResetBody=Jemand hat angefordert Ihr {2} Passwort zur\u00FCckzusetzen. Falls das Sie waren, dann klicken Sie auf den folgenden Link um das Passwort zur\u00FCckzusetzen.\n\n{0}\n\nDieser Link wird in {1} Minuten ablaufen.\n\nFalls Sie das Passwort nicht zur\u00FCcksetzen m\u00F6chten, dann k\u00F6nnen Sie diese E-Mail ignorieren.
+passwordResetBodyHtml=<p>Jemand hat angefordert Ihr {2} Passwort zur\u00FCckzusetzen. Falls das Sie waren, dann klicken Sie auf den folgenden Link um das Passwort zur\u00FCckzusetzen.</p><p><a href="{0}">{0}</a></p><p>Dieser Link wird in {1} Minuten ablaufen.</p><p>Falls Sie das Passwort nicht zur\u00FCcksetzen m\u00F6chten, dann k\u00F6nnen Sie diese E-Mail ignorieren.</p>
 emailVerificationBody=Jemand hat ein {2} Konto mit dieser E-Mail Adresse erstellt. Fall das Sie waren, dann klicken Sie auf den Link um die E-Mail Adresse zu verifizieren.\n\n{0}\n\nDieser Link wird in {1} Minuten ablaufen.\n\nFalls Sie dieses Konto nicht erstellt haben, dann k\u00F6nnen sie diese Nachricht ignorieren.
+emailVerificationBodyHtml=<p>Jemand hat ein {2} Konto mit dieser E-Mail Adresse erstellt. Fall das Sie waren, dann klicken Sie auf den Link um die E-Mail Adresse zu verifizieren.</p><p><a href="{0}">{0}</a></p><p>Dieser Link wird in {1} Minuten ablaufen.</p><p>Falls Sie dieses Konto nicht erstellt haben, dann k\u00F6nnen sie diese Nachricht ignorieren.</p>
 eventLoginErrorSubject=Fehlgeschlagene Anmeldung
 eventLoginErrorBody=Jemand hat um {0} von {1} versucht sich mit ihrem Konto anzumelden. Falls das nicht Sie waren, dann kontaktieren Sie bitte Ihren Admin.
+eventLoginErrorBodyHtml=<p>Jemand hat um {0} von {1} versucht sich mit ihrem Konto anzumelden. Falls das nicht Sie waren, dann kontaktieren Sie bitte Ihren Admin.</p>
 eventRemoveTotpSubject=TOTP Entfernt
 eventRemoveTotpBody=TOTP wurde von ihrem Konto am {0} von {1} entfernt. Falls das nicht Sie waren, dann kontaktieren Sie bitte Ihren Admin.
+eventRemoveTotpBodyHtml=<p>TOTP wurde von ihrem Konto am {0} von {1} entfernt. Falls das nicht Sie waren, dann kontaktieren Sie bitte Ihren Admin.</p>
 eventUpdatePasswordSubject=Passwort Aktualisiert
 eventUpdatePasswordBody=Ihr Passwort wurde am {0} von {1} ge\u00E4ndert. Falls das nicht Sie waren, dann kontaktieren Sie bitte Ihren Admin.
+eventUpdatePasswordBodyHtml=<p>Ihr Passwort wurde am {0} von {1} ge\u00E4ndert. Falls das nicht Sie waren, dann kontaktieren Sie bitte Ihren Admin.</p>
 eventUpdateTotpSubject=TOTP Aktualisiert
 eventUpdateTotpBody=TOTP wurde am {0} von {1} ge\u00E4ndert. Falls das nicht Sie waren, dann kontaktieren Sie bitte Ihren Admin.
+eventUpdateTotpBodyHtml=<p>TOTP wurde am {0} von {1} ge\u00E4ndert. Falls das nicht Sie waren, dann kontaktieren Sie bitte Ihren Admin.</p>
diff --git a/forms/common-themes/src/main/resources/theme/keycloak/email/messages/messages_en.properties b/forms/common-themes/src/main/resources/theme/keycloak/email/messages/messages_en.properties
index c0afc9c..7a3ac65 100755
--- a/forms/common-themes/src/main/resources/theme/keycloak/email/messages/messages_en.properties
+++ b/forms/common-themes/src/main/resources/theme/keycloak/email/messages/messages_en.properties
@@ -1,12 +1,18 @@
 emailVerificationSubject=Verify email
 emailVerificationBody=Someone has created a {2} account with this email address. If this was you, click the link below to verify your email address\n\n{0}\n\nThis link will expire within {1} minutes.\n\nIf you didn''t create this account, just ignore this message.
+emailVerificationBodyHtml=<p>Someone has created a {2} account with this email address. If this was you, click the link below to verify your email address</p><p><a href="{0}">{0}</a></p><p>This link will expire within {1} minutes.</p><p>If you didn''t create this account, just ignore this message.</p>
 passwordResetSubject=Reset password
 passwordResetBody=Someone just requested to change your {2} account''s password. If this was you, click on the link below to set a new password\n\n{0}\n\nThis link will expire within {1} minutes.\n\nIf you don''t want to reset your password, just ignore this message and nothing will be changed.
+passwordResetBodyHtml=<p>Someone just requested to change your {2} account''s password. If this was you, click on the link below to set a new password</p><p><a href="{0}">{0}</a></p><p>This link will expire within {1} minutes.</p><p>If you don''t want to reset your password, just ignore this message and nothing will be changed.</p>
 eventLoginErrorSubject=Login error
-eventLoginErrorBody=A failed login attempt was dettected to your account on {0} from {1}. If this was not you, please contact an admin.
+eventLoginErrorBody=A failed login attempt was detected to your account on {0} from {1}. If this was not you, please contact an admin.
+eventLoginErrorBodyHtml=<p>A failed login attempt was detected to your account on {0} from {1}. If this was not you, please contact an admin.</p>
 eventRemoveTotpSubject=Remove TOTP
 eventRemoveTotpBody=TOTP was removed from your account on {0} from {1}. If this was not you, please contact an admin.
+eventRemoveTotpBodyHtml=<p>TOTP was removed from your account on {0} from {1}. If this was not you, please contact an admin.</p>
 eventUpdatePasswordSubject=Update password
 eventUpdatePasswordBody=Your password was changed on {0} from {1}. If this was not you, please contact an admin.
+eventUpdatePasswordBodyHtml=<p>Your password was changed on {0} from {1}. If this was not you, please contact an admin.</p>
 eventUpdateTotpSubject=Update TOTP
-eventUpdateTotpBody=TOTP was updated for your account on {0} from {1}. If this was not you, please contact an admin.
\ No newline at end of file
+eventUpdateTotpBody=TOTP was updated for your account on {0} from {1}. If this was not you, please contact an admin.
+eventUpdateTotpBodyHtml=<p>TOTP was updated for your account on {0} from {1}. If this was not you, please contact an admin.</p>
diff --git a/forms/common-themes/src/main/resources/theme/keycloak/email/messages/messages_pt_BR.properties b/forms/common-themes/src/main/resources/theme/keycloak/email/messages/messages_pt_BR.properties
index 0316e19..fff7e10 100644
--- a/forms/common-themes/src/main/resources/theme/keycloak/email/messages/messages_pt_BR.properties
+++ b/forms/common-themes/src/main/resources/theme/keycloak/email/messages/messages_pt_BR.properties
@@ -1,12 +1,18 @@
 emailVerificationSubject=Verifica\u00E7\u00E3o de e-mail
 emailVerificationBody=Algu\u00E9m criou uma conta {2} com este endere\u00E7o de e-mail. Se foi voc\u00EA, clique no link abaixo para verificar o seu endere\u00E7o de email\n\n{0}\n\nEste link ir\u00E1 expirar dentro de {1} minutos.\n\nSe n\u00E3o foi voc\u00EA que criou esta conta, basta ignorar esta mensagem.
+emailVerificationBodyHtml=<p>Algu\u00E9m criou uma conta {2} com este endere\u00E7o de e-mail. Se foi voc\u00EA, clique no link abaixo para verificar o seu endere\u00E7o de email</p><p><a href="{0}">{0}</a></p><p>Este link ir\u00E1 expirar dentro de {1} minutos.</p><p>Se n\u00E3o foi voc\u00EA que criou esta conta, basta ignorar esta mensagem.</p>
 passwordResetSubject=Redefini\u00E7\u00E3o de senha
 passwordResetBody=Algu\u00E9m pediu para mudar a senha de sua conta {2}. Se foi voc\u00EA, clique no link abaixo para definir uma nova senha\n\n{0}\n\nEste link ir\u00E1 expirar dentro de {1} minutos.\n\nSe voc\u00EA n\u00E3o deseja redefinir sua senha, basta ignorar esta mensagem e nada ser\u00E1 mudado.
+passwordResetBodyHtml=<p>Algu\u00E9m pediu para mudar a senha de sua conta {2}. Se foi voc\u00EA, clique no link abaixo para definir uma nova senha</p><p><a href="{0}">{0}</a></p><p>Este link ir\u00E1 expirar dentro de {1} minutos.</p><p>Se voc\u00EA n\u00E3o deseja redefinir sua senha, basta ignorar esta mensagem e nada ser\u00E1 mudado.</p>
 eventLoginErrorSubject=Erro de login
 eventLoginErrorBody=Uma tentativa de login mal sucedida para a sua conta foi detectada em {0} de {1}. Se n\u00E3o foi voc\u00EA, por favor, entre em contato com um administrador.
+eventLoginErrorBodyHtml=<p>Uma tentativa de login mal sucedida para a sua conta foi detectada em {0} de {1}. Se n\u00E3o foi voc\u00EA, por favor, entre em contato com um administrador.</p>
 eventRemoveTotpSubject=Remover TOTP
 eventRemoveTotpBody=TOTP foi removido da sua conta em {0} de {1}. Se n\u00E3o foi voc\u00EA, por favor, entre em contato com um administrador.
+eventRemoveTotpBodyHtml=<p>TOTP foi removido da sua conta em {0} de {1}. Se n\u00E3o foi voc\u00EA, por favor, entre em contato com um administrador.</p>
 eventUpdatePasswordSubject=Atualiza\u00E7\u00E3o de senha
 eventUpdatePasswordBody=Sua senha foi alterada em {0} de {1}. Se n\u00E3o foi voc\u00EA, por favor, entre em contato com um administrador.
+eventUpdatePasswordBodyHtml=<p>Sua senha foi alterada em {0} de {1}. Se n\u00E3o foi voc\u00EA, por favor, entre em contato com um administrador.</p>
 eventUpdateTotpSubject=Atualiza\u00E7\u00E3o TOTP
 eventUpdateTotpBody=TOTP foi atualizado para a sua conta em {0} de {1}. Se n\u00E3o foi voc\u00EA, por favor, entre em contato com um administrador.
+eventUpdateTotpBodyHtml=<p>TOTP foi atualizado para a sua conta em {0} de {1}. Se n\u00E3o foi voc\u00EA, por favor, entre em contato com um administrador.</p>
diff --git a/forms/email-api/src/main/java/org/keycloak/email/EmailSpi.java b/forms/email-api/src/main/java/org/keycloak/email/EmailSpi.java
index cde73ce..8d08533 100644
--- a/forms/email-api/src/main/java/org/keycloak/email/EmailSpi.java
+++ b/forms/email-api/src/main/java/org/keycloak/email/EmailSpi.java
@@ -10,7 +10,7 @@ import org.keycloak.provider.Spi;
 public class EmailSpi implements Spi {
 
     @Override
-    public boolean isPrivate() {
+    public boolean isInternal() {
         return true;
     }
 
diff --git a/forms/email-freemarker/src/main/java/org/keycloak/email/freemarker/FreeMarkerEmailProvider.java b/forms/email-freemarker/src/main/java/org/keycloak/email/freemarker/FreeMarkerEmailProvider.java
index 95f55f3..79080de 100755
--- a/forms/email-freemarker/src/main/java/org/keycloak/email/freemarker/FreeMarkerEmailProvider.java
+++ b/forms/email-freemarker/src/main/java/org/keycloak/email/freemarker/FreeMarkerEmailProvider.java
@@ -1,11 +1,28 @@
 package org.keycloak.email.freemarker;
 
+import java.text.MessageFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.mail.Message;
+import javax.mail.Multipart;
+import javax.mail.Session;
+import javax.mail.Transport;
+import javax.mail.internet.InternetAddress;
+import javax.mail.internet.MimeBodyPart;
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimeMultipart;
+
 import org.jboss.logging.Logger;
 import org.keycloak.email.EmailException;
 import org.keycloak.email.EmailProvider;
 import org.keycloak.email.freemarker.beans.EventBean;
 import org.keycloak.events.Event;
 import org.keycloak.events.EventType;
+import org.keycloak.freemarker.FreeMarkerException;
 import org.keycloak.freemarker.FreeMarkerUtil;
 import org.keycloak.freemarker.LocaleHelper;
 import org.keycloak.freemarker.Theme;
@@ -15,14 +32,6 @@ import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserModel;
 
-import javax.mail.Message;
-import javax.mail.Session;
-import javax.mail.Transport;
-import javax.mail.internet.InternetAddress;
-import javax.mail.internet.MimeMessage;
-import java.text.MessageFormat;
-import java.util.*;
-
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
  */
@@ -93,16 +102,29 @@ public class FreeMarkerEmailProvider implements EmailProvider {
             Properties rb = theme.getMessages(locale);
             attributes.put("msg", new MessageFormatterMethod(locale, rb));
             String subject = new MessageFormat(rb.getProperty(subjectKey,subjectKey),locale).format(new Object[0]);
-            String body = freeMarker.processTemplate(attributes, template, theme);
+            String textTemplate = String.format("text/%s", template);
+            String textBody;
+            try {
+            	textBody = freeMarker.processTemplate(attributes, textTemplate, theme);
+            } catch (final FreeMarkerException e ) {
+            	textBody = null;
+            }
+            String htmlTemplate = String.format("html/%s", template);
+            String htmlBody;
+            try {
+            	htmlBody = freeMarker.processTemplate(attributes, htmlTemplate, theme);
+            } catch (final FreeMarkerException e ) {
+            	htmlBody = null;
+            }
 
-            send(subject, body);
+            send(subject, textBody, htmlBody);
         } catch (Exception e) {
             throw new EmailException("Failed to template email", e);
         }
     }
 
 
-    private void send(String subject, String body) throws EmailException {
+    private void send(String subject, String textBody, String htmlBody) throws EmailException {
         try {
             String address = user.getEmail();
             Map<String, String> config = realm.getSmtpConfig();
@@ -135,11 +157,25 @@ public class FreeMarkerEmailProvider implements EmailProvider {
 
             Session session = Session.getInstance(props);
 
+            Multipart multipart = new MimeMultipart("alternative");
+            
+            if(textBody != null) {
+            	MimeBodyPart textPart = new MimeBodyPart();
+            	textPart.setText(textBody, "UTF-8");
+            	multipart.addBodyPart(textPart);
+            }
+            
+            if(htmlBody != null) {
+            	MimeBodyPart htmlPart = new MimeBodyPart();
+            	htmlPart.setContent(htmlBody, "text/html; charset=UTF-8");
+            	multipart.addBodyPart(htmlPart);
+            }
+            
             Message msg = new MimeMessage(session);
             msg.setFrom(new InternetAddress(from));
             msg.setHeader("To", address);
             msg.setSubject(subject);
-            msg.setText(body);
+            msg.setContent(multipart);
             msg.saveChanges();
             msg.setSentDate(new Date());
 
diff --git a/forms/login-api/src/main/java/org/keycloak/login/LoginFormsSpi.java b/forms/login-api/src/main/java/org/keycloak/login/LoginFormsSpi.java
index f99292a..dc18703 100644
--- a/forms/login-api/src/main/java/org/keycloak/login/LoginFormsSpi.java
+++ b/forms/login-api/src/main/java/org/keycloak/login/LoginFormsSpi.java
@@ -10,7 +10,7 @@ import org.keycloak.provider.Spi;
 public class LoginFormsSpi implements Spi {
 
     @Override
-    public boolean isPrivate() {
+    public boolean isInternal() {
         return true;
     }
 
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/BearerTokenRequestAuthenticator.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/BearerTokenRequestAuthenticator.java
index a1a68df..1ff7b15 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/BearerTokenRequestAuthenticator.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/BearerTokenRequestAuthenticator.java
@@ -136,7 +136,7 @@ public class BearerTokenRequestAuthenticator {
         return new AuthChallenge() {
             @Override
             public boolean errorPage() {
-                return false;
+                return true;
             }
 
             @Override
diff --git a/integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakAdapterConfigService.java b/integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakAdapterConfigService.java
index 7f86d79..8f3a59d 100755
--- a/integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakAdapterConfigService.java
+++ b/integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakAdapterConfigService.java
@@ -14,14 +14,8 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-
 package org.keycloak.subsystem.server.extension;
 
-import java.util.HashMap;
-import java.util.Map;
-
-import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADDRESS;
-
 /**
  * This service keeps track of the entire Keycloak management model so as to provide
  * adapter configuration to each deployment at deploy time.
@@ -30,37 +24,25 @@ import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADD
  */
 public final class KeycloakAdapterConfigService {
 
-    private static final KeycloakAdapterConfigService INSTANCE = new KeycloakAdapterConfigService();
-
-    public static KeycloakAdapterConfigService getInstance() {
-        return INSTANCE;
-    }
+    static final KeycloakAdapterConfigService INSTANCE = new KeycloakAdapterConfigService();
 
-    // key=auth-server deployment name; value=web-context
-    private final Map<String, String> webContexts = new HashMap<String, String>();
+    static final String DEPLOYMENT_NAME = "keycloak-server";
 
+    private String webContext;
 
 
     private KeycloakAdapterConfigService() {
     }
 
-    public void addServerDeployment(String deploymentName, String webContext) {
-        this.webContexts.put(deploymentName, webContext);
-    }
-
-    public String getWebContext(String deploymentName) {
-        return webContexts.get(deploymentName);
-    }
-
-    public void removeServerDeployment(String deploymentName) {
-        this.webContexts.remove(deploymentName);
+    void setWebContext(String webContext) {
+        this.webContext = webContext;
     }
 
-    public boolean isWebContextUsed(String webContext) {
-        return webContexts.containsValue(webContext);
+    String getWebContext() {
+        return webContext;
     }
 
-    public boolean isKeycloakServerDeployment(String deploymentName) {
-        return this.webContexts.containsKey(deploymentName);
+    boolean isKeycloakServerDeployment(String deploymentName) {
+        return DEPLOYMENT_NAME.equals(deploymentName);
     }
 }
diff --git a/integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakExtension.java b/integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakExtension.java
index 145b475..cf1a4d7 100755
--- a/integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakExtension.java
+++ b/integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakExtension.java
@@ -24,11 +24,9 @@ import org.jboss.as.controller.ResourceDefinition;
 import org.jboss.as.controller.SubsystemRegistration;
 import org.jboss.as.controller.descriptions.StandardResourceDescriptionResolver;
 import org.jboss.as.controller.parsing.ExtensionParsingContext;
-import org.jboss.as.controller.registry.ManagementResourceRegistration;
-import org.keycloak.subsystem.server.extension.authserver.AuthServerDefinition;
-import org.keycloak.subsystem.server.logging.KeycloakLogger;
 
 import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SUBSYSTEM;
+import static org.keycloak.subsystem.server.logging.KeycloakLogger.ROOT_LOGGER;
 
 
 /**
@@ -38,17 +36,16 @@ import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SUB
  */
 public class KeycloakExtension implements Extension {
 
-    public static final String SUBSYSTEM_NAME = "keycloak-server";
-    public static final String NAMESPACE = "urn:jboss:domain:keycloak-server:1.1";
-    private static final KeycloakSubsystemParser PARSER = new KeycloakSubsystemParser();
+    static final String SUBSYSTEM_NAME = "keycloak-server";
+    static final String NAMESPACE = "urn:jboss:domain:keycloak-server:1.1";
     static final PathElement PATH_SUBSYSTEM = PathElement.pathElement(SUBSYSTEM, SUBSYSTEM_NAME);
+
     private static final String RESOURCE_NAME = KeycloakExtension.class.getPackage().getName() + ".LocalDescriptions";
-    private static final ModelVersion MGMT_API_VERSION = ModelVersion.create(1,1,0);
-    static final PathElement SUBSYSTEM_PATH = PathElement.pathElement(SUBSYSTEM, SUBSYSTEM_NAME);
     private static final ResourceDefinition KEYCLOAK_SUBSYSTEM_RESOURCE = new KeycloakSubsystemDefinition();
-    static final AuthServerDefinition AUTH_SERVER_DEFINITION = new AuthServerDefinition();
+    private static final KeycloakSubsystemParser PARSER = new KeycloakSubsystemParser();
+    private static final ModelVersion MGMT_API_VERSION = ModelVersion.create(1,1,0);
 
-    public static StandardResourceDescriptionResolver getResourceDescriptionResolver(final String... keyPrefix) {
+    static StandardResourceDescriptionResolver getResourceDescriptionResolver(final String... keyPrefix) {
         StringBuilder prefix = new StringBuilder(SUBSYSTEM_NAME);
         for (String kp : keyPrefix) {
             prefix.append('.').append(kp);
@@ -61,7 +58,7 @@ public class KeycloakExtension implements Extension {
      */
     @Override
     public void initializeParsers(final ExtensionParsingContext context) {
-        context.setSubsystemXmlMapping(SUBSYSTEM_NAME, KeycloakExtension.NAMESPACE, PARSER);
+        context.setSubsystemXmlMapping(SUBSYSTEM_NAME, NAMESPACE, PARSER);
     }
 
     /**
@@ -69,11 +66,10 @@ public class KeycloakExtension implements Extension {
      */
     @Override
     public void initialize(final ExtensionContext context) {
-        KeycloakLogger.ROOT_LOGGER.debug("Activating Keycloak Extension");
+        ROOT_LOGGER.debug("Activating Keycloak Extension");
         final SubsystemRegistration subsystem = context.registerSubsystem(SUBSYSTEM_NAME, MGMT_API_VERSION);
 
-        ManagementResourceRegistration registration = subsystem.registerSubsystemModel(KEYCLOAK_SUBSYSTEM_RESOURCE);
-        registration.registerSubModel(AUTH_SERVER_DEFINITION);
+        subsystem.registerSubsystemModel(KEYCLOAK_SUBSYSTEM_RESOURCE);
         subsystem.registerXMLElementWriter(PARSER);
     }
 }
diff --git a/integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakSubsystemAdd.java b/integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakSubsystemAdd.java
index 4f0dde9..7038408 100755
--- a/integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakSubsystemAdd.java
+++ b/integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakSubsystemAdd.java
@@ -17,13 +17,18 @@
 package org.keycloak.subsystem.server.extension;
 
 import org.jboss.as.controller.AbstractBoottimeAddStepHandler;
+import org.jboss.as.controller.AttributeDefinition;
 import org.jboss.as.controller.OperationContext;
+import org.jboss.as.controller.OperationFailedException;
+import org.jboss.as.controller.registry.Resource;
 import org.jboss.as.server.AbstractDeploymentChainStep;
 import org.jboss.as.server.DeploymentProcessorTarget;
 import org.jboss.as.server.deployment.Phase;
 import org.jboss.dmr.ModelNode;
 
-import org.keycloak.subsystem.server.extension.authserver.KeycloakServerDeploymentProcessor;
+import static org.keycloak.subsystem.server.extension.KeycloakExtension.SUBSYSTEM_NAME;
+import static org.keycloak.subsystem.server.extension.KeycloakSubsystemDefinition.ALL_ATTRIBUTES;
+import static org.keycloak.subsystem.server.extension.KeycloakSubsystemDefinition.WEB_CONTEXT;
 
 /**
  * The Keycloak subsystem add update handler.
@@ -35,15 +40,44 @@ class KeycloakSubsystemAdd extends AbstractBoottimeAddStepHandler {
     static final KeycloakSubsystemAdd INSTANCE = new KeycloakSubsystemAdd();
 
     @Override
-    protected void performBoottime(final OperationContext context, ModelNode operation, final ModelNode model) {
+    protected void performBoottime(final OperationContext context, final ModelNode operation, final ModelNode model) {
         context.addStep(new AbstractDeploymentChainStep() {
             @Override
             protected void execute(DeploymentProcessorTarget processorTarget) {
-                processorTarget.addDeploymentProcessor(KeycloakExtension.SUBSYSTEM_NAME,
+                processorTarget.addDeploymentProcessor(SUBSYSTEM_NAME,
                         Phase.POST_MODULE, // PHASE
                         Phase.POST_MODULE_VALIDATOR_FACTORY - 1, // PRIORITY
                         new KeycloakServerDeploymentProcessor());
             }
         }, OperationContext.Stage.RUNTIME);
     }
+
+    protected void populateModel(final OperationContext context, final ModelNode operation, final Resource resource) throws  OperationFailedException {
+        ModelNode model = resource.getModel();
+
+        // set attribute values from parsed model
+        for (AttributeDefinition attrDef : ALL_ATTRIBUTES) {
+            attrDef.validateAndSet(operation, model);
+        }
+
+        // returns early if on domain controller
+        if (!requiresRuntime(context)) {
+            return;
+        }
+
+        // don't want to try to start server on host controller
+        if (!context.isNormalServer()) {
+            return;
+        }
+
+        ModelNode webContextNode = resource.getModel().get(WEB_CONTEXT.getName());
+        if (!webContextNode.isDefined()) {
+            webContextNode = WEB_CONTEXT.getDefaultValue();
+        }
+        String webContext = webContextNode.asString();
+
+        ServerUtil serverUtil = new ServerUtil(operation);
+        serverUtil.addStepToUploadServerWar(context);
+        KeycloakAdapterConfigService.INSTANCE.setWebContext(webContext);
+    }
 }
diff --git a/integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakSubsystemDefinition.java b/integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakSubsystemDefinition.java
index f553188..25ed28a 100644
--- a/integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakSubsystemDefinition.java
+++ b/integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakSubsystemDefinition.java
@@ -14,25 +14,56 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-
 package org.keycloak.subsystem.server.extension;
 
-import org.jboss.as.controller.ReloadRequiredRemoveStepHandler;
+import org.jboss.as.controller.AttributeDefinition;
+import org.jboss.as.controller.SimpleAttributeDefinition;
+import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
 import org.jboss.as.controller.SimpleResourceDefinition;
 import org.jboss.as.controller.operations.common.GenericSubsystemDescribeHandler;
 import org.jboss.as.controller.registry.ManagementResourceRegistration;
+import org.jboss.dmr.ModelNode;
+import org.jboss.dmr.ModelType;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 /**
- * Definition of subsystem=keycloak.
+ * Definition of subsystem=keycloak-server.
  *
  * @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
  */
 public class KeycloakSubsystemDefinition extends SimpleResourceDefinition {
+
+    static final SimpleAttributeDefinition WEB_CONTEXT =
+        new SimpleAttributeDefinitionBuilder("web-context", ModelType.STRING, true)
+            .setAllowExpression(true)
+            .setDefaultValue(new ModelNode("auth"))
+            .setRestartAllServices()
+            .build();
+
+    static final List<SimpleAttributeDefinition> ALL_ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
+
+    static {
+        ALL_ATTRIBUTES.add(WEB_CONTEXT);
+    }
+
+    private static final Map<String, SimpleAttributeDefinition> DEFINITION_LOOKUP = new HashMap<String, SimpleAttributeDefinition>();
+    static {
+        for (SimpleAttributeDefinition def : ALL_ATTRIBUTES) {
+            DEFINITION_LOOKUP.put(def.getXmlName(), def);
+        }
+    }
+
+    private static KeycloakSubsystemWriteAttributeHandler attrHandler = new KeycloakSubsystemWriteAttributeHandler(ALL_ATTRIBUTES);
+
     protected KeycloakSubsystemDefinition() {
-        super(KeycloakExtension.SUBSYSTEM_PATH,
-                KeycloakExtension.getResourceDescriptionResolver("subsystem"),
-                KeycloakSubsystemAdd.INSTANCE,
-                ReloadRequiredRemoveStepHandler.INSTANCE
+        super(KeycloakExtension.PATH_SUBSYSTEM,
+            KeycloakExtension.getResourceDescriptionResolver("subsystem"),
+            KeycloakSubsystemAdd.INSTANCE,
+            KeycloakSubsystemRemoveHandler.INSTANCE
         );
     }
 
@@ -42,4 +73,15 @@ public class KeycloakSubsystemDefinition extends SimpleResourceDefinition {
         resourceRegistration.registerOperationHandler(GenericSubsystemDescribeHandler.DEFINITION, GenericSubsystemDescribeHandler.INSTANCE);
     }
 
+    @Override
+    public void registerAttributes(ManagementResourceRegistration resourceRegistration) {
+        super.registerAttributes(resourceRegistration);
+        for (AttributeDefinition attrDef : ALL_ATTRIBUTES) {
+            resourceRegistration.registerReadWriteAttribute(attrDef, null, attrHandler);
+        }
+    }
+
+    public static SimpleAttributeDefinition lookup(String name) {
+        return DEFINITION_LOOKUP.get(name);
+    }
 }
diff --git a/integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakSubsystemParser.java b/integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakSubsystemParser.java
index 921c576..53d35db 100755
--- a/integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakSubsystemParser.java
+++ b/integration/wildfly/wildfly-server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakSubsystemParser.java
@@ -16,17 +16,11 @@
  */
 package org.keycloak.subsystem.server.extension;
 
-import org.keycloak.subsystem.server.extension.authserver.AuthServerDefinition;
-import org.jboss.as.controller.AttributeDefinition;
 import org.jboss.as.controller.PathAddress;
-import org.jboss.as.controller.PathElement;
-import org.jboss.as.controller.SimpleAttributeDefinition;
-import org.jboss.as.controller.descriptions.ModelDescriptionConstants;
 import org.jboss.as.controller.operations.common.Util;
 import org.jboss.as.controller.parsing.ParseUtils;
 import org.jboss.as.controller.persistence.SubsystemMarshallingContext;
 import org.jboss.dmr.ModelNode;
-import org.jboss.dmr.Property;
 import org.jboss.staxmapper.XMLElementReader;
 import org.jboss.staxmapper.XMLElementWriter;
 import org.jboss.staxmapper.XMLExtendedStreamReader;
@@ -34,9 +28,11 @@ import org.jboss.staxmapper.XMLExtendedStreamWriter;
 
 import javax.xml.stream.XMLStreamConstants;
 import javax.xml.stream.XMLStreamException;
-import java.util.Collections;
 import java.util.List;
 
+import static org.keycloak.subsystem.server.extension.KeycloakExtension.PATH_SUBSYSTEM;
+import static org.keycloak.subsystem.server.extension.KeycloakSubsystemDefinition.WEB_CONTEXT;
+
 /**
  * The subsystem parser, which uses stax to read and write to and from xml
  */
@@ -49,12 +45,14 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader<Li
     public void readElement(final XMLExtendedStreamReader reader, final List<ModelNode> list) throws XMLStreamException {
         // Require no attributes
         ParseUtils.requireNoAttributes(reader);
-        ModelNode addKeycloakSub = Util.createAddOperation(PathAddress.pathAddress(KeycloakExtension.PATH_SUBSYSTEM));
+        ModelNode addKeycloakSub = Util.createAddOperation(PathAddress.pathAddress(PATH_SUBSYSTEM));
         list.add(addKeycloakSub);
 
         while (reader.hasNext() && nextTag(reader) != END_ELEMENT) {
-            if (reader.getLocalName().equals(AuthServerDefinition.TAG_NAME)) {
-                readAuthServer(reader, list);
+            if (reader.getLocalName().equals(WEB_CONTEXT.getXmlName())) {
+                WEB_CONTEXT.parseAndSetParameter(reader.getElementText(), addKeycloakSub, reader);
+            } else {
+                throw new XMLStreamException("Unknown keycloak-server subsystem tag: " + reader.getLocalName());
             }
         }
     }
@@ -64,64 +62,21 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader<Li
         return reader.nextTag();
     }
 
-    private void readAuthServer(XMLExtendedStreamReader reader, List<ModelNode> list) throws XMLStreamException {
-        String authServerName = readNameAttribute(reader);
-        ModelNode addAuthServer = new ModelNode();
-        addAuthServer.get(ModelDescriptionConstants.OP).set(ModelDescriptionConstants.ADD);
-        PathAddress addr = PathAddress.pathAddress(PathElement.pathElement(ModelDescriptionConstants.SUBSYSTEM, KeycloakExtension.SUBSYSTEM_NAME),
-                                                   PathElement.pathElement(AuthServerDefinition.TAG_NAME, authServerName));
-        addAuthServer.get(ModelDescriptionConstants.OP_ADDR).set(addr.toModelNode());
-
-        while (reader.hasNext() && nextTag(reader) != END_ELEMENT) {
-            String tagName = reader.getLocalName();
-            SimpleAttributeDefinition def = AuthServerDefinition.lookup(tagName);
-            if (def == null) throw new XMLStreamException("Unknown auth-server tag " + tagName);
-            def.parseAndSetParameter(reader.getElementText(), addAuthServer, reader);
-        }
-
-        list.add(addAuthServer);
-    }
-
-    // expects that the current tag will have one single attribute called "name"
-    private String readNameAttribute(XMLExtendedStreamReader reader) throws XMLStreamException {
-        String name = null;
-        for (int i = 0; i < reader.getAttributeCount(); i++) {
-            String attr = reader.getAttributeLocalName(i);
-            if (attr.equals("name")) {
-                name = reader.getAttributeValue(i);
-                continue;
-            }
-            throw ParseUtils.unexpectedAttribute(reader, i);
-        }
-        if (name == null) {
-            throw ParseUtils.missingRequired(reader, Collections.singleton("name"));
-        }
-        return name;
-    }
-
     /**
      * {@inheritDoc}
      */
     @Override
     public void writeContent(final XMLExtendedStreamWriter writer, final SubsystemMarshallingContext context) throws XMLStreamException {
         context.startSubsystemElement(KeycloakExtension.NAMESPACE, false);
-        writeAuthServers(writer, context);
+        writeWebContext(writer, context);
         writer.writeEndElement();
     }
 
-    private void writeAuthServers(XMLExtendedStreamWriter writer, SubsystemMarshallingContext context) throws XMLStreamException {
-        if (!context.getModelNode().get(AuthServerDefinition.TAG_NAME).isDefined()) {
+    private void writeWebContext(XMLExtendedStreamWriter writer, SubsystemMarshallingContext context) throws XMLStreamException {
+        if (!context.getModelNode().get(WEB_CONTEXT.getName()).isDefined()) {
             return;
         }
-        for (Property authServer : context.getModelNode().get(AuthServerDefinition.TAG_NAME).asPropertyList()) {
-            writer.writeStartElement(AuthServerDefinition.TAG_NAME);
-            writer.writeAttribute("name", authServer.getName());
-            ModelNode authServerElements = authServer.getValue();
-            for (AttributeDefinition element : AuthServerDefinition.ALL_ATTRIBUTES) {
-                element.marshallAsElement(authServerElements, writer);
-            }
 
-            writer.writeEndElement();
-        }
+        WEB_CONTEXT.marshallAsElement(context.getModelNode(), writer);
     }
 }
diff --git a/integration/wildfly/wildfly-server-subsystem/src/main/resources/org/keycloak/subsystem/server/extension/LocalDescriptions.properties b/integration/wildfly/wildfly-server-subsystem/src/main/resources/org/keycloak/subsystem/server/extension/LocalDescriptions.properties
index f09e3bd..909e6b3 100755
--- a/integration/wildfly/wildfly-server-subsystem/src/main/resources/org/keycloak/subsystem/server/extension/LocalDescriptions.properties
+++ b/integration/wildfly/wildfly-server-subsystem/src/main/resources/org/keycloak/subsystem/server/extension/LocalDescriptions.properties
@@ -1,26 +1,4 @@
 keycloak-server.subsystem=Keycloak subsystem
 keycloak-server.subsystem.add=Operation Adds Keycloak subsystem
 keycloak-server.subsystem.remove=Operation removes Keycloak subsystem
-keycloak-server.subsystem.auth-server=Keycloak Auth Server
-keycloak-server.subsystem.realm=A Keycloak realm.
-keycloak-server.subsystem.secure-deployment=A deployment secured by Keycloak.
-
-
-keycloak-server.auth-server=A Keycloak Auth Server
-keycloak-server.auth-server.add=Add an Auth Server to the subsystem.
-keycloak-server.auth-server.remove=Remove an Auth Server from the subsystem.
-keycloak-server.auth-server.add-provider=Add a provider service jar to the Keycloak auth server.
-keycloak-server.auth-server.add-provider.uploaded-file-name=The file name of the provider service jar to be added or updated.
-keycloak-server.auth-server.add-provider.bytes-to-upload=The bytes of the provider service jar to be added or updated.
-keycloak-server.auth-server.add-provider.redeploy=Redeploy the auth server after adding the provider.  Ignored if auth server is disabled.
-keycloak-server.auth-server.add-provider.overwrite=Overwrite even if the uploaded-file-name already exists as an overlay.
-keycloak-server.auth-server.list-overlays=List the overlays uploaded for this auth server.
-keycloak-server.auth-server.remove-overlay=Remove a provider jar, theme jar, or keycloak-server.json that has been uploaded to the auth server.
-keycloak-server.auth-server.remove-overlay.overlay-file-path=The uploaded path and file name of the overlay to be removed.
-keycloak-server.auth-server.remove-overlay.redeploy=Redeploy the auth server after removing the overlay.
-keycloak-server.auth-server.update-server-config=Upload a new keycloak-server.json configuration file for the Keycloak auth server.
-keycloak-server.auth-server.update-server-config.bytes-to-upload=The bytes of the keycloak-server.json file to be added or updated.
-keycloak-server.auth-server.update-server-config.redeploy=Redeploy the auth server after updating the server config.
-keycloak-server.auth-server.update-server-config.overwrite=Overwrite even if keycloak-server.json already exitss as an overlay.
-keycloak-server.auth-server.enabled=Enable or disable the Auth Server.
-keycloak-server.auth-server.web-context=Web context the auth-server will use.  Also, the module name of the auth-server deployment.
+keycloak-server.subsystem.web-context=Web context where Keycloak server is bound. Default value is 'auth'.
diff --git a/integration/wildfly/wildfly-server-subsystem/src/main/resources/schema/wildfly-keycloak-server_1_1.xsd b/integration/wildfly/wildfly-server-subsystem/src/main/resources/schema/wildfly-keycloak-server_1_1.xsd
index a8dd28e..b346d36 100755
--- a/integration/wildfly/wildfly-server-subsystem/src/main/resources/schema/wildfly-keycloak-server_1_1.xsd
+++ b/integration/wildfly/wildfly-server-subsystem/src/main/resources/schema/wildfly-keycloak-server_1_1.xsd
@@ -18,21 +18,8 @@
                 ]]>
             </xs:documentation>
         </xs:annotation>
-        <xs:choice minOccurs="0" maxOccurs="unbounded">
-            <xs:element name="auth-server" maxOccurs="1" minOccurs="0" type="auth-server-type"/>
+        <xs:choice minOccurs="0" maxOccurs="1">
+            <xs:element name="web-context" type="xs:string" minOccurs="0" maxOccurs="1"/>
         </xs:choice>
     </xs:complexType>
-
-    <xs:complexType name="auth-server-type">
-        <xs:all>
-            <xs:element name="web-context" type="xs:string" minOccurs="1" maxOccurs="1"/>
-            <xs:element name="enabled" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
-        </xs:all>
-        <xs:attribute name="name" type="xs:string" use="required">
-            <xs:annotation>
-                <xs:documentation>The name of the war archive containing the Keycloak server web application.</xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-    </xs:complexType>
-
 </xs:schema>
diff --git a/integration/wildfly/wildfly-server-subsystem/src/main/resources/subsystem-templates/keycloak-server.xml b/integration/wildfly/wildfly-server-subsystem/src/main/resources/subsystem-templates/keycloak-server.xml
index 7f66f74..4a83086 100644
--- a/integration/wildfly/wildfly-server-subsystem/src/main/resources/subsystem-templates/keycloak-server.xml
+++ b/integration/wildfly/wildfly-server-subsystem/src/main/resources/subsystem-templates/keycloak-server.xml
@@ -3,9 +3,6 @@
 <config>
    <extension-module>org.keycloak.keycloak-server-subsystem</extension-module>
    <subsystem xmlns="urn:jboss:domain:keycloak-server:1.1">
-      <auth-server name="main-auth-server">
-         <enabled>true</enabled>
-         <web-context>auth</web-context>
-      </auth-server>
+      <web-context>auth</web-context>
    </subsystem>
 </config>
diff --git a/integration/wildfly/wildfly-server-subsystem/src/test/java/org/keycloak/subsystem/server/extension/SubsystemParsingTestCase.java b/integration/wildfly/wildfly-server-subsystem/src/test/java/org/keycloak/subsystem/server/extension/SubsystemParsingTestCase.java
index 9f29a6f..405b06b 100755
--- a/integration/wildfly/wildfly-server-subsystem/src/test/java/org/keycloak/subsystem/server/extension/SubsystemParsingTestCase.java
+++ b/integration/wildfly/wildfly-server-subsystem/src/test/java/org/keycloak/subsystem/server/extension/SubsystemParsingTestCase.java
@@ -41,7 +41,6 @@ public class SubsystemParsingTestCase extends AbstractSubsystemBaseTest {
     @Test
     public void testJson() throws Exception {
         ModelNode node = new ModelNode();
-        node.get("enabled").set(true);
         node.get("web-context").set("auth");
 
         System.out.println("json=" + node.toJSONString(false));
diff --git a/integration/wildfly/wildfly-server-subsystem/src/test/resources/org/keycloak/subsystem/server/extension/keycloak-server-1.1.xml b/integration/wildfly/wildfly-server-subsystem/src/test/resources/org/keycloak/subsystem/server/extension/keycloak-server-1.1.xml
index f05f8d1..bc8f11a 100644
--- a/integration/wildfly/wildfly-server-subsystem/src/test/resources/org/keycloak/subsystem/server/extension/keycloak-server-1.1.xml
+++ b/integration/wildfly/wildfly-server-subsystem/src/test/resources/org/keycloak/subsystem/server/extension/keycloak-server-1.1.xml
@@ -1,6 +1,3 @@
 <subsystem xmlns="urn:jboss:domain:keycloak-server:1.1">
-    <auth-server name="main-auth-server">
-        <enabled>true</enabled>
-        <web-context>auth</web-context>
-    </auth-server>
+    <web-context>auth</web-context>
 </subsystem>
\ No newline at end of file
diff --git a/model/api/src/main/java/org/keycloak/mappers/UserFederationMapperSpi.java b/model/api/src/main/java/org/keycloak/mappers/UserFederationMapperSpi.java
index f668058..9597f08 100644
--- a/model/api/src/main/java/org/keycloak/mappers/UserFederationMapperSpi.java
+++ b/model/api/src/main/java/org/keycloak/mappers/UserFederationMapperSpi.java
@@ -25,7 +25,7 @@ public class UserFederationMapperSpi implements Spi {
     }
 
     @Override
-    public boolean isPrivate() {
-        return false;
+    public boolean isInternal() {
+        return true;
     }
 }
diff --git a/model/api/src/main/java/org/keycloak/migration/MigrationModel.java b/model/api/src/main/java/org/keycloak/migration/MigrationModel.java
index 936fbcf..df24b3d 100755
--- a/model/api/src/main/java/org/keycloak/migration/MigrationModel.java
+++ b/model/api/src/main/java/org/keycloak/migration/MigrationModel.java
@@ -11,7 +11,7 @@ public interface MigrationModel {
     /**
      * Must have the form of major.minor.micro as the version is parsed and numbers are compared
      */
-    public static final String LATEST_VERSION = "1.2.0.CR1";
+    public static final String LATEST_VERSION = "1.3.0.Beta1";
 
     String getStoredVersion();
     void setStoredVersion(String version);
diff --git a/model/api/src/main/java/org/keycloak/migration/MigrationModelManager.java b/model/api/src/main/java/org/keycloak/migration/MigrationModelManager.java
index 7f52ab3..5d58fe1 100755
--- a/model/api/src/main/java/org/keycloak/migration/MigrationModelManager.java
+++ b/model/api/src/main/java/org/keycloak/migration/MigrationModelManager.java
@@ -17,11 +17,13 @@ public class MigrationModelManager {
         String storedVersion = model.getStoredVersion();
         if (MigrationModel.LATEST_VERSION.equals(storedVersion)) return;
         ModelVersion stored = null;
-        if (storedVersion != null) new ModelVersion(storedVersion);
+        if (storedVersion != null) {
+            stored = new ModelVersion(storedVersion);
+        }
 
         if (stored == null || stored.lessThan(MigrationTo1_2_0_CR1.VERSION)) {
             if (stored != null) {
-                logger.debug("Migrating older model to 1.2.0.RC1 updates");
+                logger.debug("Migrating older model to 1.2.0.CR1 updates");
             }
             new MigrationTo1_2_0_CR1().migrate(session);
         }
diff --git a/model/api/src/main/java/org/keycloak/migration/MigrationSpi.java b/model/api/src/main/java/org/keycloak/migration/MigrationSpi.java
index e599146..cc9601a 100644
--- a/model/api/src/main/java/org/keycloak/migration/MigrationSpi.java
+++ b/model/api/src/main/java/org/keycloak/migration/MigrationSpi.java
@@ -10,7 +10,7 @@ import org.keycloak.provider.Spi;
 public class MigrationSpi implements Spi {
 
     @Override
-    public boolean isPrivate() {
+    public boolean isInternal() {
         return true;
     }
 
diff --git a/model/api/src/main/java/org/keycloak/migration/migrators/MigrateTo1_3_0_Beta1.java b/model/api/src/main/java/org/keycloak/migration/migrators/MigrateTo1_3_0_Beta1.java
index ccf3c75..195910b 100755
--- a/model/api/src/main/java/org/keycloak/migration/migrators/MigrateTo1_3_0_Beta1.java
+++ b/model/api/src/main/java/org/keycloak/migration/migrators/MigrateTo1_3_0_Beta1.java
@@ -2,10 +2,20 @@ package org.keycloak.migration.migrators;
 
 import org.keycloak.migration.ModelVersion;
 import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.LDAPConstants;
 import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserFederationEventAwareProviderFactory;
+import org.keycloak.models.UserFederationMapperModel;
+import org.keycloak.models.UserFederationProvider;
+import org.keycloak.models.UserFederationProviderFactory;
+import org.keycloak.models.UserFederationProviderModel;
 import org.keycloak.models.utils.DefaultAuthenticationFlows;
 
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.naming.directory.SearchControls;
 
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -21,7 +31,54 @@ public class MigrateTo1_3_0_Beta1 {
             if (realm.getAuthenticationFlows().size() == 0) {
                 DefaultAuthenticationFlows.addFlows(realm);
             }
+
+            migrateLDAPProviders(session, realm);
         }
 
     }
+
+    private void migrateLDAPProviders(KeycloakSession session, RealmModel realm) {
+        List<UserFederationProviderModel> federationProviders = realm.getUserFederationProviders();
+        for (UserFederationProviderModel fedProvider : federationProviders) {
+
+            if (fedProvider.getProviderName().equals(LDAPConstants.LDAP_PROVIDER)) {
+                Map<String, String> config = fedProvider.getConfig();
+
+                // Update config properties for LDAP federation provider
+                if (config.get(LDAPConstants.SEARCH_SCOPE) == null) {
+                    config.put(LDAPConstants.SEARCH_SCOPE, String.valueOf(SearchControls.SUBTREE_SCOPE));
+                }
+
+                String usersDn = config.remove("userDnSuffix");
+                if (usersDn != null && config.get(LDAPConstants.USERS_DN) == null) {
+                    config.put(LDAPConstants.USERS_DN, usersDn);
+                }
+
+                String usernameLdapAttribute = config.get(LDAPConstants.USERNAME_LDAP_ATTRIBUTE);
+                if (usernameLdapAttribute != null && config.get(LDAPConstants.RDN_LDAP_ATTRIBUTE) == null) {
+                    if (usernameLdapAttribute.equalsIgnoreCase(LDAPConstants.SAM_ACCOUNT_NAME)) {
+                        config.put(LDAPConstants.RDN_LDAP_ATTRIBUTE, LDAPConstants.CN);
+                    } else {
+                        config.put(LDAPConstants.RDN_LDAP_ATTRIBUTE, usernameLdapAttribute);
+                    }
+                }
+
+                if (config.get(LDAPConstants.UUID_LDAP_ATTRIBUTE) == null) {
+                    String uuidAttrName = LDAPConstants.getUuidAttributeName(config.get(LDAPConstants.VENDOR));
+                    config.put(LDAPConstants.UUID_LDAP_ATTRIBUTE, uuidAttrName);
+                }
+
+                realm.updateUserFederationProvider(fedProvider);
+
+                // Create default mappers for LDAP
+                Set<UserFederationMapperModel> mappers = realm.getUserFederationMappersByFederationProvider(fedProvider.getId());
+                if (mappers.isEmpty()) {
+                    UserFederationProviderFactory ldapFactory = (UserFederationProviderFactory) session.getKeycloakSessionFactory().getProviderFactory(UserFederationProvider.class, LDAPConstants.LDAP_PROVIDER);
+                    if (ldapFactory != null) {
+                        ((UserFederationEventAwareProviderFactory) ldapFactory).onProviderModelCreated(realm, fedProvider);
+                    }
+                }
+            }
+        }
+    }
 }
diff --git a/model/api/src/main/java/org/keycloak/migration/ModelVersion.java b/model/api/src/main/java/org/keycloak/migration/ModelVersion.java
index 1dfcd14..095576a 100755
--- a/model/api/src/main/java/org/keycloak/migration/ModelVersion.java
+++ b/model/api/src/main/java/org/keycloak/migration/ModelVersion.java
@@ -59,7 +59,7 @@ public class ModelVersion {
         if (major < version.major) return true;
         if (minor < version.minor) return true;
         if (micro < version.micro) return true;
-        if (qualifier == version.qualifier) return false;
+        if (qualifier != null && qualifier.equals(version.qualifier)) return false;
         if (qualifier == null) return false;
         if (version.qualifier == null) return true;
         int comp = qualifier.compareTo(version.qualifier);
diff --git a/model/api/src/main/java/org/keycloak/models/entities/AuthenticationExecutionEntity.java b/model/api/src/main/java/org/keycloak/models/entities/AuthenticationExecutionEntity.java
index c90a657..e98b371 100755
--- a/model/api/src/main/java/org/keycloak/models/entities/AuthenticationExecutionEntity.java
+++ b/model/api/src/main/java/org/keycloak/models/entities/AuthenticationExecutionEntity.java
@@ -13,7 +13,7 @@ public class AuthenticationExecutionEntity {
     protected AuthenticationExecutionModel.Requirement requirement;
     protected int priority;
     private boolean userSetupAllowed;
-    private boolean autheticatorFlow;
+    private boolean authenticatorFlow;
     private String parentFlow;
 
     public String getId() {
@@ -56,12 +56,12 @@ public class AuthenticationExecutionEntity {
         this.userSetupAllowed = userSetupAllowed;
     }
 
-    public boolean isAutheticatorFlow() {
-        return autheticatorFlow;
+    public boolean isAuthenticatorFlow() {
+        return authenticatorFlow;
     }
 
-    public void setAutheticatorFlow(boolean autheticatorFlow) {
-        this.autheticatorFlow = autheticatorFlow;
+    public void setAuthenticatorFlow(boolean authenticatorFlow) {
+        this.authenticatorFlow = authenticatorFlow;
     }
 
     public String getParentFlow() {
diff --git a/model/api/src/main/java/org/keycloak/models/entities/IdentityProviderEntity.java b/model/api/src/main/java/org/keycloak/models/entities/IdentityProviderEntity.java
index 04dd0bc..c4cdd62 100755
--- a/model/api/src/main/java/org/keycloak/models/entities/IdentityProviderEntity.java
+++ b/model/api/src/main/java/org/keycloak/models/entities/IdentityProviderEntity.java
@@ -30,7 +30,8 @@ public class IdentityProviderEntity {
     private String providerId;
     private String name;
     private boolean enabled;
-    private boolean updateProfileFirstLogin;
+    private String updateProfileFirstLoginMode;
+    private boolean trustEmail;
     private boolean storeToken;
     protected boolean addReadTokenRoleOnCreate;
     private boolean authenticateByDefault;
@@ -61,12 +62,12 @@ public class IdentityProviderEntity {
         this.enabled = enabled;
     }
 
-    public boolean isUpdateProfileFirstLogin() {
-        return updateProfileFirstLogin;
+    public String getUpdateProfileFirstLoginMode() {
+        return updateProfileFirstLoginMode;
     }
 
-    public void setUpdateProfileFirstLogin(boolean updateProfileFirstLogin) {
-        this.updateProfileFirstLogin = updateProfileFirstLogin;
+    public void setUpdateProfileFirstLoginMode(String updateProfileFirstLoginMode) {
+        this.updateProfileFirstLoginMode = updateProfileFirstLoginMode;
     }
 
     public boolean isAuthenticateByDefault() {
@@ -116,4 +117,12 @@ public class IdentityProviderEntity {
     public void setAddReadTokenRoleOnCreate(boolean addReadTokenRoleOnCreate) {
         this.addReadTokenRoleOnCreate = addReadTokenRoleOnCreate;
     }
+
+    public boolean isTrustEmail() {
+        return trustEmail;
+    }
+
+    public void setTrustEmail(boolean trustEmail) {
+        this.trustEmail = trustEmail;
+    }
 }
diff --git a/model/api/src/main/java/org/keycloak/models/entities/RealmEntity.java b/model/api/src/main/java/org/keycloak/models/entities/RealmEntity.java
index 7c393bb..827c80b 100755
--- a/model/api/src/main/java/org/keycloak/models/entities/RealmEntity.java
+++ b/model/api/src/main/java/org/keycloak/models/entities/RealmEntity.java
@@ -17,9 +17,9 @@ public class RealmEntity extends AbstractIdentifiableEntity {
     protected boolean registrationEmailAsUsername;
     private boolean rememberMe;
     private boolean verifyEmail;
-    private boolean passwordCredentialGrantAllowed;
     private boolean resetPasswordAllowed;
     private String passwordPolicy;
+    private boolean editUsernameAllowed;
     //--- brute force settings
     private boolean bruteForceProtected;
     private int maxFailureWaitSeconds;
@@ -102,14 +102,6 @@ public class RealmEntity extends AbstractIdentifiableEntity {
         this.sslRequired = sslRequired;
     }
 
-    public boolean isPasswordCredentialGrantAllowed() {
-        return passwordCredentialGrantAllowed;
-    }
-
-    public void setPasswordCredentialGrantAllowed(boolean passwordCredentialGrantAllowed) {
-        this.passwordCredentialGrantAllowed = passwordCredentialGrantAllowed;
-    }
-
     public boolean isRegistrationAllowed() {
         return registrationAllowed;
     }
@@ -150,6 +142,14 @@ public class RealmEntity extends AbstractIdentifiableEntity {
         this.resetPasswordAllowed = resetPasswordAllowed;
     }
 
+    public boolean isEditUsernameAllowed() {
+        return editUsernameAllowed;
+    }
+
+    public void setEditUsernameAllowed(boolean editUsernameAllowed) {
+        this.editUsernameAllowed = editUsernameAllowed;
+    }
+
     public String getPasswordPolicy() {
         return passwordPolicy;
     }
diff --git a/model/api/src/main/java/org/keycloak/models/IdentityProviderModel.java b/model/api/src/main/java/org/keycloak/models/IdentityProviderModel.java
index c7cb4a7..0c34e4b 100755
--- a/model/api/src/main/java/org/keycloak/models/IdentityProviderModel.java
+++ b/model/api/src/main/java/org/keycloak/models/IdentityProviderModel.java
@@ -20,6 +20,8 @@ package org.keycloak.models;
 import java.util.HashMap;
 import java.util.Map;
 
+import org.keycloak.representations.idm.IdentityProviderRepresentation;
+
 /**
  * <p>A model type representing the configuration for identity providers. It provides some common properties and also a {@link org.keycloak.models.IdentityProviderModel#config}
  * for configuration options and properties specifics to a identity provider.</p>
@@ -43,7 +45,15 @@ public class IdentityProviderModel {
 
     private boolean enabled;
 
-    private boolean updateProfileFirstLogin = true;
+    /**
+     * For possible values see {@link IdentityProviderRepresentation#getUpdateProfileFirstLoginMode()}
+     * @see IdentityProviderRepresentation#UPFLM_ON
+     * @see IdentityProviderRepresentation#UPFLM_MISSING
+     * @see IdentityProviderRepresentation#UPFLM_OFF
+     */
+    protected String updateProfileFirstLoginMode = IdentityProviderRepresentation.UPFLM_ON;
+    
+    private boolean trustEmail;
 
     private boolean storeToken;
 
@@ -68,7 +78,8 @@ public class IdentityProviderModel {
         this.alias = model.getAlias();
         this.config = new HashMap<String, String>(model.getConfig());
         this.enabled = model.isEnabled();
-        this.updateProfileFirstLogin = model.isUpdateProfileFirstLogin();
+        this.updateProfileFirstLoginMode = model.getUpdateProfileFirstLoginMode();
+        this.trustEmail = model.isTrustEmail();
         this.storeToken = model.isStoreToken();
         this.authenticateByDefault = model.isAuthenticateByDefault();
         this.addReadTokenRoleOnCreate = model.addReadTokenRoleOnCreate;
@@ -106,12 +117,18 @@ public class IdentityProviderModel {
         this.enabled = enabled;
     }
 
-    public boolean isUpdateProfileFirstLogin() {
-        return this.updateProfileFirstLogin;
+    /**
+     * @see IdentityProviderRepresentation#getUpdateProfileFirstLoginMode() 
+     */
+    public String getUpdateProfileFirstLoginMode() {
+        return updateProfileFirstLoginMode;
     }
 
-    public void setUpdateProfileFirstLogin(boolean updateProfileFirstLogin) {
-        this.updateProfileFirstLogin = updateProfileFirstLogin;
+    /**
+     * @see IdentityProviderRepresentation#setUpdateProfileFirstLoginMode(String) 
+     */
+    public void setUpdateProfileFirstLoginMode(String updateProfileFirstLoginMode) {
+        this.updateProfileFirstLoginMode = updateProfileFirstLoginMode;
     }
 
     public boolean isStoreToken() {
@@ -145,4 +162,13 @@ public class IdentityProviderModel {
     public void setAddReadTokenRoleOnCreate(boolean addReadTokenRoleOnCreate) {
         this.addReadTokenRoleOnCreate = addReadTokenRoleOnCreate;
     }
+
+    public boolean isTrustEmail() {
+        return trustEmail;
+    }
+
+    public void setTrustEmail(boolean trustEmail) {
+        this.trustEmail = trustEmail;
+    }
+    
 }
diff --git a/model/api/src/main/java/org/keycloak/models/LDAPConstants.java b/model/api/src/main/java/org/keycloak/models/LDAPConstants.java
index c0c24a8..0d97664 100644
--- a/model/api/src/main/java/org/keycloak/models/LDAPConstants.java
+++ b/model/api/src/main/java/org/keycloak/models/LDAPConstants.java
@@ -5,6 +5,8 @@ package org.keycloak.models;
  */
 public class LDAPConstants {
 
+    public static final String LDAP_PROVIDER = "ldap";
+
     public static final String VENDOR = "vendor";
     public static final String VENDOR_RHDS = "rhds";
     public static final String VENDOR_ACTIVE_DIRECTORY = "ad";
@@ -19,6 +21,7 @@ public class LDAPConstants {
 
     public static final String CONNECTION_URL = "connectionUrl";
     public static final String SECURITY_PROTOCOL = "securityProtocol";
+    public static final String BASE_DN = "baseDn"; // used for tests only
     public static final String USERS_DN = "usersDn";
     public static final String BIND_DN = "bindDn";
     public static final String BIND_CREDENTIAL = "bindCredential";
@@ -51,7 +54,7 @@ public class LDAPConstants {
     public static final String CONFIG_DIVIDER = ":::";
 
     // Those are forked from Picketlink
-    public static final String GIVENNAME = "givenname";
+    public static final String GIVENNAME = "givenName";
     public static final String CN = "cn";
     public static final String SN = "sn";
     public static final String SAM_ACCOUNT_NAME = "sAMAccountName";
@@ -62,6 +65,7 @@ public class LDAPConstants {
     public static final String OBJECT_CLASS = "objectclass";
     public static final String UID = "uid";
     public static final String USER_PASSWORD_ATTRIBUTE = "userpassword";
+    public static final String GROUP = "group";
     public static final String GROUP_OF_NAMES = "groupOfNames";
     public static final String GROUP_OF_ENTRIES = "groupOfEntries";
     public static final String GROUP_OF_UNIQUE_NAMES = "groupOfUniqueNames";
@@ -69,6 +73,7 @@ public class LDAPConstants {
     public static final String COMMA = ",";
     public static final String EQUAL = "=";
     public static final String EMPTY_ATTRIBUTE_VALUE = " ";
+    public static final String EMPTY_MEMBER_ATTRIBUTE_VALUE = "";
 
     public static final String CUSTOM_ATTRIBUTE_ENABLED = "enabled";
     public static final String CUSTOM_ATTRIBUTE_CREATE_DATE = "createDate";
@@ -77,4 +82,21 @@ public class LDAPConstants {
     public static final String OBJECT_GUID = "objectGUID";
     public static final String CREATE_TIMESTAMP = "createTimestamp";
     public static final String MODIFY_TIMESTAMP = "modifyTimestamp";
+
+    public static String getUuidAttributeName(String vendor) {
+        if (vendor != null) {
+            switch (vendor) {
+                case VENDOR_RHDS:
+                    return "nsuniqueid";
+                case VENDOR_TIVOLI:
+                    return "uniqueidentifier";
+                case VENDOR_NOVELL_EDIRECTORY:
+                    return "guid";
+                case VENDOR_ACTIVE_DIRECTORY:
+                    return OBJECT_GUID;
+            }
+        }
+
+        return ENTRY_UUID;
+    }
 }
diff --git a/model/api/src/main/java/org/keycloak/models/RealmModel.java b/model/api/src/main/java/org/keycloak/models/RealmModel.java
index 43eaa30..61bdbee 100755
--- a/model/api/src/main/java/org/keycloak/models/RealmModel.java
+++ b/model/api/src/main/java/org/keycloak/models/RealmModel.java
@@ -29,6 +29,12 @@ public interface RealmModel extends RoleContainerModel {
         RealmModel getRealm();
     }
 
+    interface UserFederationMapperEvent extends ProviderEvent {
+        UserFederationMapperModel getFederationMapper();
+        RealmModel getRealm();
+        KeycloakSession getSession();
+    }
+
     String getId();
 
     String getName();
@@ -47,18 +53,18 @@ public interface RealmModel extends RoleContainerModel {
 
     void setRegistrationAllowed(boolean registrationAllowed);
 
-    public boolean isRegistrationEmailAsUsername();
-
-    public void setRegistrationEmailAsUsername(boolean registrationEmailAsUsername);
+    boolean isRegistrationEmailAsUsername();
 
-    boolean isPasswordCredentialGrantAllowed();
-
-    void setPasswordCredentialGrantAllowed(boolean passwordCredentialGrantAllowed);
+    void setRegistrationEmailAsUsername(boolean registrationEmailAsUsername);
 
     boolean isRememberMe();
 
     void setRememberMe(boolean rememberMe);
 
+    boolean isEditUsernameAllowed();
+
+    void setEditUsernameAllowed(boolean editUsernameAllowed);
+
     //--- brute force settings
     boolean isBruteForceProtected();
     void setBruteForceProtected(boolean value);
diff --git a/model/api/src/main/java/org/keycloak/models/RealmSpi.java b/model/api/src/main/java/org/keycloak/models/RealmSpi.java
index f531cd9..ce49557 100755
--- a/model/api/src/main/java/org/keycloak/models/RealmSpi.java
+++ b/model/api/src/main/java/org/keycloak/models/RealmSpi.java
@@ -10,7 +10,7 @@ import org.keycloak.provider.Spi;
 public class RealmSpi implements Spi {
 
     @Override
-    public boolean isPrivate() {
+    public boolean isInternal() {
         return true;
     }
 
diff --git a/model/api/src/main/java/org/keycloak/models/UserFederationEventAwareProviderFactory.java b/model/api/src/main/java/org/keycloak/models/UserFederationEventAwareProviderFactory.java
index 866bf79..b409d87 100644
--- a/model/api/src/main/java/org/keycloak/models/UserFederationEventAwareProviderFactory.java
+++ b/model/api/src/main/java/org/keycloak/models/UserFederationEventAwareProviderFactory.java
@@ -29,5 +29,5 @@ public abstract class UserFederationEventAwareProviderFactory implements UserFed
         });
     }
 
-    protected abstract void onProviderModelCreated(RealmModel realm, UserFederationProviderModel createdProviderModel);
+    public abstract void onProviderModelCreated(RealmModel realm, UserFederationProviderModel createdProviderModel);
 }
diff --git a/model/api/src/main/java/org/keycloak/models/UserFederationManager.java b/model/api/src/main/java/org/keycloak/models/UserFederationManager.java
index bd07b77..4682ddd 100755
--- a/model/api/src/main/java/org/keycloak/models/UserFederationManager.java
+++ b/model/api/src/main/java/org/keycloak/models/UserFederationManager.java
@@ -20,6 +20,9 @@ public class UserFederationManager implements UserProvider {
 
     protected KeycloakSession session;
 
+    // Set of already validated/proxied federation users during this session. Key is user ID
+    private Map<String, UserModel> managedUsers = new HashMap<>();
+
     public UserFederationManager(KeycloakSession session) {
         this.session = session;
     }
@@ -47,7 +50,9 @@ public class UserFederationManager implements UserProvider {
             UserFederationProvider fed = getFederationProvider(federation);
             if (fed.synchronizeRegistrations()) {
                 user.setFederationLink(federation.getId());
-                return fed.register(realm, user);
+                UserModel registered = fed.register(realm, user);
+                managedUsers.put(registered.getId(), registered);
+                return registered;
             }
         }
         return user;
@@ -70,6 +75,7 @@ public class UserFederationManager implements UserProvider {
             boolean fedRemoved = link.removeUser(realm, user);
             if (fedRemoved) {
                 boolean localRemoved = session.userStorage().removeUser(realm, user);
+                managedUsers.remove(user.getId());
                 if (!localRemoved) {
                     logger.warn("User removed from federation provider, but failed to remove him from keycloak model");
                 }
@@ -84,6 +90,10 @@ public class UserFederationManager implements UserProvider {
     }
 
     protected void validateUser(RealmModel realm, UserModel user) {
+        if (managedUsers.containsKey(user.getId())) {
+            return;
+        }
+
         UserFederationProvider link = getFederationLink(realm, user);
         if (link != null  && !link.isValid(realm, user)) {
             deleteInvalidUser(realm, user);
@@ -100,7 +110,7 @@ public class UserFederationManager implements UserProvider {
             if (realmModel == null) return;
             UserModel deletedUser = tx.userStorage().getUserById(user.getId(), realmModel);
             tx.userStorage().removeUser(realmModel, deletedUser);
-            logger.debugf("Removed invalid user '%s'", user.getUsername());
+            logger.infof("Removed invalid user '%s'", user.getUsername());
             tx.getTransaction().commit();
         } finally {
             tx.close();
@@ -109,10 +119,16 @@ public class UserFederationManager implements UserProvider {
 
 
     protected UserModel validateAndProxyUser(RealmModel realm, UserModel user) {
+        UserModel managed = managedUsers.get(user.getId());
+        if (managed != null) {
+            return managed;
+        }
+
         UserFederationProvider link = getFederationLink(realm, user);
         if (link != null) {
             UserModel validatedProxyUser = link.validateAndProxy(realm, user);
             if (validatedProxyUser != null) {
+                managedUsers.put(user.getId(), user);
                 return validatedProxyUser;
             } else {
                 deleteInvalidUser(realm, user);
diff --git a/model/api/src/main/java/org/keycloak/models/UserFederationMapperEventImpl.java b/model/api/src/main/java/org/keycloak/models/UserFederationMapperEventImpl.java
new file mode 100644
index 0000000..212ecc3
--- /dev/null
+++ b/model/api/src/main/java/org/keycloak/models/UserFederationMapperEventImpl.java
@@ -0,0 +1,33 @@
+package org.keycloak.models;
+
+/**
+ * Called during creation or update of UserFederationMapperModel
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class UserFederationMapperEventImpl implements RealmModel.UserFederationMapperEvent {
+
+    private final UserFederationMapperModel mapperModel;
+    private final RealmModel realm;
+    private final KeycloakSession session;
+
+    public UserFederationMapperEventImpl(UserFederationMapperModel mapperModel, RealmModel realm, KeycloakSession session) {
+        this.mapperModel = mapperModel;
+        this.realm = realm;
+        this.session = session;
+    }
+
+    @Override
+    public UserFederationMapperModel getFederationMapper() {
+        return mapperModel;
+    }
+
+    @Override
+    public RealmModel getRealm() {
+        return realm;
+    }
+
+    public KeycloakSession getSession() {
+        return session;
+    }
+}
diff --git a/model/api/src/main/java/org/keycloak/models/UserFederationProvider.java b/model/api/src/main/java/org/keycloak/models/UserFederationProvider.java
index 7c97d67..8fdd45a 100755
--- a/model/api/src/main/java/org/keycloak/models/UserFederationProvider.java
+++ b/model/api/src/main/java/org/keycloak/models/UserFederationProvider.java
@@ -44,11 +44,12 @@ public interface UserFederationProvider extends Provider {
 
     /**
      * Gives the provider an option to validate if user still exists in federation backend and then proxy UserModel loaded from local storage.
-     * This method is called whenever a UserModel is pulled from local storage.
+     * This method is called whenever a UserModel is pulled from Keycloak local storage.
      * For example, the LDAP provider proxies the UserModel and does on-demand synchronization with
      * LDAP whenever UserModel update methods are invoked.  It also overrides UserModel.updateCredential for the
      * credential types it supports
      *
+     * @param realm
      * @param local
      * @return null if user is no longer valid or proxy object otherwise
      */
@@ -122,6 +123,7 @@ public interface UserFederationProvider extends Provider {
      * Is the Keycloak UserModel still valid and/or existing in federated storage?  Keycloak may call this method
      * in various user operations.  The local storage may be deleted if this method returns false.
      *
+     * @param realm
      * @param local
      * @return
      */
diff --git a/model/api/src/main/java/org/keycloak/models/UserFederationSpi.java b/model/api/src/main/java/org/keycloak/models/UserFederationSpi.java
index c17c02a..6b97751 100755
--- a/model/api/src/main/java/org/keycloak/models/UserFederationSpi.java
+++ b/model/api/src/main/java/org/keycloak/models/UserFederationSpi.java
@@ -10,7 +10,7 @@ import org.keycloak.provider.Spi;
 public class UserFederationSpi implements Spi {
 
     @Override
-    public boolean isPrivate() {
+    public boolean isInternal() {
         return false;
     }
 
diff --git a/model/api/src/main/java/org/keycloak/models/UserSessionSpi.java b/model/api/src/main/java/org/keycloak/models/UserSessionSpi.java
index 8755660..993eb9e 100644
--- a/model/api/src/main/java/org/keycloak/models/UserSessionSpi.java
+++ b/model/api/src/main/java/org/keycloak/models/UserSessionSpi.java
@@ -12,7 +12,7 @@ public class UserSessionSpi implements Spi {
     public static final String NAME = "userSessions";
 
     @Override
-    public boolean isPrivate() {
+    public boolean isInternal() {
         return true;
     }
 
diff --git a/model/api/src/main/java/org/keycloak/models/UserSpi.java b/model/api/src/main/java/org/keycloak/models/UserSpi.java
index 1d6cd74..af834e8 100755
--- a/model/api/src/main/java/org/keycloak/models/UserSpi.java
+++ b/model/api/src/main/java/org/keycloak/models/UserSpi.java
@@ -10,7 +10,7 @@ import org.keycloak.provider.Spi;
 public class UserSpi implements Spi {
 
     @Override
-    public boolean isPrivate() {
+    public boolean isInternal() {
         return true;
     }
 
diff --git a/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java b/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
index 67d5932..2adcb25 100755
--- a/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
+++ b/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
@@ -99,7 +99,6 @@ public class ModelToRepresentation {
             rep.setCodeSecret(realm.getCodeSecret());
         }
         rep.setCertificate(realm.getCertificatePem());
-        rep.setPasswordCredentialGrantAllowed(realm.isPasswordCredentialGrantAllowed());
         rep.setRegistrationAllowed(realm.isRegistrationAllowed());
         rep.setRegistrationEmailAsUsername(realm.isRegistrationEmailAsUsername());
         rep.setRememberMe(realm.isRememberMe());
@@ -124,6 +123,7 @@ public class ModelToRepresentation {
 
         rep.setVerifyEmail(realm.isVerifyEmail());
         rep.setResetPasswordAllowed(realm.isResetPasswordAllowed());
+        rep.setEditUsernameAllowed(realm.isEditUsernameAllowed());
         rep.setAccessTokenLifespan(realm.getAccessTokenLifespan());
         rep.setSsoSessionIdleTimeout(realm.getSsoSessionIdleTimeout());
         rep.setSsoSessionMaxLifespan(realm.getSsoSessionMaxLifespan());
@@ -324,7 +324,8 @@ public class ModelToRepresentation {
         providerRep.setAlias(identityProviderModel.getAlias());
         providerRep.setEnabled(identityProviderModel.isEnabled());
         providerRep.setStoreToken(identityProviderModel.isStoreToken());
-        providerRep.setUpdateProfileFirstLogin(identityProviderModel.isUpdateProfileFirstLogin());
+        providerRep.setUpdateProfileFirstLoginMode(identityProviderModel.getUpdateProfileFirstLoginMode());
+        providerRep.setTrustEmail(identityProviderModel.isTrustEmail());
         providerRep.setAuthenticateByDefault(identityProviderModel.isAuthenticateByDefault());
         providerRep.setConfig(identityProviderModel.getConfig());
         providerRep.setAddReadTokenRoleOnCreate(identityProviderModel.isAddReadTokenRoleOnCreate());
diff --git a/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java b/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
index 715b14a..c9611af 100755
--- a/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
+++ b/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
@@ -96,13 +96,13 @@ public class RepresentationToModel {
         else newRealm.setAccessCodeLifespanLogin(1800);
 
         if (rep.getSslRequired() != null) newRealm.setSslRequired(SslRequired.valueOf(rep.getSslRequired().toUpperCase()));
-        if (rep.isPasswordCredentialGrantAllowed() != null) newRealm.setPasswordCredentialGrantAllowed(rep.isPasswordCredentialGrantAllowed());
         if (rep.isRegistrationAllowed() != null) newRealm.setRegistrationAllowed(rep.isRegistrationAllowed());
         if (rep.isRegistrationEmailAsUsername() != null)
             newRealm.setRegistrationEmailAsUsername(rep.isRegistrationEmailAsUsername());
         if (rep.isRememberMe() != null) newRealm.setRememberMe(rep.isRememberMe());
         if (rep.isVerifyEmail() != null) newRealm.setVerifyEmail(rep.isVerifyEmail());
         if (rep.isResetPasswordAllowed() != null) newRealm.setResetPasswordAllowed(rep.isResetPasswordAllowed());
+        if (rep.isEditUsernameAllowed() != null) newRealm.setEditUsernameAllowed(rep.isEditUsernameAllowed());
         if (rep.getPrivateKey() == null || rep.getPublicKey() == null) {
             KeycloakModelUtils.generateRealmKeys(newRealm);
         } else {
@@ -420,12 +420,12 @@ public class RepresentationToModel {
         if (rep.getQuickLoginCheckMilliSeconds() != null) realm.setQuickLoginCheckMilliSeconds(rep.getQuickLoginCheckMilliSeconds());
         if (rep.getMaxDeltaTimeSeconds() != null) realm.setMaxDeltaTimeSeconds(rep.getMaxDeltaTimeSeconds());
         if (rep.getFailureFactor() != null) realm.setFailureFactor(rep.getFailureFactor());
-        if (rep.isPasswordCredentialGrantAllowed() != null) realm.setPasswordCredentialGrantAllowed(rep.isPasswordCredentialGrantAllowed());
         if (rep.isRegistrationAllowed() != null) realm.setRegistrationAllowed(rep.isRegistrationAllowed());
         if (rep.isRegistrationEmailAsUsername() != null) realm.setRegistrationEmailAsUsername(rep.isRegistrationEmailAsUsername());
         if (rep.isRememberMe() != null) realm.setRememberMe(rep.isRememberMe());
         if (rep.isVerifyEmail() != null) realm.setVerifyEmail(rep.isVerifyEmail());
         if (rep.isResetPasswordAllowed() != null) realm.setResetPasswordAllowed(rep.isResetPasswordAllowed());
+        if (rep.isEditUsernameAllowed() != null) realm.setEditUsernameAllowed(rep.isEditUsernameAllowed());
         if (rep.getSslRequired() != null) realm.setSslRequired(SslRequired.valueOf(rep.getSslRequired().toUpperCase()));
         if (rep.getAccessCodeLifespan() != null) realm.setAccessCodeLifespan(rep.getAccessCodeLifespan());
         if (rep.getAccessCodeLifespanUserAction() != null) realm.setAccessCodeLifespanUserAction(rep.getAccessCodeLifespanUserAction());
@@ -917,7 +917,8 @@ public class RepresentationToModel {
         identityProviderModel.setAlias(representation.getAlias());
         identityProviderModel.setProviderId(representation.getProviderId());
         identityProviderModel.setEnabled(representation.isEnabled());
-        identityProviderModel.setUpdateProfileFirstLogin(representation.isUpdateProfileFirstLogin());
+        identityProviderModel.setUpdateProfileFirstLoginMode(representation.getUpdateProfileFirstLoginMode());
+        identityProviderModel.setTrustEmail(representation.isTrustEmail());
         identityProviderModel.setAuthenticateByDefault(representation.isAuthenticateByDefault());
         identityProviderModel.setStoreToken(representation.isStoreToken());
         identityProviderModel.setAddReadTokenRoleOnCreate(representation.isAddReadTokenRoleOnCreate());
diff --git a/model/api/src/main/java/org/keycloak/provider/Spi.java b/model/api/src/main/java/org/keycloak/provider/Spi.java
index be68251..e88b66b 100644
--- a/model/api/src/main/java/org/keycloak/provider/Spi.java
+++ b/model/api/src/main/java/org/keycloak/provider/Spi.java
@@ -5,9 +5,9 @@ package org.keycloak.provider;
  */
 public interface Spi {
 
-    public boolean isPrivate();
-    public String getName();
-    public Class<? extends Provider> getProviderClass();
-    public Class<? extends ProviderFactory> getProviderFactoryClass();
+    boolean isInternal();
+    String getName();
+    Class<? extends Provider> getProviderClass();
+    Class<? extends ProviderFactory> getProviderFactoryClass();
 
 }
diff --git a/model/api/src/test/java/org/keycloak/models/MigrationVersionTest.java b/model/api/src/test/java/org/keycloak/models/MigrationVersionTest.java
index c706d8a..9bdd231 100755
--- a/model/api/src/test/java/org/keycloak/models/MigrationVersionTest.java
+++ b/model/api/src/test/java/org/keycloak/models/MigrationVersionTest.java
@@ -16,30 +16,30 @@ public class MigrationVersionTest {
         Assert.assertEquals(version_100Beta1.getMajor(), 1);
         Assert.assertEquals(version_100Beta1.getMinor(), 0);
         Assert.assertEquals(version_100Beta1.getMicro(), 0);
-        ModelVersion version_100RC1 = new ModelVersion("1.0.0.RC1");
+        ModelVersion version_100CR1 = new ModelVersion("1.0.0.CR1");
         ModelVersion version_100 = new ModelVersion("1.0.0");
         ModelVersion version_110Beta1 = new ModelVersion("1.1.0.Beta1");
-        ModelVersion version_110RC1 = new ModelVersion("1.1.0.RC1");
+        ModelVersion version_110CR1 = new ModelVersion("1.1.0.CR1");
         ModelVersion version_110 = new ModelVersion("1.1.0");
         ModelVersion version_111Beta1 = new ModelVersion("1.1.1.Beta1");
-        ModelVersion version_111RC1 = new ModelVersion("1.1.1.RC1");
+        ModelVersion version_111CR1 = new ModelVersion("1.1.1.CR1");
         ModelVersion version_111 = new ModelVersion("1.1.1");
         ModelVersion version_211Beta1 = new ModelVersion("2.1.1.Beta1");
-        ModelVersion version_211RC1 = new ModelVersion("2.1.1.RC1");
-        Assert.assertEquals(version_211RC1.getMajor(), 2);
-        Assert.assertEquals(version_211RC1.getMinor(), 1);
-        Assert.assertEquals(version_211RC1.getMicro(), 1);
-        Assert.assertEquals(version_211RC1.getQualifier(), "RC1");
+        ModelVersion version_211CR1 = new ModelVersion("2.1.1.CR1");
+        Assert.assertEquals(version_211CR1.getMajor(), 2);
+        Assert.assertEquals(version_211CR1.getMinor(), 1);
+        Assert.assertEquals(version_211CR1.getMicro(), 1);
+        Assert.assertEquals(version_211CR1.getQualifier(), "CR1");
         ModelVersion version_211 = new ModelVersion("2.1.1");
 
         Assert.assertFalse(version_100Beta1.lessThan(version_100Beta1));
-        Assert.assertTrue(version_100Beta1.lessThan(version_100RC1));
+        Assert.assertTrue(version_100Beta1.lessThan(version_100CR1));
         Assert.assertTrue(version_100Beta1.lessThan(version_100));
         Assert.assertTrue(version_100Beta1.lessThan(version_110Beta1));
-        Assert.assertTrue(version_100Beta1.lessThan(version_110RC1));
+        Assert.assertTrue(version_100Beta1.lessThan(version_110CR1));
         Assert.assertTrue(version_100Beta1.lessThan(version_110));
 
-        Assert.assertFalse(version_211.lessThan(version_110RC1));
+        Assert.assertFalse(version_211.lessThan(version_110CR1));
 
     }
 }
diff --git a/model/file/src/main/java/org/keycloak/models/file/adapter/RealmAdapter.java b/model/file/src/main/java/org/keycloak/models/file/adapter/RealmAdapter.java
index 26e09bb..1a19bad 100755
--- a/model/file/src/main/java/org/keycloak/models/file/adapter/RealmAdapter.java
+++ b/model/file/src/main/java/org/keycloak/models/file/adapter/RealmAdapter.java
@@ -30,6 +30,7 @@ import org.keycloak.models.PasswordPolicy;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.RequiredCredentialModel;
 import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserFederationMapperEventImpl;
 import org.keycloak.models.UserFederationMapperModel;
 import org.keycloak.models.UserFederationProviderCreationEventImpl;
 import org.keycloak.models.UserFederationProviderModel;
@@ -139,16 +140,6 @@ public class RealmAdapter implements RealmModel {
     }
 
     @Override
-    public boolean isPasswordCredentialGrantAllowed() {
-        return realm.isPasswordCredentialGrantAllowed();
-    }
-
-    @Override
-    public void setPasswordCredentialGrantAllowed(boolean passwordCredentialGrantAllowed) {
-        realm.setPasswordCredentialGrantAllowed(passwordCredentialGrantAllowed);
-    }
-
-    @Override
     public boolean isRegistrationAllowed() {
         return realm.isRegistrationAllowed();
     }
@@ -271,6 +262,16 @@ public class RealmAdapter implements RealmModel {
     }
 
     @Override
+    public boolean isEditUsernameAllowed() {
+        return realm.isEditUsernameAllowed();
+    }
+
+    @Override
+    public void setEditUsernameAllowed(boolean editUsernameAllowed) {
+        realm.setEditUsernameAllowed(editUsernameAllowed);
+    }
+
+    @Override
     public PasswordPolicy getPasswordPolicy() {
         if (passwordPolicy == null) {
             passwordPolicy = new PasswordPolicy(realm.getPasswordPolicy());
@@ -837,7 +838,9 @@ public class RealmAdapter implements RealmModel {
         realm.getUserFederationProviders().add(entity);
 
         UserFederationProviderModel providerModel = new UserFederationProviderModel(entity.getId(), providerName, config, priority, displayName, fullSyncPeriod, changedSyncPeriod, lastSync);
+
         session.getKeycloakSessionFactory().publish(new UserFederationProviderCreationEventImpl(this, providerModel));
+
         return providerModel;
     }
 
@@ -935,6 +938,7 @@ public class RealmAdapter implements RealmModel {
             entity.setChangedSyncPeriod(model.getChangedSyncPeriod());
             entity.setLastSync(model.getLastSync());
             entities.add(entity);
+
             session.getKeycloakSessionFactory().publish(new UserFederationProviderCreationEventImpl(this, model));
         }
 
@@ -1283,7 +1287,7 @@ public class RealmAdapter implements RealmModel {
         model.setPriority(entity.getPriority());
         model.setAuthenticator(entity.getAuthenticator());
         model.setParentFlow(entity.getParentFlow());
-        model.setAutheticatorFlow(entity.isAutheticatorFlow());
+        model.setAutheticatorFlow(entity.isAuthenticatorFlow());
         return model;
     }
 
@@ -1313,7 +1317,7 @@ public class RealmAdapter implements RealmModel {
         entity.setPriority(model.getPriority());
         entity.setRequirement(model.getRequirement());
         entity.setUserSetupAllowed(model.isUserSetupAllowed());
-        entity.setAutheticatorFlow(model.isAutheticatorFlow());
+        entity.setAuthenticatorFlow(model.isAutheticatorFlow());
         AuthenticationFlowEntity flow = getFlowEntity(model.getId());
         flow.getExecutions().add(entity);
         model.setId(entity.getId());
@@ -1331,7 +1335,7 @@ public class RealmAdapter implements RealmModel {
             }
         }
         if (entity == null) return;
-        entity.setAutheticatorFlow(model.isAutheticatorFlow());
+        entity.setAuthenticatorFlow(model.isAutheticatorFlow());
         entity.setAuthenticator(model.getAuthenticator());
         entity.setPriority(model.getPriority());
         entity.setRequirement(model.getRequirement());
@@ -1459,7 +1463,11 @@ public class RealmAdapter implements RealmModel {
         entity.setConfig(model.getConfig());
 
         this.realm.getUserFederationMappers().add(entity);
-        return entityToModel(entity);
+        UserFederationMapperModel mapperModel = entityToModel(entity);
+
+        session.getKeycloakSessionFactory().publish(new UserFederationMapperEventImpl(mapperModel, this, session));
+
+        return mapperModel;
     }
 
     protected UserFederationMapperEntity getUserFederationMapperEntity(String id) {
@@ -1511,6 +1519,8 @@ public class RealmAdapter implements RealmModel {
             entity.getConfig().clear();
             entity.getConfig().putAll(mapper.getConfig());
         }
+
+        session.getKeycloakSessionFactory().publish(new UserFederationMapperEventImpl(mapper, this, session));
     }
 
     @Override
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/CacheRealmProviderSpi.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/CacheRealmProviderSpi.java
index 300b8f0..bff04a9 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/CacheRealmProviderSpi.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/CacheRealmProviderSpi.java
@@ -11,7 +11,7 @@ import org.keycloak.provider.Spi;
 public class CacheRealmProviderSpi implements Spi {
 
     @Override
-    public boolean isPrivate() {
+    public boolean isInternal() {
         return true;
     }
 
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/CacheUserProviderSpi.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/CacheUserProviderSpi.java
index 9e0affa..989f062 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/CacheUserProviderSpi.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/CacheUserProviderSpi.java
@@ -11,7 +11,7 @@ import org.keycloak.provider.Spi;
 public class CacheUserProviderSpi implements Spi {
 
     @Override
-    public boolean isPrivate() {
+    public boolean isInternal() {
         return true;
     }
 
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java
index d93acf6..016870e 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java
@@ -39,9 +39,9 @@ public class CachedRealm {
     private boolean registrationEmailAsUsername;
     private boolean rememberMe;
     private boolean verifyEmail;
-    private boolean passwordCredentialGrantAllowed;
     private boolean resetPasswordAllowed;
     private boolean identityFederationEnabled;
+    private boolean editUsernameAllowed;
     //--- brute force settings
     private boolean bruteForceProtected;
     private int maxFailureWaitSeconds;
@@ -111,9 +111,9 @@ public class CachedRealm {
         registrationEmailAsUsername = model.isRegistrationEmailAsUsername();
         rememberMe = model.isRememberMe();
         verifyEmail = model.isVerifyEmail();
-        passwordCredentialGrantAllowed = model.isPasswordCredentialGrantAllowed();
         resetPasswordAllowed = model.isResetPasswordAllowed();
         identityFederationEnabled = model.isIdentityFederationEnabled();
+        editUsernameAllowed = model.isEditUsernameAllowed();
         //--- brute force settings
         bruteForceProtected = model.isBruteForceProtected();
         maxFailureWaitSeconds = model.getMaxFailureWaitSeconds();
@@ -244,10 +244,6 @@ public class CachedRealm {
         return registrationEmailAsUsername;
     }
 
-    public boolean isPasswordCredentialGrantAllowed() {
-        return passwordCredentialGrantAllowed;
-    }
-
     public boolean isRememberMe() {
         return this.rememberMe;
     }
@@ -288,6 +284,10 @@ public class CachedRealm {
         return resetPasswordAllowed;
     }
 
+    public boolean isEditUsernameAllowed() {
+        return editUsernameAllowed;
+    }
+
     public int getSsoSessionIdleTimeout() {
         return ssoSessionIdleTimeout;
     }
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java
index afb1c2c..75b8b82 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java
@@ -8,14 +8,12 @@ import org.keycloak.models.AuthenticatorModel;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.IdentityProviderMapperModel;
 import org.keycloak.models.IdentityProviderModel;
-import org.keycloak.models.LDAPConstants;
 import org.keycloak.models.PasswordPolicy;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.RequiredCredentialModel;
 import org.keycloak.models.RoleModel;
 import org.keycloak.models.UserFederationMapperModel;
 import org.keycloak.models.UserFederationProviderModel;
-import org.keycloak.models.UserModel;
 import org.keycloak.models.cache.entities.CachedRealm;
 import org.keycloak.models.utils.KeycloakModelUtils;
 
@@ -123,18 +121,6 @@ public class RealmAdapter implements RealmModel {
         getDelegateForUpdate();
         updated.setRegistrationEmailAsUsername(registrationEmailAsUsername);
     }
-    
-    @Override
-    public boolean isPasswordCredentialGrantAllowed() {
-        if (updated != null) return updated.isPasswordCredentialGrantAllowed();
-        return cached.isPasswordCredentialGrantAllowed();
-    }
-
-    @Override
-    public void setPasswordCredentialGrantAllowed(boolean passwordCredentialGrantAllowed) {
-        getDelegateForUpdate();
-        updated.setPasswordCredentialGrantAllowed(passwordCredentialGrantAllowed);
-    }
 
     @Override
     public boolean isRememberMe() {
@@ -257,6 +243,18 @@ public class RealmAdapter implements RealmModel {
     }
 
     @Override
+    public boolean isEditUsernameAllowed() {
+        if (updated != null) return updated.isEditUsernameAllowed();
+        return cached.isEditUsernameAllowed();
+    }
+
+    @Override
+    public void setEditUsernameAllowed(boolean editUsernameAllowed) {
+        getDelegateForUpdate();
+        updated.setEditUsernameAllowed(editUsernameAllowed);
+    }
+
+    @Override
     public int getSsoSessionIdleTimeout() {
         if (updated != null) return updated.getSsoSessionIdleTimeout();
         return cached.getSsoSessionIdleTimeout();
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/IdentityProviderEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/IdentityProviderEntity.java
index ba6de02..eeef707 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/IdentityProviderEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/IdentityProviderEntity.java
@@ -41,8 +41,11 @@ public class IdentityProviderEntity {
     @Column(name="ENABLED")
     private boolean enabled;
 
-    @Column(name="UPDATE_PROFILE_FIRST_LOGIN")
-    private boolean updateProfileFirstLogin;
+    @Column(name = "UPDATE_PROFILE_FIRST_LGN_MD")
+    private String updateProfileFirstLoginMode;
+
+    @Column(name = "TRUST_EMAIL")
+    private boolean trustEmail;
 
     @Column(name="STORE_TOKEN")
     private boolean storeToken;
@@ -99,12 +102,12 @@ public class IdentityProviderEntity {
         this.enabled = enabled;
     }
 
-    public boolean isUpdateProfileFirstLogin() {
-        return this.updateProfileFirstLogin;
+    public String getUpdateProfileFirstLoginMode() {
+        return updateProfileFirstLoginMode;
     }
 
-    public void setUpdateProfileFirstLogin(boolean updateProfileFirstLogin) {
-        this.updateProfileFirstLogin = updateProfileFirstLogin;
+    public void setUpdateProfileFirstLoginMode(String updateProfileFirstLoginMode) {
+        this.updateProfileFirstLoginMode = updateProfileFirstLoginMode;
     }
 
     public boolean isStoreToken() {
@@ -138,4 +141,12 @@ public class IdentityProviderEntity {
     public void setAddReadTokenRoleOnCreate(boolean addReadTokenRoleOnCreate) {
         this.addReadTokenRoleOnCreate = addReadTokenRoleOnCreate;
     }
+
+    public boolean isTrustEmail() {
+        return trustEmail;
+    }
+
+    public void setTrustEmail(boolean trustEmail) {
+        this.trustEmail = trustEmail;
+    }
 }
\ No newline at end of file
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java
index 089cd67..41be2b1 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java
@@ -49,8 +49,6 @@ public class RealmEntity {
     protected boolean registrationAllowed;
     @Column(name = "REG_EMAIL_AS_USERNAME")
     protected boolean registrationEmailAsUsername;
-    @Column(name="PASSWORD_CRED_GRANT_ALLOWED")
-    protected boolean passwordCredentialGrantAllowed;
     @Column(name="VERIFY_EMAIL")
     protected boolean verifyEmail;
     @Column(name="RESET_PASSWORD_ALLOWED")
@@ -59,6 +57,8 @@ public class RealmEntity {
     protected boolean rememberMe;
     @Column(name="PASSWORD_POLICY")
     protected String passwordPolicy;
+    @Column(name="EDIT_USERNAME_ALLOWED")
+    protected boolean editUsernameAllowed;
 
     @Column(name="SSO_IDLE_TIMEOUT")
     private int ssoSessionIdleTimeout;
@@ -206,14 +206,6 @@ public class RealmEntity {
         this.sslRequired = sslRequired;
     }
 
-    public boolean isPasswordCredentialGrantAllowed() {
-        return passwordCredentialGrantAllowed;
-    }
-
-    public void setPasswordCredentialGrantAllowed(boolean passwordCredentialGrantAllowed) {
-        this.passwordCredentialGrantAllowed = passwordCredentialGrantAllowed;
-    }
-
     public boolean isRegistrationAllowed() {
         return registrationAllowed;
     }
@@ -254,6 +246,14 @@ public class RealmEntity {
         this.resetPasswordAllowed = resetPasswordAllowed;
     }
 
+    public boolean isEditUsernameAllowed() {
+        return editUsernameAllowed;
+    }
+
+    public void setEditUsernameAllowed(boolean editUsernameAllowed) {
+        this.editUsernameAllowed = editUsernameAllowed;
+    }
+
     public int getSsoSessionIdleTimeout() {
         return ssoSessionIdleTimeout;
     }
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
index 6689a24..8cd0678 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
@@ -13,6 +13,7 @@ import org.keycloak.models.PasswordPolicy;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.RequiredCredentialModel;
 import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserFederationMapperEventImpl;
 import org.keycloak.models.UserFederationMapperModel;
 import org.keycloak.models.UserFederationProviderCreationEventImpl;
 import org.keycloak.models.UserFederationProviderModel;
@@ -112,17 +113,6 @@ public class RealmAdapter implements RealmModel {
     }
 
     @Override
-    public boolean isPasswordCredentialGrantAllowed() {
-        return realm.isPasswordCredentialGrantAllowed();
-    }
-
-    @Override
-    public void setPasswordCredentialGrantAllowed(boolean passwordCredentialGrantAllowed) {
-        realm.setPasswordCredentialGrantAllowed(passwordCredentialGrantAllowed);
-        em.flush();
-    }
-
-    @Override
     public boolean isRegistrationAllowed() {
         return realm.isRegistrationAllowed();
     }
@@ -321,6 +311,17 @@ public class RealmAdapter implements RealmModel {
     }
 
     @Override
+    public boolean isEditUsernameAllowed() {
+        return realm.isEditUsernameAllowed();
+    }
+
+    @Override
+    public void setEditUsernameAllowed(boolean editUsernameAllowed) {
+        realm.setEditUsernameAllowed(editUsernameAllowed);
+        em.flush();
+    }
+
+    @Override
     public int getNotBefore() {
         return realm.getNotBefore();
     }
@@ -789,7 +790,9 @@ public class RealmAdapter implements RealmModel {
         realm.getUserFederationProviders().add(entity);
         em.flush();
         UserFederationProviderModel providerModel = new UserFederationProviderModel(entity.getId(), providerName, config, priority, displayName, fullSyncPeriod, changedSyncPeriod, lastSync);
+
         session.getKeycloakSessionFactory().publish(new UserFederationProviderCreationEventImpl(this, providerModel));
+
         return providerModel;
     }
 
@@ -801,18 +804,23 @@ public class RealmAdapter implements RealmModel {
             if (entity.getId().equals(provider.getId())) {
 
                 session.users().preRemove(this, provider);
+                removeFederationMappersForProvider(provider.getId());
 
-                Set<UserFederationMapperEntity> mappers = getUserFederationMapperEntitiesByFederationProvider(provider.getId());
-                for (UserFederationMapperEntity mapper : mappers) {
-                    realm.getUserFederationMappers().remove(mapper);
-                    em.remove(mapper);
-                }
                 it.remove();
                 em.remove(entity);
                 return;
             }
         }
     }
+
+    private void removeFederationMappersForProvider(String federationProviderId) {
+        Set<UserFederationMapperEntity> mappers = getUserFederationMapperEntitiesByFederationProvider(federationProviderId);
+        for (UserFederationMapperEntity mapper : mappers) {
+            realm.getUserFederationMappers().remove(mapper);
+            em.remove(mapper);
+        }
+    }
+
     @Override
     public void updateUserFederationProvider(UserFederationProviderModel model) {
         KeycloakModelUtils.ensureUniqueDisplayName(model.getDisplayName(), model, getUserFederationProviders());
@@ -852,10 +860,9 @@ public class RealmAdapter implements RealmModel {
                     entity.setConfig(model.getConfig());
                     entity.setPriority(model.getPriority());
                     entity.setProviderName(model.getProviderName());
-                    entity.setPriority(model.getPriority());
                     String displayName = model.getDisplayName();
                     if (displayName != null) {
-                        entity.setDisplayName(model.getDisplayName());
+                        entity.setDisplayName(displayName);
                     }
                     entity.setFullSyncPeriod(model.getFullSyncPeriod());
                     entity.setChangedSyncPeriod(model.getChangedSyncPeriod());
@@ -868,6 +875,8 @@ public class RealmAdapter implements RealmModel {
             if (found) continue;
             session.users().preRemove(this, new UserFederationProviderModel(entity.getId(), entity.getProviderName(), entity.getConfig(), entity.getPriority(), entity.getDisplayName(),
                     entity.getFullSyncPeriod(), entity.getChangedSyncPeriod(), entity.getLastSync()));
+            removeFederationMappersForProvider(entity.getId());
+
             it.remove();
             em.remove(entity);
         }
@@ -907,6 +916,7 @@ public class RealmAdapter implements RealmModel {
             entity.setLastSync(model.getLastSync());
             em.persist(entity);
             realm.getUserFederationProviders().add(entity);
+
             session.getKeycloakSessionFactory().publish(new UserFederationProviderCreationEventImpl(this, model));
         }
     }
@@ -1153,7 +1163,8 @@ public class RealmAdapter implements RealmModel {
             identityProviderModel.setInternalId(entity.getInternalId());
             identityProviderModel.setConfig(entity.getConfig());
             identityProviderModel.setEnabled(entity.isEnabled());
-            identityProviderModel.setUpdateProfileFirstLogin(entity.isUpdateProfileFirstLogin());
+            identityProviderModel.setUpdateProfileFirstLoginMode(entity.getUpdateProfileFirstLoginMode());
+            identityProviderModel.setTrustEmail(entity.isTrustEmail());
             identityProviderModel.setAuthenticateByDefault(entity.isAuthenticateByDefault());
             identityProviderModel.setStoreToken(entity.isStoreToken());
             identityProviderModel.setAddReadTokenRoleOnCreate(entity.isAddReadTokenRoleOnCreate());
@@ -1185,7 +1196,8 @@ public class RealmAdapter implements RealmModel {
         entity.setEnabled(identityProvider.isEnabled());
         entity.setStoreToken(identityProvider.isStoreToken());
         entity.setAddReadTokenRoleOnCreate(identityProvider.isAddReadTokenRoleOnCreate());
-        entity.setUpdateProfileFirstLogin(identityProvider.isUpdateProfileFirstLogin());
+        entity.setUpdateProfileFirstLoginMode(identityProvider.getUpdateProfileFirstLoginMode());
+        entity.setTrustEmail(identityProvider.isTrustEmail());
         entity.setAuthenticateByDefault(identityProvider.isAuthenticateByDefault());
         entity.setConfig(identityProvider.getConfig());
 
@@ -1211,7 +1223,8 @@ public class RealmAdapter implements RealmModel {
             if (entity.getInternalId().equals(identityProvider.getInternalId())) {
                 entity.setAlias(identityProvider.getAlias());
                 entity.setEnabled(identityProvider.isEnabled());
-                entity.setUpdateProfileFirstLogin(identityProvider.isUpdateProfileFirstLogin());
+                entity.setUpdateProfileFirstLoginMode(identityProvider.getUpdateProfileFirstLoginMode());
+                entity.setTrustEmail(identityProvider.isTrustEmail());
                 entity.setAuthenticateByDefault(identityProvider.isAuthenticateByDefault());
                 entity.setAddReadTokenRoleOnCreate(identityProvider.isAddReadTokenRoleOnCreate());
                 entity.setStoreToken(identityProvider.isStoreToken());
@@ -1410,7 +1423,11 @@ public class RealmAdapter implements RealmModel {
 
         em.persist(entity);
         this.realm.getUserFederationMappers().add(entity);
-        return entityToModel(entity);
+        UserFederationMapperModel mapperModel = entityToModel(entity);
+
+        session.getKeycloakSessionFactory().publish(new UserFederationMapperEventImpl(mapperModel, this, session));
+
+        return mapperModel;
     }
 
     @Override
@@ -1464,6 +1481,8 @@ public class RealmAdapter implements RealmModel {
             entity.getConfig().putAll(mapper.getConfig());
         }
         em.flush();
+
+        session.getKeycloakSessionFactory().publish(new UserFederationMapperEventImpl(mapper, this, session));
     }
 
     @Override
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java
index 9b57238..2b8c397 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java
@@ -18,6 +18,7 @@ import org.keycloak.models.RealmModel;
 import org.keycloak.models.RealmProvider;
 import org.keycloak.models.RequiredCredentialModel;
 import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserFederationMapperEventImpl;
 import org.keycloak.models.UserFederationMapperModel;
 import org.keycloak.models.UserFederationProviderCreationEventImpl;
 import org.keycloak.models.UserFederationProviderModel;
@@ -112,17 +113,6 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
     }
 
     @Override
-    public boolean isPasswordCredentialGrantAllowed() {
-        return realm.isPasswordCredentialGrantAllowed();
-    }
-
-    @Override
-    public void setPasswordCredentialGrantAllowed(boolean passwordCredentialGrantAllowed) {
-        realm.setPasswordCredentialGrantAllowed(passwordCredentialGrantAllowed);
-        updateRealm();
-    }
-
-    @Override
     public boolean isRegistrationAllowed() {
         return realm.isRegistrationAllowed();
     }
@@ -255,6 +245,17 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
     }
 
     @Override
+    public boolean isEditUsernameAllowed() {
+        return realm.isEditUsernameAllowed();
+    }
+
+    @Override
+    public void setEditUsernameAllowed(boolean editUsernameAllowed) {
+        realm.setEditUsernameAllowed(editUsernameAllowed);
+        updateRealm();
+    }
+
+    @Override
     public PasswordPolicy getPasswordPolicy() {
         if (passwordPolicy == null) {
             passwordPolicy = new PasswordPolicy(realm.getPasswordPolicy());
@@ -771,7 +772,8 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
             identityProviderModel.setInternalId(entity.getInternalId());
             identityProviderModel.setConfig(entity.getConfig());
             identityProviderModel.setEnabled(entity.isEnabled());
-            identityProviderModel.setUpdateProfileFirstLogin(entity.isUpdateProfileFirstLogin());
+            identityProviderModel.setUpdateProfileFirstLoginMode(entity.getUpdateProfileFirstLoginMode());
+            identityProviderModel.setTrustEmail(entity.isTrustEmail());
             identityProviderModel.setAuthenticateByDefault(entity.isAuthenticateByDefault());
             identityProviderModel.setStoreToken(entity.isStoreToken());
             identityProviderModel.setAddReadTokenRoleOnCreate(entity.isAddReadTokenRoleOnCreate());
@@ -801,7 +803,8 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
         entity.setAlias(identityProvider.getAlias());
         entity.setProviderId(identityProvider.getProviderId());
         entity.setEnabled(identityProvider.isEnabled());
-        entity.setUpdateProfileFirstLogin(identityProvider.isUpdateProfileFirstLogin());
+        entity.setUpdateProfileFirstLoginMode(identityProvider.getUpdateProfileFirstLoginMode());
+        entity.setTrustEmail(identityProvider.isTrustEmail());
         entity.setAddReadTokenRoleOnCreate(identityProvider.isAddReadTokenRoleOnCreate());
         entity.setStoreToken(identityProvider.isStoreToken());
         entity.setAuthenticateByDefault(identityProvider.isAuthenticateByDefault());
@@ -813,7 +816,6 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
 
     @Override
     public void removeIdentityProviderByAlias(String alias) {
-        IdentityProviderEntity toRemove;
         for (IdentityProviderEntity entity : realm.getIdentityProviders()) {
             if (entity.getAlias().equals(alias)) {
                 realm.getIdentityProviders().remove(entity);
@@ -829,7 +831,8 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
             if (entity.getInternalId().equals(identityProvider.getInternalId())) {
                 entity.setAlias(identityProvider.getAlias());
                 entity.setEnabled(identityProvider.isEnabled());
-                entity.setUpdateProfileFirstLogin(identityProvider.isUpdateProfileFirstLogin());
+                entity.setUpdateProfileFirstLoginMode(identityProvider.getUpdateProfileFirstLoginMode());
+                entity.setTrustEmail(identityProvider.isTrustEmail());
                 entity.setAuthenticateByDefault(identityProvider.isAuthenticateByDefault());
                 entity.setAddReadTokenRoleOnCreate(identityProvider.isAddReadTokenRoleOnCreate());
                 entity.setStoreToken(identityProvider.isStoreToken());
@@ -860,7 +863,9 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
         updateRealm();
 
         UserFederationProviderModel providerModel = new UserFederationProviderModel(entity.getId(), providerName, config, priority, displayName, fullSyncPeriod, changedSyncPeriod, lastSync);
+
         session.getKeycloakSessionFactory().publish(new UserFederationProviderCreationEventImpl(this, providerModel));
+
         return providerModel;
     }
 
@@ -872,11 +877,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
             if (entity.getId().equals(provider.getId())) {
                 session.users().preRemove(this, new UserFederationProviderModel(entity.getId(), entity.getProviderName(), entity.getConfig(), entity.getPriority(), entity.getDisplayName(),
                         entity.getFullSyncPeriod(), entity.getChangedSyncPeriod(), entity.getLastSync()));
-
-                Set<UserFederationMapperEntity> mappers = getUserFederationMapperEntitiesByFederationProvider(provider.getId());
-                for (UserFederationMapperEntity mapper : mappers) {
-                    getMongoEntity().getUserFederationMappers().remove(mapper);
-                }
+                removeFederationMappersForProvider(provider.getId());
 
                 it.remove();
             }
@@ -884,6 +885,13 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
         updateRealm();
     }
 
+    private void removeFederationMappersForProvider(String federationProviderId) {
+        Set<UserFederationMapperEntity> mappers = getUserFederationMapperEntitiesByFederationProvider(federationProviderId);
+        for (UserFederationMapperEntity mapper : mappers) {
+            getMongoEntity().getUserFederationMappers().remove(mapper);
+        }
+    }
+
     @Override
     public void updateUserFederationProvider(UserFederationProviderModel model) {
         KeycloakModelUtils.ensureUniqueDisplayName(model.getDisplayName(), model, getUserFederationProviders());
@@ -938,8 +946,52 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
             KeycloakModelUtils.ensureUniqueDisplayName(currentProvider.getDisplayName(), currentProvider, providers);
         }
 
-        List<UserFederationProviderEntity> entities = new LinkedList<UserFederationProviderEntity>();
+        List<UserFederationProviderEntity> existingProviders = realm.getUserFederationProviders();
+        List<UserFederationProviderEntity> toRemove = new LinkedList<>();
+        for (UserFederationProviderEntity entity : existingProviders) {
+            boolean found = false;
+            for (UserFederationProviderModel model : providers) {
+                if (entity.getId().equals(model.getId())) {
+                    entity.setConfig(model.getConfig());
+                    entity.setPriority(model.getPriority());
+                    entity.setProviderName(model.getProviderName());
+                    String displayName = model.getDisplayName();
+                    if (displayName != null) {
+                        entity.setDisplayName(displayName);
+                    }
+                    entity.setFullSyncPeriod(model.getFullSyncPeriod());
+                    entity.setChangedSyncPeriod(model.getChangedSyncPeriod());
+                    entity.setLastSync(model.getLastSync());
+                    found = true;
+                    break;
+                }
+
+            }
+            if (found) continue;
+            session.users().preRemove(this, new UserFederationProviderModel(entity.getId(), entity.getProviderName(), entity.getConfig(), entity.getPriority(), entity.getDisplayName(),
+                    entity.getFullSyncPeriod(), entity.getChangedSyncPeriod(), entity.getLastSync()));
+            removeFederationMappersForProvider(entity.getId());
+
+            toRemove.add(entity);
+        }
+
+        for (UserFederationProviderEntity entity : toRemove) {
+            realm.getUserFederationProviders().remove(entity);
+        }
+
+        List<UserFederationProviderModel> add = new LinkedList<UserFederationProviderModel>();
         for (UserFederationProviderModel model : providers) {
+            boolean found = false;
+            for (UserFederationProviderEntity entity : realm.getUserFederationProviders()) {
+                if (entity.getId().equals(model.getId())) {
+                    found = true;
+                    break;
+                }
+            }
+            if (!found) add.add(model);
+        }
+
+        for (UserFederationProviderModel model : add) {
             UserFederationProviderEntity entity = new UserFederationProviderEntity();
             if (model.getId() != null) {
                 entity.setId(model.getId());
@@ -959,11 +1011,11 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
             entity.setFullSyncPeriod(model.getFullSyncPeriod());
             entity.setChangedSyncPeriod(model.getChangedSyncPeriod());
             entity.setLastSync(model.getLastSync());
-            entities.add(entity);
+            realm.getUserFederationProviders().add(entity);
+
             session.getKeycloakSessionFactory().publish(new UserFederationProviderCreationEventImpl(this, model));
         }
 
-        realm.setUserFederationProviders(entities);
         updateRealm();
     }
 
@@ -1230,7 +1282,6 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
     @Override
     public List<AuthenticationFlowModel> getAuthenticationFlows() {
         List<AuthenticationFlowEntity> flows = getMongoEntity().getAuthenticationFlows();
-        if (flows.size() == 0) return Collections.EMPTY_LIST;
         List<AuthenticationFlowModel> models = new LinkedList<>();
         for (AuthenticationFlowEntity entity : flows) {
             AuthenticationFlowModel model = entityToModel(entity);
@@ -1249,10 +1300,9 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
 
     @Override
     public AuthenticationFlowModel getAuthenticationFlowById(String id) {
-        for (AuthenticationFlowModel model : getAuthenticationFlows()) {
-            if (model.getId().equals(id)) return model;
-        }
-        return null;
+        AuthenticationFlowEntity entity = getFlowEntity(id);
+        if (entity == null) return null;
+        return entityToModel(entity);
     }
 
     protected AuthenticationFlowEntity getFlowEntity(String id) {
@@ -1274,7 +1324,6 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
 
     @Override
     public void updateAuthenticationFlow(AuthenticationFlowModel model) {
-        List<AuthenticationFlowEntity> flows = getMongoEntity().getAuthenticationFlows();
         AuthenticationFlowEntity toUpdate = getFlowEntity(model.getId());;
         if (toUpdate == null) return;
         toUpdate.setAlias(model.getAlias());
@@ -1316,7 +1365,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
         model.setPriority(entity.getPriority());
         model.setAuthenticator(entity.getAuthenticator());
         model.setParentFlow(entity.getParentFlow());
-        model.setAutheticatorFlow(entity.isAutheticatorFlow());
+        model.setAutheticatorFlow(entity.isAuthenticatorFlow());
         return model;
     }
 
@@ -1346,8 +1395,9 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
         entity.setPriority(model.getPriority());
         entity.setRequirement(model.getRequirement());
         entity.setUserSetupAllowed(model.isUserSetupAllowed());
-        entity.setAutheticatorFlow(model.isAutheticatorFlow());
-        AuthenticationFlowEntity flow = getFlowEntity(model.getId());
+        entity.setAuthenticatorFlow(model.isAutheticatorFlow());
+        entity.setParentFlow(model.getParentFlow());
+        AuthenticationFlowEntity flow = getFlowEntity(model.getParentFlow());
         flow.getExecutions().add(entity);
         updateMongoEntity();
         model.setId(entity.getId());
@@ -1365,7 +1415,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
             }
         }
         if (entity == null) return;
-        entity.setAutheticatorFlow(model.isAutheticatorFlow());
+        entity.setAuthenticatorFlow(model.isAutheticatorFlow());
         entity.setAuthenticator(model.getAuthenticator());
         entity.setPriority(model.getPriority());
         entity.setRequirement(model.getRequirement());
@@ -1499,7 +1549,11 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
 
         getMongoEntity().getUserFederationMappers().add(entity);
         updateMongoEntity();
-        return entityToModel(entity);
+        UserFederationMapperModel mapperModel = entityToModel(entity);
+
+        session.getKeycloakSessionFactory().publish(new UserFederationMapperEventImpl(mapperModel, this, session));
+
+        return mapperModel;
     }
 
     protected UserFederationMapperEntity getUserFederationMapperEntity(String id) {
@@ -1553,6 +1607,8 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
             entity.getConfig().putAll(mapper.getConfig());
         }
         updateMongoEntity();
+
+        session.getKeycloakSessionFactory().publish(new UserFederationMapperEventImpl(mapper, this, session));
     }
 
     @Override

pom.xml 8(+7 -1)

diff --git a/pom.xml b/pom.xml
index 9fb531b..a8dcdb7 100755
--- a/pom.xml
+++ b/pom.xml
@@ -84,7 +84,7 @@
         <jboss.as.plugin.version>7.5.Final</jboss.as.plugin.version>
         <wildfly.plugin.version>1.0.1.Final</wildfly.plugin.version>
         <minify.plugin.version>1.7.2</minify.plugin.version>
-        <embedmongo.plugin.version>0.1.10</embedmongo.plugin.version>
+        <embedmongo.plugin.version>0.1.12</embedmongo.plugin.version>
         <jmeter.plugin.version>1.9.0</jmeter.plugin.version>
         <jmeter.analysis.plugin.version>1.0.4</jmeter.analysis.plugin.version>
     </properties>
@@ -1108,6 +1108,12 @@
             </dependency>
             <dependency>
                 <groupId>org.keycloak</groupId>
+                <artifactId>keycloak-wf9-adapter-dist</artifactId>
+                <version>${project.version}</version>
+                <type>zip</type>
+            </dependency>
+            <dependency>
+                <groupId>org.keycloak</groupId>
                 <artifactId>keycloak-server-overlay</artifactId>
                 <version>${project.version}</version>
                 <type>zip</type>
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java
index bfa184b..09b033b 100755
--- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java
@@ -504,6 +504,7 @@ public class SamlService {
                                     @QueryParam(GeneralConstants.SAML_RESPONSE_KEY) String samlResponse,
                                     @QueryParam(GeneralConstants.RELAY_STATE) String relayState) {
         logger.debug("SAML GET");
+        //String uri = uriInfo.getRequestUri().toString();
         return new RedirectBindingProtocol().execute(samlRequest, samlResponse, relayState);
     }
 
diff --git a/services/src/main/java/org/keycloak/authentication/AuthenticatorSpi.java b/services/src/main/java/org/keycloak/authentication/AuthenticatorSpi.java
index 684d074..81b0373 100755
--- a/services/src/main/java/org/keycloak/authentication/AuthenticatorSpi.java
+++ b/services/src/main/java/org/keycloak/authentication/AuthenticatorSpi.java
@@ -11,7 +11,7 @@ import org.keycloak.provider.Spi;
 public class AuthenticatorSpi implements Spi {
 
     @Override
-    public boolean isPrivate() {
+    public boolean isInternal() {
         return false;
     }
 
diff --git a/services/src/main/java/org/keycloak/exportimport/ClientImportSpi.java b/services/src/main/java/org/keycloak/exportimport/ClientImportSpi.java
index e59a45a..47a777e 100755
--- a/services/src/main/java/org/keycloak/exportimport/ClientImportSpi.java
+++ b/services/src/main/java/org/keycloak/exportimport/ClientImportSpi.java
@@ -10,7 +10,7 @@ import org.keycloak.provider.Spi;
 public class ClientImportSpi implements Spi {
 
     @Override
-    public boolean isPrivate() {
+    public boolean isInternal() {
         return true;
     }
 
diff --git a/services/src/main/java/org/keycloak/messages/MessagesSpi.java b/services/src/main/java/org/keycloak/messages/MessagesSpi.java
index 6e82006..dd8b266 100644
--- a/services/src/main/java/org/keycloak/messages/MessagesSpi.java
+++ b/services/src/main/java/org/keycloak/messages/MessagesSpi.java
@@ -10,7 +10,7 @@ import org.keycloak.provider.Spi;
 public class MessagesSpi implements Spi {
 
     @Override
-    public boolean isPrivate() {
+    public boolean isInternal() {
         return true;
     }
 
diff --git a/services/src/main/java/org/keycloak/offlineconfig/AdminRecovery.java b/services/src/main/java/org/keycloak/offlineconfig/AdminRecovery.java
new file mode 100644
index 0000000..cb775b1
--- /dev/null
+++ b/services/src/main/java/org/keycloak/offlineconfig/AdminRecovery.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2015 Red Hat Inc. and/or its affiliates and other contributors
+ * as indicated by the @author tags. All rights reserved.
+ *
+ * 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.offlineconfig;
+
+import org.jboss.logging.Logger;
+import org.keycloak.Config;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RealmProvider;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.UserProvider;
+import org.keycloak.services.managers.ApplianceBootstrap;
+
+/**
+ * Static utility class that performs recovery on the master admin account.
+ *
+ * @author Stan Silvert ssilvert@redhat.com (C) 2015 Red Hat Inc.
+ */
+public class AdminRecovery {
+    private static final Logger log = Logger.getLogger(AdminRecovery.class);
+
+    public static final String RECOVER_ADMIN_ACCOUNT = "keycloak.recover-admin";
+    public static final String TEMP_ADMIN_PASSWORD = "keycloak.temp-admin-password";
+
+    // Don't allow instances
+    private AdminRecovery() {}
+
+    public static void recover(KeycloakSessionFactory sessionFactory) {
+        if (!needRecovery()) return;
+
+        KeycloakSession session = sessionFactory.create();
+
+        session.getTransaction().begin();
+        try {
+            doRecover(session, getTempAdminPassword());
+            session.getTransaction().commit();
+            log.info("*******************************");
+            log.info("Recovered Master Admin account.");
+            log.info("*******************************");
+        } finally {
+            session.close();
+            System.clearProperty(RECOVER_ADMIN_ACCOUNT);
+            System.clearProperty(TEMP_ADMIN_PASSWORD);
+        }
+    }
+
+    private static boolean needRecovery() {
+        String strNeedRecovery = System.getProperty(RECOVER_ADMIN_ACCOUNT, "false");
+        return Boolean.parseBoolean(strNeedRecovery);
+    }
+
+    private static String getTempAdminPassword() {
+        String tempAdminPassword = System.getProperty(TEMP_ADMIN_PASSWORD);
+        if ((tempAdminPassword == null) || tempAdminPassword.isEmpty()) {
+            throw new OfflineConfigException("Must provide temporary admin password to recover admin account.");
+        }
+        return tempAdminPassword;
+    }
+
+    private static void doRecover(KeycloakSession session, String tempAdminPassword) {
+        RealmProvider realmProvider = session.realms();
+        UserProvider userProvider = session.users();
+
+        String adminRealmName = Config.getAdminRealm();
+        RealmModel realm = realmProvider.getRealmByName(adminRealmName);
+        UserModel adminUser = userProvider.getUserByUsername("admin", realm);
+
+        if (adminUser == null) {
+            adminUser = userProvider.addUser(realm, "admin");
+        }
+
+        ApplianceBootstrap.setupAdminUser(session, realm, adminUser, tempAdminPassword);
+    }
+}
diff --git a/services/src/main/java/org/keycloak/protocol/LoginProtocolSpi.java b/services/src/main/java/org/keycloak/protocol/LoginProtocolSpi.java
index 6ac5496..2b594de 100755
--- a/services/src/main/java/org/keycloak/protocol/LoginProtocolSpi.java
+++ b/services/src/main/java/org/keycloak/protocol/LoginProtocolSpi.java
@@ -10,7 +10,7 @@ import org.keycloak.provider.Spi;
 public class LoginProtocolSpi implements Spi {
 
     @Override
-    public boolean isPrivate() {
+    public boolean isInternal() {
         return true;
     }
 
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java
index ffbc6a7..66d3995 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java
@@ -37,6 +37,7 @@ import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -150,7 +151,7 @@ public class TokenEndpoint {
             if (legacyGrantType != null) {
                 grantType = legacyGrantType;
             } else {
-                throw new ErrorResponseException("invalid_request", "Missing query parameter: " + OIDCLoginProtocol.GRANT_TYPE_PARAM, Response.Status.BAD_REQUEST);
+                throw new ErrorResponseException("invalid_request", "Missing form parameter: " + OIDCLoginProtocol.GRANT_TYPE_PARAM, Response.Status.BAD_REQUEST);
             }
         }
 
@@ -227,16 +228,7 @@ public class TokenEndpoint {
             throw new ErrorResponseException("invalid_grant", "Session not active", Response.Status.BAD_REQUEST);
         }
 
-        String adapterSessionId = formParams.getFirst(AdapterConstants.CLIENT_SESSION_STATE);
-        if (adapterSessionId != null) {
-            String adapterSessionHost = formParams.getFirst(AdapterConstants.CLIENT_SESSION_HOST);
-            logger.debugf("Adapter Session '%s' saved in ClientSession for client '%s'. Host is '%s'", adapterSessionId, client.getClientId(), adapterSessionHost);
-
-            event.detail(AdapterConstants.CLIENT_SESSION_STATE, adapterSessionId);
-            clientSession.setNote(AdapterConstants.CLIENT_SESSION_STATE, adapterSessionId);
-            event.detail(AdapterConstants.CLIENT_SESSION_HOST, adapterSessionHost);
-            clientSession.setNote(AdapterConstants.CLIENT_SESSION_HOST, adapterSessionHost);
-        }
+        updateClientSession(clientSession);
 
         AccessToken token = tokenManager.createClientAccessToken(session, accessCode.getRequestedRoles(), realm, client, user, userSession, clientSession);
 
@@ -259,6 +251,10 @@ public class TokenEndpoint {
         AccessTokenResponse res;
         try {
             res = tokenManager.refreshAccessToken(session, uriInfo, clientConnection, realm, client, refreshToken, event, headers);
+
+            UserSessionModel userSession = session.sessions().getUserSession(realm, res.getSessionState());
+            updateClientSessions(userSession.getClientSessions());
+
         } catch (OAuthErrorException e) {
             event.error(Errors.INVALID_TOKEN);
             throw new ErrorResponseException(e.getError(), e.getDescription(), Response.Status.BAD_REQUEST);
@@ -269,11 +265,46 @@ public class TokenEndpoint {
         return Cors.add(request, Response.ok(res, MediaType.APPLICATION_JSON_TYPE)).auth().allowedOrigins(client).allowedMethods("POST").exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS).build();
     }
 
-    public Response buildResourceOwnerPasswordCredentialsGrant() {
-        if (!realm.isPasswordCredentialGrantAllowed()) {
-            throw new ErrorResponseException("not_enabled", "Direct Grant REST API not enabled", Response.Status.FORBIDDEN);
+    private void updateClientSession(ClientSessionModel clientSession) {
+
+        if(clientSession == null) {
+            logger.error("client session is null");
+            return;
+        }
+
+        String adapterSessionId = formParams.getFirst(AdapterConstants.CLIENT_SESSION_STATE);
+        if (adapterSessionId != null) {
+            String adapterSessionHost = formParams.getFirst(AdapterConstants.CLIENT_SESSION_HOST);
+            logger.debugf("Adapter Session '%s' saved in ClientSession for client '%s'. Host is '%s'", adapterSessionId, client.getClientId(), adapterSessionHost);
+
+            event.detail(AdapterConstants.CLIENT_SESSION_STATE, adapterSessionId);
+            clientSession.setNote(AdapterConstants.CLIENT_SESSION_STATE, adapterSessionId);
+            event.detail(AdapterConstants.CLIENT_SESSION_HOST, adapterSessionHost);
+            clientSession.setNote(AdapterConstants.CLIENT_SESSION_HOST, adapterSessionHost);
         }
+    }
 
+    private void updateClientSessions(List<ClientSessionModel> clientSessions) {
+        if(clientSessions == null) {
+            logger.error("client sessions is null");
+            return;
+        }
+        for (ClientSessionModel clientSession : clientSessions) {
+            if(clientSession == null) {
+                logger.error("client session is null");
+                continue;
+            }
+            if(clientSession.getClient() == null) {
+                logger.error("client model in client session is null");
+                continue;
+            }
+            if(client.getId().equals(clientSession.getClient().getId())) {
+                updateClientSession(clientSession);
+            }
+        }
+    }
+
+    public Response buildResourceOwnerPasswordCredentialsGrant() {
         event.detail(Details.AUTH_METHOD, "oauth_credentials").detail(Details.RESPONSE_TYPE, "token");
 
         String username = formParams.getFirst(AuthenticationManager.FORM_USERNAME);
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProvider.java b/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProvider.java
index 80aee4a..afd2a8a 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProvider.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProvider.java
@@ -20,7 +20,7 @@ public class OIDCWellKnownProvider implements WellKnownProvider {
 
     public static final List<String> DEFAULT_ID_TOKEN_SIGNING_ALG_VALUES_SUPPORTED = list("RS256");
 
-    public static final List<String> DEFAULT_GRANT_TYPES_SUPPORTED = list(OAuth2Constants.AUTHORIZATION_CODE, OAuth2Constants.REFRESH_TOKEN);
+    public static final List<String> DEFAULT_GRANT_TYPES_SUPPORTED = list(OAuth2Constants.AUTHORIZATION_CODE, OAuth2Constants.REFRESH_TOKEN, OAuth2Constants.PASSWORD);
 
     public static final List<String> DEFAULT_RESPONSE_TYPES_SUPPORTED = list(OAuth2Constants.CODE);
 
@@ -53,14 +53,7 @@ public class OIDCWellKnownProvider implements WellKnownProvider {
         config.setResponseTypesSupported(DEFAULT_RESPONSE_TYPES_SUPPORTED);
         config.setSubjectTypesSupported(DEFAULT_SUBJECT_TYPES_SUPPORTED);
         config.setResponseModesSupported(DEFAULT_RESPONSE_MODES_SUPPORTED);
-
-        if (!realm.isPasswordCredentialGrantAllowed()) {
-            config.setGrantTypesSupported(DEFAULT_GRANT_TYPES_SUPPORTED);
-        } else {
-            List<String> grantTypes = new LinkedList<>(DEFAULT_GRANT_TYPES_SUPPORTED);
-            grantTypes.add(OAuth2Constants.PASSWORD);
-            config.setGrantTypesSupported(grantTypes);
-        }
+        config.setGrantTypesSupported(DEFAULT_GRANT_TYPES_SUPPORTED);
 
         return config;
     }
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/utils/AuthorizeClientUtil.java b/services/src/main/java/org/keycloak/protocol/oidc/utils/AuthorizeClientUtil.java
index a8a9e2a..0626f1c 100644
--- a/services/src/main/java/org/keycloak/protocol/oidc/utils/AuthorizeClientUtil.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/utils/AuthorizeClientUtil.java
@@ -39,7 +39,7 @@ public class AuthorizeClientUtil {
         if (client_id == null) {
             Map<String, String> error = new HashMap<String, String>();
             error.put(OAuth2Constants.ERROR, "invalid_client");
-            error.put(OAuth2Constants.ERROR_DESCRIPTION, "Could not find client");
+            error.put(OAuth2Constants.ERROR_DESCRIPTION, "Missing client_id parameter");
             throw new BadRequestException("Could not find client", Response.status(Response.Status.BAD_REQUEST).entity(error).type(MediaType.APPLICATION_JSON_TYPE).build());
         }
 
diff --git a/services/src/main/java/org/keycloak/protocol/ProtocolMapperSpi.java b/services/src/main/java/org/keycloak/protocol/ProtocolMapperSpi.java
index 1b98e07..f08e7dd 100755
--- a/services/src/main/java/org/keycloak/protocol/ProtocolMapperSpi.java
+++ b/services/src/main/java/org/keycloak/protocol/ProtocolMapperSpi.java
@@ -10,8 +10,8 @@ import org.keycloak.provider.Spi;
 public class ProtocolMapperSpi implements Spi {
 
     @Override
-    public boolean isPrivate() {
-        return false;
+    public boolean isInternal() {
+        return true;
     }
 
     @Override
diff --git a/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java b/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java
index 0bd9f31..b91858a 100755
--- a/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java
+++ b/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java
@@ -4,8 +4,6 @@ import org.jboss.logging.Logger;
 import org.keycloak.Config;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.KeycloakSessionFactory;
-import org.keycloak.models.RealmModel;
-import org.keycloak.models.RealmProvider;
 import org.keycloak.provider.Provider;
 import org.keycloak.provider.ProviderEvent;
 import org.keycloak.provider.ProviderEventListener;
@@ -66,7 +64,7 @@ public class DefaultKeycloakSessionFactory implements KeycloakSessionFactory {
                 Config.Scope scope = Config.scope(spi.getName(), provider);
                 factory.init(scope);
 
-                if (spi.isPrivate() && !isInternal(factory)) {
+                if (spi.isInternal() && !isInternal(factory)) {
                     log.warnv("{0} ({1}) is implementing the internal SPI {2}. This SPI is internal and may change without notice", factory.getId(), factory.getClass().getName(), spi.getName());
                 }
 
@@ -78,7 +76,7 @@ public class DefaultKeycloakSessionFactory implements KeycloakSessionFactory {
                     Config.Scope scope = Config.scope(spi.getName(), factory.getId());
                     factory.init(scope);
 
-                    if (spi.isPrivate() && !isInternal(factory)) {
+                    if (spi.isInternal() && !isInternal(factory)) {
                         log.warnv("{0} ({1}) is implementing the internal SPI {2}. This SPI is internal and may change without notice", factory.getId(), factory.getClass().getName(), spi.getName());
                     }
 
diff --git a/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java b/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java
index 8760ff0..7510572 100755
--- a/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java
+++ b/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java
@@ -61,11 +61,15 @@ public class ApplianceBootstrap {
         KeycloakModelUtils.generateRealmKeys(realm);
 
         UserModel adminUser = session.users().addUser(realm, "admin");
+        setupAdminUser(session, realm, adminUser, "admin");
+    }
+
+    public static void setupAdminUser(KeycloakSession session, RealmModel realm, UserModel adminUser, String password) {
         adminUser.setEnabled(true);
-        UserCredentialModel password = new UserCredentialModel();
-        password.setType(UserCredentialModel.PASSWORD);
-        password.setValue("admin");
-        session.users().updateCredential(realm, adminUser, password);
+        UserCredentialModel usrCredModel = new UserCredentialModel();
+        usrCredModel.setType(UserCredentialModel.PASSWORD);
+        usrCredModel.setValue(password);
+        session.users().updateCredential(realm, adminUser, usrCredModel);
         adminUser.addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD);
 
         RoleModel adminRole = realm.getRole(AdminRoles.ADMIN);
diff --git a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
index 3ada879..f200130 100755
--- a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
@@ -443,7 +443,7 @@ public class AuthenticationManager {
             Iterator<String> i = user.getRequiredActions().iterator();
             String action = i.next();
             
-            if (action.equals(UserModel.RequiredAction.VERIFY_EMAIL.name()) && Validation.isEmpty(user.getEmail())) {
+            if (action.equals(UserModel.RequiredAction.VERIFY_EMAIL.name()) && Validation.isBlank(user.getEmail())) {
                 if (i.hasNext())
                     action = i.next();
                 else
@@ -465,7 +465,6 @@ public class AuthenticationManager {
         }
 
         if (client.isConsentRequired()) {
-            accessCode.setAction(ClientSessionModel.Action.OAUTH_GRANT);
 
             UserConsentModel grantedConsent = user.getConsentByClient(client.getId());
 
@@ -496,11 +495,18 @@ public class AuthenticationManager {
 
             // Skip grant screen if everything was already approved by this user
             if (realmRoles.size() > 0 || resourceRoles.size() > 0 || protocolMappers.size() > 0) {
+                accessCode.setAction(ClientSessionModel.Action.OAUTH_GRANT);
+
                 return session.getProvider(LoginFormsProvider.class)
                         .setClientSessionCode(accessCode.getCode())
                         .setAccessRequest(realmRoles, resourceRoles, protocolMappers)
                         .createOAuthGrant(clientSession);
+            } else {
+                String consentDetail = (grantedConsent != null) ? Details.CONSENT_VALUE_PERSISTED_CONSENT : Details.CONSENT_VALUE_NO_CONSENT_REQUIRED;
+                event.detail(Details.CONSENT, consentDetail);
             }
+        } else {
+            event.detail(Details.CONSENT, Details.CONSENT_VALUE_NO_CONSENT_REQUIRED);
         }
 
         event.success();
diff --git a/services/src/main/java/org/keycloak/services/resources/AccountService.java b/services/src/main/java/org/keycloak/services/resources/AccountService.java
index 026c877..697a28f 100755
--- a/services/src/main/java/org/keycloak/services/resources/AccountService.java
+++ b/services/src/main/java/org/keycloak/services/resources/AccountService.java
@@ -35,23 +35,35 @@ import org.keycloak.events.EventBuilder;
 import org.keycloak.events.EventStoreProvider;
 import org.keycloak.events.EventType;
 import org.keycloak.login.LoginFormsProvider;
-import org.keycloak.models.*;
+import org.keycloak.models.AccountRoles;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.ClientSessionModel;
+import org.keycloak.models.Constants;
+import org.keycloak.models.FederatedIdentityModel;
+import org.keycloak.models.IdentityProviderModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.ModelException;
+import org.keycloak.models.ModelReadOnlyException;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserCredentialValueModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.UserSessionModel;
 import org.keycloak.models.utils.FormMessage;
 import org.keycloak.models.utils.ModelToRepresentation;
 import org.keycloak.models.utils.TimeBasedOTP;
 import org.keycloak.protocol.oidc.OIDCLoginProtocol;
 import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
-import org.keycloak.protocol.oidc.TokenManager;
 import org.keycloak.protocol.oidc.utils.RedirectUtils;
 import org.keycloak.representations.idm.CredentialRepresentation;
 import org.keycloak.representations.idm.UserRepresentation;
 import org.keycloak.services.ForbiddenException;
+import org.keycloak.services.Urls;
 import org.keycloak.services.managers.AppAuthManager;
 import org.keycloak.services.managers.Auth;
 import org.keycloak.services.managers.AuthenticationManager;
 import org.keycloak.services.managers.ClientSessionCode;
 import org.keycloak.services.messages.Messages;
-import org.keycloak.services.Urls;
 import org.keycloak.services.util.CookieHelper;
 import org.keycloak.services.util.ResolveRelative;
 import org.keycloak.services.validation.Validation;
@@ -73,7 +85,6 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriBuilder;
 import javax.ws.rs.core.UriInfo;
 import javax.ws.rs.core.Variant;
-
 import java.lang.reflect.Method;
 import java.net.URI;
 import java.util.HashSet;
@@ -414,13 +425,16 @@ public class AccountService {
 
         UserModel user = auth.getUser();
 
-        List<FormMessage> errors = Validation.validateUpdateProfileForm(formData);
+        List<FormMessage> errors = Validation.validateUpdateProfileForm(realm, formData);
         if (errors != null && !errors.isEmpty()) {
             setReferrerOnPage();
             return account.setErrors(errors).setProfileFormData(formData).createResponse(AccountPages.ACCOUNT);
         }
 
         try {
+            if (realm.isEditUsernameAllowed()) {
+                user.setUsername(formData.getFirst("username"));
+            }
             user.setFirstName(formData.getFirst("firstName"));
             user.setLastName(formData.getFirst("lastName"));
 
@@ -566,7 +580,7 @@ public class AccountService {
         String totp = formData.getFirst("totp");
         String totpSecret = formData.getFirst("totpSecret");
 
-        if (Validation.isEmpty(totp)) {
+        if (Validation.isBlank(totp)) {
             setReferrerOnPage();
             return account.setError(Messages.MISSING_TOTP).createResponse(AccountPages.TOTP);
         } else if (!new TimeBasedOTP().validate(totp, totpSecret.getBytes())) {
@@ -626,7 +640,7 @@ public class AccountService {
         String passwordConfirm = formData.getFirst("password-confirm");
 
         if (requireCurrent) {
-            if (Validation.isEmpty(password)) {
+            if (Validation.isBlank(password)) {
                 setReferrerOnPage();
                 return account.setError(Messages.MISSING_PASSWORD).createResponse(AccountPages.PASSWORD);
             }
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
index b27ce49..c94fa6e 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
@@ -193,8 +193,9 @@ public class RealmAdminResource {
         } catch (PatternSyntaxException e) {
             return ErrorResponse.error("Specified regex pattern(s) is invalid.", Response.Status.BAD_REQUEST);
         } catch (ModelDuplicateException e) {
-            return ErrorResponse.exists("Realm " + rep.getRealm() + " already exists.");
-        }  catch (Exception e) {
+            throw e;
+        } catch (Exception e) {
+            logger.error(e);
             return ErrorResponse.error("Failed to update " + rep.getRealm() + " Realm.", Response.Status.INTERNAL_SERVER_ERROR);
         }
     }
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoAdminResource.java
index 4e0d8f9..4f1c225 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoAdminResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoAdminResource.java
@@ -69,9 +69,13 @@ public class ServerInfoAdminResource {
     }
 
     private void setProviders(ServerInfoRepresentation info) {
-        Map<String, Set<String>> providers = new HashMap<String, Set<String>>();
+        List<SpiInfoRepresentation> providers = new LinkedList<>();
         for (Spi spi : ServiceLoader.load(Spi.class)) {
-            providers.put(spi.getName(), session.listProviderIds(spi.getProviderClass()));
+            SpiInfoRepresentation spiRep = new SpiInfoRepresentation();
+            spiRep.setName(spi.getName());
+            spiRep.setInternal(spi.isInternal());
+            spiRep.setImplementations(session.listProviderIds(spi.getProviderClass()));
+            providers.add(spiRep);
         }
         info.providers = providers;
     }
@@ -197,7 +201,7 @@ public class ServerInfoAdminResource {
         private List<String> protocols;
         private List<Map<String, String>> clientImporters;
 
-        private Map<String, Set<String>> providers;
+        private List<SpiInfoRepresentation> providers;
 
         private List<String> eventListeners;
         private Map<String, List<ProtocolMapperTypeRepresentation>> protocolMapperTypes;
@@ -240,7 +244,7 @@ public class ServerInfoAdminResource {
             return clientImporters;
         }
 
-        public Map<String, Set<String>> getProviders() {
+        public List<SpiInfoRepresentation> getProviders() {
             return providers;
         }
 
@@ -265,6 +269,36 @@ public class ServerInfoAdminResource {
         }
     }
 
+    public static class SpiInfoRepresentation {
+        private String name;
+        private boolean internal;
+        private Set<String> implementations;
+
+        public String getName() {
+            return name;
+        }
+
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        public boolean isInternal() {
+            return internal;
+        }
+
+        public void setInternal(boolean internal) {
+            this.internal = internal;
+        }
+
+        public Set<String> getImplementations() {
+            return implementations;
+        }
+
+        public void setImplementations(Set<String> implementations) {
+            this.implementations = implementations;
+        }
+    }
+
     private static Map<String, List<String>> createEnumsMap(Class... enums) {
         Map<String, List<String>> m = new HashMap<>();
         for (Class e : enums) {
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 d6dc0d3..55d97b0 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
@@ -186,6 +186,9 @@ public class UsersResource {
     }
 
     private void updateUserFromRep(UserModel user, UserRepresentation rep, Set<String> attrsToRemove) {
+        if (realm.isEditUsernameAllowed()) {
+            user.setUsername(rep.getUsername());
+        }
         user.setEmail(rep.getEmail());
         user.setFirstName(rep.getFirstName());
         user.setLastName(rep.getLastName());
diff --git a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
index e6660ee..e1d6bfa 100755
--- a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
+++ b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
@@ -44,10 +44,10 @@ import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.UserSessionModel;
-import org.keycloak.models.utils.KeycloakModelUtils;
 import org.keycloak.protocol.oidc.TokenManager;
 import org.keycloak.provider.ProviderFactory;
 import org.keycloak.representations.AccessToken;
+import org.keycloak.representations.idm.IdentityProviderRepresentation;
 import org.keycloak.services.managers.AppAuthManager;
 import org.keycloak.services.managers.AuthenticationManager;
 import org.keycloak.services.managers.AuthenticationManager.AuthResult;
@@ -71,6 +71,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.Status;
 import javax.ws.rs.core.UriBuilder;
 import javax.ws.rs.core.UriInfo;
+
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -278,12 +279,16 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
             try {
                 federatedUser = createUser(context);
 
-                if (identityProviderConfig.isUpdateProfileFirstLogin()) {
+                if (IdentityProviderRepresentation.UPFLM_ON.equals(identityProviderConfig.getUpdateProfileFirstLoginMode()) 
+                        || (IdentityProviderRepresentation.UPFLM_MISSING.equals(identityProviderConfig.getUpdateProfileFirstLoginMode()) && !Validation.validateUserMandatoryFields(realmModel, federatedUser))) {
                     if (isDebugEnabled()) {
                         LOGGER.debugf("Identity provider requires update profile action.", federatedUser);
                     }
                     federatedUser.addRequiredAction(UPDATE_PROFILE);
                 }
+                if(identityProviderConfig.isTrustEmail() && !Validation.isBlank(federatedUser.getEmail())){
+                    federatedUser.setEmailVerified(true);
+                }
             } catch (Exception e) {
                 return redirectToLoginPage(e, clientCode);
             }
@@ -506,7 +511,7 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
         String username = context.getModelUsername();
         if (username == null) {
             username = context.getUsername();
-            if (this.realmModel.isRegistrationEmailAsUsername() && !Validation.isEmpty(context.getEmail())) {
+            if (this.realmModel.isRegistrationEmailAsUsername() && !Validation.isBlank(context.getEmail())) {
                 username = context.getEmail();
             } else if (username == null) {
                 username = context.getIdpConfig().getAlias() + "." + context.getId();
diff --git a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
index e4c821c..0e32fe8 100755
--- a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
+++ b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
@@ -42,6 +42,7 @@ import java.util.HashSet;
 import java.util.Properties;
 import java.util.Set;
 import java.util.StringTokenizer;
+import org.keycloak.offlineconfig.AdminRecovery;
 
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -88,6 +89,7 @@ public class KeycloakApplication extends Application {
         importRealms(context);
         migrateModel();
 
+        AdminRecovery.recover(sessionFactory);
 
         setupScheduledTasks(sessionFactory);
     }
diff --git a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java
index 3af66d3..08a05c9 100755
--- a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java
+++ b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java
@@ -316,7 +316,7 @@ public class LoginActionsService {
             return ErrorPage.error(session, Messages.UNKNOWN_LOGIN_REQUESTER);
         }
         if (!client.isEnabled()) {
-            event.error(Errors.CLIENT_NOT_FOUND);
+            event.error(Errors.CLIENT_DISABLED);
             return ErrorPage.error(session, Messages.LOGIN_REQUESTER_NOT_ENABLED);
         }
 
@@ -443,7 +443,7 @@ public class LoginActionsService {
             return ErrorPage.error(session, Messages.UNKNOWN_LOGIN_REQUESTER);
         }
         if (!client.isEnabled()) {
-            event.error(Errors.CLIENT_NOT_FOUND);
+            event.error(Errors.CLIENT_DISABLED);
             return ErrorPage.error(session, Messages.LOGIN_REQUESTER_NOT_ENABLED);
         }
 
@@ -741,6 +741,7 @@ public class LoginActionsService {
         }
         user.updateConsent(grantedConsent);
 
+        event.detail(Details.CONSENT, Details.CONSENT_VALUE_CONSENT_GRANTED);
         event.success();
 
         return authManager.redirectAfterSuccessfulFlow(session, realm, userSession, clientSession, request, uriInfo, clientConnection);
@@ -829,7 +830,7 @@ public class LoginActionsService {
         String totpSecret = formData.getFirst("totpSecret");
 
         LoginFormsProvider loginForms = session.getProvider(LoginFormsProvider.class).setUser(user);
-        if (Validation.isEmpty(totp)) {
+        if (Validation.isBlank(totp)) {
             return loginForms.setError(Messages.MISSING_TOTP)
                     .setClientSessionCode(accessCode.getCode())
                     .createResponse(RequiredAction.CONFIGURE_TOTP);
@@ -875,7 +876,7 @@ public class LoginActionsService {
 
         LoginFormsProvider loginForms = session.getProvider(LoginFormsProvider.class)
                 .setUser(user);
-        if (Validation.isEmpty(passwordNew)) {
+        if (Validation.isBlank(passwordNew)) {
             return loginForms.setError(Messages.MISSING_PASSWORD)
                     .setClientSessionCode(accessCode.getCode())
                     .createResponse(RequiredAction.UPDATE_PASSWORD);
diff --git a/services/src/main/java/org/keycloak/services/validation/Validation.java b/services/src/main/java/org/keycloak/services/validation/Validation.java
index 1a4392b..d3abc4d 100755
--- a/services/src/main/java/org/keycloak/services/validation/Validation.java
+++ b/services/src/main/java/org/keycloak/services/validation/Validation.java
@@ -1,17 +1,18 @@
 package org.keycloak.services.validation;
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.regex.Pattern;
-
-import javax.ws.rs.core.MultivaluedMap;
-
 import org.keycloak.models.PasswordPolicy;
 import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
 import org.keycloak.models.utils.FormMessage;
 import org.keycloak.representations.idm.CredentialRepresentation;
 import org.keycloak.services.messages.Messages;
 
+import javax.ws.rs.core.MultivaluedMap;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+
 public class Validation {
 
     public static final String FIELD_PASSWORD_CONFIRM = "password-confirm";
@@ -27,26 +28,26 @@ public class Validation {
     public static List<FormMessage> validateRegistrationForm(RealmModel realm, MultivaluedMap<String, String> formData, List<String> requiredCredentialTypes, PasswordPolicy policy) {
         List<FormMessage> errors = new ArrayList<>();
 
-        if (!realm.isRegistrationEmailAsUsername() && isEmpty(formData.getFirst(FIELD_USERNAME))) {
+        if (!realm.isRegistrationEmailAsUsername() && isBlank(formData.getFirst(FIELD_USERNAME))) {
             addError(errors, FIELD_USERNAME, Messages.MISSING_USERNAME);
         }
 
-        if (isEmpty(formData.getFirst(FIELD_FIRST_NAME))) {
+        if (isBlank(formData.getFirst(FIELD_FIRST_NAME))) {
             addError(errors, FIELD_FIRST_NAME, Messages.MISSING_FIRST_NAME);
         }
 
-        if (isEmpty(formData.getFirst(FIELD_LAST_NAME))) {
+        if (isBlank(formData.getFirst(FIELD_LAST_NAME))) {
             addError(errors, FIELD_LAST_NAME, Messages.MISSING_LAST_NAME);
         }
 
-        if (isEmpty(formData.getFirst(FIELD_EMAIL))) {
+        if (isBlank(formData.getFirst(FIELD_EMAIL))) {
             addError(errors, FIELD_EMAIL, Messages.MISSING_EMAIL);
         } else if (!isEmailValid(formData.getFirst(FIELD_EMAIL))) {
             addError(errors, FIELD_EMAIL, Messages.INVALID_EMAIL);
         }
 
         if (requiredCredentialTypes.contains(CredentialRepresentation.PASSWORD)) {
-            if (isEmpty(formData.getFirst(FIELD_PASSWORD))) {
+            if (isBlank(formData.getFirst(FIELD_PASSWORD))) {
                 addError(errors, FIELD_PASSWORD, Messages.MISSING_PASSWORD);
             } else if (!formData.getFirst(FIELD_PASSWORD).equals(formData.getFirst(FIELD_PASSWORD_CONFIRM))) {
                 addError(errors, FIELD_PASSWORD_CONFIRM, Messages.INVALID_PASSWORD_CONFIRM);
@@ -66,19 +67,26 @@ public class Validation {
         errors.add(new FormMessage(field, message));
     }
 
-
     public static List<FormMessage> validateUpdateProfileForm(MultivaluedMap<String, String> formData) {
+        return validateUpdateProfileForm(null, formData);
+    }
+
+    public static List<FormMessage> validateUpdateProfileForm(RealmModel realm, MultivaluedMap<String, String> formData) {
         List<FormMessage> errors = new ArrayList<>();
         
-        if (isEmpty(formData.getFirst(FIELD_FIRST_NAME))) {
+        if (realm != null && realm.isEditUsernameAllowed() && isBlank(formData.getFirst(FIELD_USERNAME))) {
+            addError(errors, FIELD_USERNAME, Messages.MISSING_USERNAME);
+        }
+
+        if (isBlank(formData.getFirst(FIELD_FIRST_NAME))) {
             addError(errors, FIELD_FIRST_NAME, Messages.MISSING_FIRST_NAME);
         }
 
-        if (isEmpty(formData.getFirst(FIELD_LAST_NAME))) {
+        if (isBlank(formData.getFirst(FIELD_LAST_NAME))) {
             addError(errors, FIELD_LAST_NAME, Messages.MISSING_LAST_NAME);
         }
 
-        if (isEmpty(formData.getFirst(FIELD_EMAIL))) {
+        if (isBlank(formData.getFirst(FIELD_EMAIL))) {
             addError(errors, FIELD_EMAIL, Messages.MISSING_EMAIL);
         } else if (!isEmailValid(formData.getFirst(FIELD_EMAIL))) {
             addError(errors, FIELD_EMAIL, Messages.INVALID_EMAIL);
@@ -86,10 +94,37 @@ public class Validation {
 
         return errors;
     }
+    
+    /**
+     * Validate if user object contains all mandatory fields.
+     * 
+     * @param realm user is for
+     * @param user to validate
+     * @return true if user object contains all mandatory values, false if some mandatory value is missing
+     */
+    public static boolean validateUserMandatoryFields(RealmModel realm, UserModel user){
+        return!(isBlank(user.getFirstName()) || isBlank(user.getLastName()) || isBlank(user.getEmail()));        
+    }
 
+    /**
+     * Check if string is empty (null or lenght is 0)
+     * 
+     * @param s to check
+     * @return true if string is empty
+     */
     public static boolean isEmpty(String s) {
         return s == null || s.length() == 0;
     }
+    
+    /**
+     * Check if string is blank (null or lenght is 0 or contains only white characters)
+     * 
+     * @param s to check
+     * @return true if string is blank
+     */
+    public static boolean isBlank(String s) {
+        return s == null || s.trim().length() == 0;
+    }
 
     public static boolean isEmailValid(String email) {
         return EMAIL_PATTERN.matcher(email).matches();
diff --git a/services/src/main/java/org/keycloak/wellknown/WellKnownSpi.java b/services/src/main/java/org/keycloak/wellknown/WellKnownSpi.java
index 7734f48..564c600 100755
--- a/services/src/main/java/org/keycloak/wellknown/WellKnownSpi.java
+++ b/services/src/main/java/org/keycloak/wellknown/WellKnownSpi.java
@@ -10,7 +10,7 @@ import org.keycloak.provider.Spi;
 public class WellKnownSpi implements Spi {
 
     @Override
-    public boolean isPrivate() {
+    public boolean isInternal() {
         return true;
     }
 
diff --git a/services/src/test/java/org/keycloak/test/ValidationTest.java b/services/src/test/java/org/keycloak/test/ValidationTest.java
index 0da7dfa..72f5926 100644
--- a/services/src/test/java/org/keycloak/test/ValidationTest.java
+++ b/services/src/test/java/org/keycloak/test/ValidationTest.java
@@ -24,4 +24,26 @@ public class ValidationTest {
         Assert.assertFalse(Validation.isEmailValid("abc@foo."));
         Assert.assertFalse(Validation.isEmailValid("abc@foo..bar"));
     }
+    
+    @Test
+    public void testIsEmpty(){
+        Assert.assertTrue(Validation.isEmpty(null));
+        Assert.assertTrue(Validation.isEmpty(""));
+        Assert.assertFalse(Validation.isEmpty(" "));
+        Assert.assertFalse(Validation.isEmpty("     "));
+        Assert.assertFalse(Validation.isEmpty("a"));
+        Assert.assertFalse(Validation.isEmpty("    a "));
+        Assert.assertFalse(Validation.isEmpty("asgadfgedfs"));
+    }
+    
+    @Test
+    public void testIsBlank(){
+        Assert.assertTrue(Validation.isBlank(null));
+        Assert.assertTrue(Validation.isBlank(""));
+        Assert.assertTrue(Validation.isBlank(" "));
+        Assert.assertTrue(Validation.isBlank("  \n   "));
+        Assert.assertFalse(Validation.isBlank("a"));
+        Assert.assertFalse(Validation.isBlank("    a "));
+        Assert.assertFalse(Validation.isBlank("asgadfgedfs"));
+    }
 }
diff --git a/social/core/src/main/java/org/keycloak/social/SocialProviderSpi.java b/social/core/src/main/java/org/keycloak/social/SocialProviderSpi.java
index fd500a8..382c18d 100644
--- a/social/core/src/main/java/org/keycloak/social/SocialProviderSpi.java
+++ b/social/core/src/main/java/org/keycloak/social/SocialProviderSpi.java
@@ -29,7 +29,7 @@ public class SocialProviderSpi implements Spi {
     public static final String SOCIAL_SPI_NAME = "social";
 
     @Override
-    public boolean isPrivate() {
+    public boolean isInternal() {
         return false;
     }
 
diff --git a/social/linkedin/src/main/java/org/keycloak/social/linkedin/LinkedInIdentityProvider.java b/social/linkedin/src/main/java/org/keycloak/social/linkedin/LinkedInIdentityProvider.java
index 5c5265e..d6b7108 100755
--- a/social/linkedin/src/main/java/org/keycloak/social/linkedin/LinkedInIdentityProvider.java
+++ b/social/linkedin/src/main/java/org/keycloak/social/linkedin/LinkedInIdentityProvider.java
@@ -69,7 +69,7 @@ public class LinkedInIdentityProvider extends AbstractOAuth2IdentityProvider imp
 
             return user;
 		} catch (Exception e) {
-			throw new IdentityBrokerException("Could not obtain user profile from github.", e);
+			throw new IdentityBrokerException("Could not obtain user profile from linkedIn.", e);
 		}
 	}
 
diff --git a/testsuite/integration/pom.xml b/testsuite/integration/pom.xml
index 0b0b2a6..6b5051a 100755
--- a/testsuite/integration/pom.xml
+++ b/testsuite/integration/pom.xml
@@ -421,7 +421,6 @@
                 <keycloak.connectionsMongo.host>localhost</keycloak.connectionsMongo.host>
                 <keycloak.connectionsMongo.port>27018</keycloak.connectionsMongo.port>
                 <keycloak.connectionsMongo.db>keycloak</keycloak.connectionsMongo.db>
-                <keycloak.connectionsMongo.clearOnStartup>true</keycloak.connectionsMongo.clearOnStartup>
                 <keycloak.connectionsMongo.bindIp>127.0.0.1</keycloak.connectionsMongo.bindIp>
             </properties>
 
@@ -448,7 +447,6 @@
                                         <keycloak.connectionsMongo.host>${keycloak.connectionsMongo.host}</keycloak.connectionsMongo.host>
                                         <keycloak.connectionsMongo.port>${keycloak.connectionsMongo.port}</keycloak.connectionsMongo.port>
                                         <keycloak.connectionsMongo.db>${keycloak.connectionsMongo.db}</keycloak.connectionsMongo.db>
-                                        <keycloak.connectionsMongo.clearOnStartup>${keycloak.connectionsMongo.clearOnStartup}</keycloak.connectionsMongo.clearOnStartup>
                                         <keycloak.connectionsMongo.bindIp>${keycloak.connectionsMongo.bindIp}</keycloak.connectionsMongo.bindIp>
                                     </systemPropertyVariables>
                                 </configuration>
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/account/AccountTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/account/AccountTest.java
index b8cf2a8..4fafbb3 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/account/AccountTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/account/AccountTest.java
@@ -24,11 +24,9 @@ package org.keycloak.testsuite.account;
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
-import org.junit.BeforeClass;
 import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
-import org.keycloak.account.freemarker.model.ApplicationsBean;
 import org.keycloak.events.Details;
 import org.keycloak.events.Event;
 import org.keycloak.events.EventType;
@@ -155,6 +153,9 @@ public class AccountTest {
             @Override
             public void config(RealmManager manager, RealmModel defaultRealm, RealmModel appRealm) {
                 UserModel user = manager.getSession().users().getUserByUsername("test-user@localhost", appRealm);
+                user.setFirstName("Tom");
+                user.setLastName("Brady");
+                user.setEmail("test-user@localhost");
 
                 UserCredentialModel cred = new UserCredentialModel();
                 cred.setType(CredentialRepresentation.PASSWORD);
@@ -241,7 +242,9 @@ public class AccountTest {
 
         Assert.assertEquals("Invalid username or password.", loginPage.getError());
 
-        events.expectLogin().session((String) null).error("invalid_user_credentials").assertEvent();
+        events.expectLogin().session((String) null).error("invalid_user_credentials")
+                .removeDetail(Details.CONSENT)
+                .assertEvent();
 
         loginPage.open();
         loginPage.login("test-user@localhost", "new-password");
@@ -394,6 +397,61 @@ public class AccountTest {
     }
 
     @Test
+    public void changeUsername() {
+        // allow to edit the username in realm
+        keycloakRule.update(new KeycloakRule.KeycloakSetup() {
+            @Override
+            public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+                appRealm.setEditUsernameAllowed(true);
+            }
+        });
+
+        try {
+            profilePage.open();
+            loginPage.login("test-user@localhost", "password");
+
+            events.expectLogin().client("account").detail(Details.REDIRECT_URI, ACCOUNT_REDIRECT).assertEvent();
+
+            Assert.assertEquals("test-user@localhost", profilePage.getUsername());
+            Assert.assertEquals("Tom", profilePage.getFirstName());
+            Assert.assertEquals("Brady", profilePage.getLastName());
+            Assert.assertEquals("test-user@localhost", profilePage.getEmail());
+
+            // All fields are required, so there should be an error when something is missing.
+            profilePage.updateProfile("", "New first", "New last", "new@email.com");
+
+            Assert.assertEquals("Please specify username.", profilePage.getError());
+            Assert.assertEquals("", profilePage.getUsername());
+            Assert.assertEquals("New first", profilePage.getFirstName());
+            Assert.assertEquals("New last", profilePage.getLastName());
+            Assert.assertEquals("new@email.com", profilePage.getEmail());
+
+            events.assertEmpty();
+
+            profilePage.updateProfile("test-user-new@localhost", "New first", "New last", "new@email.com");
+
+            Assert.assertEquals("Your account has been updated.", profilePage.getSuccess());
+            Assert.assertEquals("test-user-new@localhost", profilePage.getUsername());
+            Assert.assertEquals("New first", profilePage.getFirstName());
+            Assert.assertEquals("New last", profilePage.getLastName());
+            Assert.assertEquals("new@email.com", profilePage.getEmail());
+
+        } finally {
+            // reset user for other tests
+            profilePage.updateProfile("test-user@localhost", "Tom", "Brady", "test-user@localhost");
+            events.clear();
+
+            // reset realm
+            keycloakRule.update(new KeycloakRule.KeycloakSetup() {
+                @Override
+                public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+                    appRealm.setEditUsernameAllowed(false);
+                }
+            });
+        }
+    }
+
+    @Test
     public void setupTotp() {
         totpPage.open();
         loginPage.login("test-user@localhost", "password");
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionEmailVerificationTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionEmailVerificationTest.java
index 0d6b4cf..4b167cb 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionEmailVerificationTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionEmailVerificationTest.java
@@ -49,7 +49,9 @@ import org.keycloak.testsuite.rule.WebRule;
 import org.openqa.selenium.WebDriver;
 
 import javax.mail.MessagingException;
+import javax.mail.Multipart;
 import javax.mail.internet.MimeMessage;
+
 import java.io.IOException;
 
 import static org.junit.Assert.assertEquals;
@@ -119,9 +121,8 @@ public class RequiredActionEmailVerificationTest {
         Assert.assertEquals(1, greenMail.getReceivedMessages().length);
 
         MimeMessage message = greenMail.getReceivedMessages()[0];
-
-        String body = (String) message.getContent();
-        String verificationUrl = MailUtil.getLink(body);
+        
+        String verificationUrl = getPasswordResetEmailLink(message);
 
         AssertEvents.ExpectedEvent emailEvent = events.expectRequiredAction(EventType.SEND_VERIFY_EMAIL).detail("email", "test-user@localhost");
         Event sendEvent = emailEvent.assertEvent();
@@ -154,14 +155,12 @@ public class RequiredActionEmailVerificationTest {
 
         MimeMessage message = greenMail.getReceivedMessages()[0];
 
-        String body = (String) message.getContent();
-
         Event sendEvent = events.expectRequiredAction(EventType.SEND_VERIFY_EMAIL).user(userId).detail("username", "verifyEmail").detail("email", "email@mail.com").assertEvent();
         String sessionId = sendEvent.getSessionId();
 
         String mailCodeId = sendEvent.getDetails().get(Details.CODE_ID);
 
-        String verificationUrl = MailUtil.getLink(body);
+        String verificationUrl = getPasswordResetEmailLink(message);
 
         driver.navigate().to(verificationUrl.trim());
 
@@ -192,11 +191,9 @@ public class RequiredActionEmailVerificationTest {
 
         MimeMessage message = greenMail.getReceivedMessages()[1];
 
-        String body = (String) message.getContent();
-
         events.expectRequiredAction(EventType.SEND_VERIFY_EMAIL).session(sessionId).detail("email", "test-user@localhost").assertEvent(sendEvent);
 
-        String verificationUrl = MailUtil.getLink(body);
+        String verificationUrl = getPasswordResetEmailLink(message);
 
         driver.navigate().to(verificationUrl.trim());
 
@@ -218,8 +215,7 @@ public class RequiredActionEmailVerificationTest {
 
         MimeMessage message = greenMail.getReceivedMessages()[0];
 
-        String body = (String) message.getContent();
-        String verificationUrl = MailUtil.getLink(body);
+        String verificationUrl = getPasswordResetEmailLink(message);
 
         AssertEvents.ExpectedEvent emailEvent = events.expectRequiredAction(EventType.SEND_VERIFY_EMAIL).detail("email", "test-user@localhost");
         Event sendEvent = emailEvent.assertEvent();
@@ -242,6 +238,27 @@ public class RequiredActionEmailVerificationTest {
 
         assertTrue(loginPage.isCurrent());
     }
-
+    
+    private String getPasswordResetEmailLink(MimeMessage message) throws IOException, MessagingException {
+    	Multipart multipart = (Multipart) message.getContent();
+    	
+        final String textContentType = multipart.getBodyPart(0).getContentType();
+        
+        assertEquals("text/plain; charset=UTF-8", textContentType);
+        
+        final String textBody = (String) multipart.getBodyPart(0).getContent();
+        final String textChangePwdUrl = MailUtil.getLink(textBody);
+    	
+        final String htmlContentType = multipart.getBodyPart(1).getContentType();
+        
+        assertEquals("text/html; charset=UTF-8", htmlContentType);
+        
+        final String htmlBody = (String) multipart.getBodyPart(1).getContent();
+        final String htmlChangePwdUrl = MailUtil.getLink(htmlBody);
+        
+        assertEquals(htmlChangePwdUrl, textChangePwdUrl);
+
+        return htmlChangePwdUrl;
+    }
 
 }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTest.java
index 2ea5ecc..3f3e453 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTest.java
@@ -48,21 +48,50 @@ public class AdapterTest {
             realmPublicKey = realm.getPublicKey();
 
             URL url = getClass().getResource("/adapter-test/cust-app-keycloak.json");
-            deployApplication("customer-portal", "/customer-portal", CustomerServlet.class, url.getPath(), "user");
+            createApplicationDeployment()
+                    .name("customer-portal").contextPath("/customer-portal")
+                    .servletClass(CustomerServlet.class).adapterConfigPath(url.getPath())
+                    .role("user").deployApplication();
+
             url = getClass().getResource("/adapter-test/secure-portal-keycloak.json");
-            deployApplication("secure-portal", "/secure-portal", CallAuthenticatedServlet.class, url.getPath(), "user", false);
+            createApplicationDeployment()
+                    .name("secure-portal").contextPath("/secure-portal")
+                    .servletClass(CallAuthenticatedServlet.class).adapterConfigPath(url.getPath())
+                    .role("user")
+                    .isConstrained(false).deployApplication();
+
             url = getClass().getResource("/adapter-test/customer-db-keycloak.json");
-            deployApplication("customer-db", "/customer-db", CustomerDatabaseServlet.class, url.getPath(), "user");
+            createApplicationDeployment()
+                    .name("customer-db").contextPath("/customer-db")
+                    .servletClass(CustomerDatabaseServlet.class).adapterConfigPath(url.getPath())
+                    .role("user")
+                    .errorPage(null).deployApplication();
+
+            createApplicationDeployment()
+                    .name("customer-db-error-page").contextPath("/customer-db-error-page")
+                    .servletClass(CustomerDatabaseServlet.class).adapterConfigPath(url.getPath())
+                    .role("user").deployApplication();
+
             url = getClass().getResource("/adapter-test/product-keycloak.json");
-            deployApplication("product-portal", "/product-portal", ProductServlet.class, url.getPath(), "user");
+            createApplicationDeployment()
+                    .name("product-portal").contextPath("/product-portal")
+                    .servletClass(ProductServlet.class).adapterConfigPath(url.getPath())
+                    .role("user").deployApplication();
 
             // Test that replacing system properties works for adapters
             System.setProperty("app.server.base.url", "http://localhost:8081");
             System.setProperty("my.host.name", "localhost");
             url = getClass().getResource("/adapter-test/session-keycloak.json");
-            deployApplication("session-portal", "/session-portal", SessionServlet.class, url.getPath(), "user");
+            createApplicationDeployment()
+                    .name("session-portal").contextPath("/session-portal")
+                    .servletClass(SessionServlet.class).adapterConfigPath(url.getPath())
+                    .role("user").deployApplication();
+
             url = getClass().getResource("/adapter-test/input-keycloak.json");
-            deployApplication("input-portal", "/input-portal", InputServlet.class, url.getPath(), "user", true, null, "/secured/*");
+            createApplicationDeployment()
+                    .name("input-portal").contextPath("/input-portal")
+                    .servletClass(InputServlet.class).adapterConfigPath(url.getPath())
+                    .role("user").constraintUrl("/secured/*").deployApplication();
         }
     };
 
@@ -110,6 +139,15 @@ public class AdapterTest {
     }
 
     /**
+     * KEYCLOAK-1368
+     * @throws Exception
+     */
+    @Test
+    public void testNullBearerTokenCustomErrorPage() throws Exception {
+        testStrategy.testNullBearerTokenCustomErrorPage();
+    }
+
+    /**
      * KEYCLOAK-518
      * @throws Exception
      */
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTestStrategy.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTestStrategy.java
index 3f0e07e..e26baea 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTestStrategy.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTestStrategy.java
@@ -21,6 +21,11 @@
  */
 package org.keycloak.testsuite.adapter;
 
+import io.undertow.util.Headers;
+import org.apache.http.client.HttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
+import org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient4Engine;
 import org.junit.Assert;
 import org.junit.rules.ExternalResource;
 import org.keycloak.Config;
@@ -117,9 +122,6 @@ public class AdapterTestStrategy extends ExternalResource {
     }
 
     public static RealmModel baseAdapterTestInitialization(KeycloakSession session, RealmManager manager, RealmModel adminRealm, Class<?> clazz) {
-        // Required by admin client
-        adminRealm.setPasswordCredentialGrantAllowed(true);
-
         RealmRepresentation representation = KeycloakServer.loadJson(clazz.getResourceAsStream("/adapter-test/demorealm.json"), RealmRepresentation.class);
         RealmModel demoRealm = manager.importRealm(representation);
         return demoRealm;
@@ -394,6 +396,43 @@ public class AdapterTestStrategy extends ExternalResource {
     }
 
     /**
+     * KEYCLOAK-1368
+     * @throws Exception
+     */
+    public void testNullBearerTokenCustomErrorPage() throws Exception {
+        Client client = ClientBuilder.newClient();
+        WebTarget target = client.target(APP_SERVER_BASE_URL + "/customer-db-error-page/");
+
+        Response response = target.request().get();
+
+        // TODO: follow redirects automatically if possible
+        if (response.getStatus() == 302) {
+            String location = response.getHeaderString(HttpHeaders.LOCATION);
+            response.close();
+            response = client.target(location).request().get();
+        }
+        Assert.assertEquals(200, response.getStatus());
+        String errorPageResponse = response.readEntity(String.class);
+        Assert.assertTrue(errorPageResponse.contains("Error Page"));
+        response.close();
+
+        response = target.request().header(HttpHeaders.AUTHORIZATION, "Bearer null").get();
+        // TODO: follow redirects automatically if possible
+        if (response.getStatus() == 302) {
+            String location = response.getHeaderString(HttpHeaders.LOCATION);
+            response.close();
+            response = client.target(location).request().get();
+        }
+        Assert.assertEquals(200, response.getStatus());
+        errorPageResponse = response.readEntity(String.class);
+        Assert.assertTrue(errorPageResponse.contains("Error Page"));
+        response.close();
+
+        client.close();
+
+    }
+
+    /**
      * KEYCLOAK-518
      * @throws Exception
      */
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/CookieTokenStoreAdapterTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/CookieTokenStoreAdapterTest.java
index 405609c..243a626 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/CookieTokenStoreAdapterTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/CookieTokenStoreAdapterTest.java
@@ -45,11 +45,23 @@ public class CookieTokenStoreAdapterTest {
             manager.importRealm(representation);
 
             URL url = getClass().getResource("/adapter-test/cust-app-keycloak.json");
-            deployApplication("customer-portal", "/customer-portal", CustomerServlet.class, url.getPath(), "user");
+            createApplicationDeployment()
+                    .name("customer-portal").contextPath("/customer-portal")
+                    .servletClass(CustomerServlet.class).adapterConfigPath(url.getPath())
+                    .role("user").deployApplication();
+
             url = getClass().getResource("/adapter-test/cust-app-cookie-keycloak.json");
-            deployApplication("customer-cookie-portal", "/customer-cookie-portal", CustomerServlet.class, url.getPath(), "user");
+            createApplicationDeployment()
+                    .name("customer-cookie-portal").contextPath("/customer-cookie-portal")
+                    .servletClass(CustomerServlet.class).adapterConfigPath(url.getPath())
+                    .role("user").deployApplication();
+
             url = getClass().getResource("/adapter-test/customer-db-keycloak.json");
-            deployApplication("customer-db", "/customer-db", CustomerDatabaseServlet.class, url.getPath(), "user");
+            createApplicationDeployment()
+                    .name("customer-db").contextPath("/customer-db")
+                    .servletClass(CustomerDatabaseServlet.class).adapterConfigPath(url.getPath())
+                    .role("user")
+                    .errorPage(null).deployApplication();
         }
     };
 
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/MultiTenancyTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/MultiTenancyTest.java
index 83f3ff6..7c95796 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/MultiTenancyTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/MultiTenancyTest.java
@@ -26,6 +26,7 @@ import org.keycloak.models.RealmModel;
 import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
 import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.services.managers.RealmManager;
+import org.keycloak.testsuite.federation.KerberosCredDelegServlet;
 import org.keycloak.testsuite.pages.LoginPage;
 import org.keycloak.testsuite.rule.AbstractKeycloakRule;
 import org.keycloak.testsuite.rule.WebResource;
@@ -57,7 +58,11 @@ public class MultiTenancyTest {
             RealmRepresentation tenant2 = KeycloakServer.loadJson(getClass().getResourceAsStream("/adapter-test/tenant2-realm.json"), RealmRepresentation.class);
             manager.importRealm(tenant2);
 
-            deployApplication("multi-tenant", "/multi-tenant", MultiTenantServlet.class, null, "user", true, MultiTenantResolver.class);
+            createApplicationDeployment()
+                    .name("multi-tenant").contextPath("/multi-tenant")
+                    .servletClass(MultiTenantServlet.class)
+                    .role("user")
+                    .keycloakConfigResolver(MultiTenantResolver.class).deployApplication();
         }
 
         protected String[] getTestRealms() {
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/RelativeUriAdapterTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/RelativeUriAdapterTest.java
index 3ab244f..6283718 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/RelativeUriAdapterTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/RelativeUriAdapterTest.java
@@ -76,19 +76,29 @@ public class RelativeUriAdapterTest {
     public static AbstractKeycloakRule keycloakRule = new AbstractKeycloakRule(){
         @Override
         protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) {
-            adminRealm.setPasswordCredentialGrantAllowed(true);
-
             RealmRepresentation representation = KeycloakServer.loadJson(getClass().getResourceAsStream("/adapter-test/demorealm-relative.json"), RealmRepresentation.class);
             RealmModel realm = manager.importRealm(representation);
 
             realmPublicKey = realm.getPublicKey();
 
             URL url = getClass().getResource("/adapter-test/cust-app-keycloak-relative.json");
-            deployApplication("customer-portal", "/customer-portal", CustomerServlet.class, url.getPath(), "user");
+            createApplicationDeployment()
+                    .name("customer-portal").contextPath("/customer-portal")
+                    .servletClass(CustomerServlet.class).adapterConfigPath(url.getPath())
+                    .role("user").deployApplication();
+
             url = getClass().getResource("/adapter-test/customer-db-keycloak-relative.json");
-            deployApplication("customer-db", "/customer-db", CustomerDatabaseServlet.class, url.getPath(), "user");
+            createApplicationDeployment()
+                    .name("customer-db").contextPath("/customer-db")
+                    .servletClass(CustomerDatabaseServlet.class).adapterConfigPath(url.getPath())
+                    .role("user")
+                    .errorPage(null).deployApplication();
+
             url = getClass().getResource("/adapter-test/product-keycloak-relative.json");
-            deployApplication("product-portal", "/product-portal", ProductServlet.class, url.getPath(), "user");
+            createApplicationDeployment()
+                    .name("product-portal").contextPath("/product-portal")
+                    .servletClass(ProductServlet.class).adapterConfigPath(url.getPath())
+                    .role("user").deployApplication();
         }
     };
 
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/AbstractClientTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/AbstractClientTest.java
index 1a8c554..cfc9270 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/AbstractClientTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/AbstractClientTest.java
@@ -39,8 +39,6 @@ public abstract class AbstractClientTest {
         keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
             @Override
             public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
-                adminstrationRealm.setPasswordCredentialGrantAllowed(true);
-
                 RealmModel testRealm = manager.createRealm(REALM_NAME);
                 testRealm.setEnabled(true);
                 KeycloakModelUtils.generateRealmKeys(testRealm);
@@ -58,8 +56,6 @@ public abstract class AbstractClientTest {
         keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
             @Override
             public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
-                adminstrationRealm.setPasswordCredentialGrantAllowed(false);
-
                 RealmModel realm = manager.getRealmByName(REALM_NAME);
                 if (realm != null) {
                     manager.removeRealm(realm);
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/AdminAPITest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/AdminAPITest.java
index afee212..3bde1cb 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/AdminAPITest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/AdminAPITest.java
@@ -236,12 +236,12 @@ public class AdminAPITest {
         if (rep.getQuickLoginCheckMilliSeconds() != null) Assert.assertEquals(rep.getQuickLoginCheckMilliSeconds(), storedRealm.getQuickLoginCheckMilliSeconds());
         if (rep.getMaxDeltaTimeSeconds() != null) Assert.assertEquals(rep.getMaxDeltaTimeSeconds(), storedRealm.getMaxDeltaTimeSeconds());
         if (rep.getFailureFactor() != null) Assert.assertEquals(rep.getFailureFactor(), storedRealm.getFailureFactor());
-        if (rep.isPasswordCredentialGrantAllowed() != null) Assert.assertEquals(rep.isPasswordCredentialGrantAllowed(), storedRealm.isPasswordCredentialGrantAllowed());
         if (rep.isRegistrationAllowed() != null) Assert.assertEquals(rep.isRegistrationAllowed(), storedRealm.isRegistrationAllowed());
         if (rep.isRegistrationEmailAsUsername() != null) Assert.assertEquals(rep.isRegistrationEmailAsUsername(), storedRealm.isRegistrationEmailAsUsername());
         if (rep.isRememberMe() != null) Assert.assertEquals(rep.isRememberMe(), storedRealm.isRememberMe());
         if (rep.isVerifyEmail() != null) Assert.assertEquals(rep.isVerifyEmail(), storedRealm.isVerifyEmail());
         if (rep.isResetPasswordAllowed() != null) Assert.assertEquals(rep.isResetPasswordAllowed(), storedRealm.isResetPasswordAllowed());
+        if (rep.isEditUsernameAllowed() != null) Assert.assertEquals(rep.isEditUsernameAllowed(), storedRealm.isEditUsernameAllowed());
         if (rep.getSslRequired() != null) Assert.assertEquals(rep.getSslRequired(), storedRealm.getSslRequired());
         if (rep.getAccessCodeLifespan() != null) Assert.assertEquals(rep.getAccessCodeLifespan(), storedRealm.getAccessCodeLifespan());
         if (rep.getAccessCodeLifespanUserAction() != null)
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/IdentityProviderTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/IdentityProviderTest.java
index 80cc7a0..a7bae96 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/IdentityProviderTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/IdentityProviderTest.java
@@ -52,7 +52,8 @@ public class IdentityProviderTest extends AbstractClientTest {
         assertEquals("clientSecret", representation.getConfig().get("clientSecret"));
         assertTrue(representation.isEnabled());
         assertFalse(representation.isStoreToken());
-        assertTrue(representation.isUpdateProfileFirstLogin());
+        assertEquals(IdentityProviderRepresentation.UPFLM_ON, representation.getUpdateProfileFirstLoginMode());
+        assertFalse(representation.isTrustEmail());
     }
 
     @Test
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/RealmTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/RealmTest.java
index 1b02d0b..6cf6427 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/RealmTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/RealmTest.java
@@ -71,6 +71,7 @@ public class RealmTest extends AbstractClientTest {
         rep.setAccessCodeLifespanLogin(1234);
         rep.setRegistrationAllowed(true);
         rep.setRegistrationEmailAsUsername(true);
+        rep.setEditUsernameAllowed(true);
 
         realm.update(rep);
 
@@ -81,16 +82,19 @@ public class RealmTest extends AbstractClientTest {
         assertEquals(1234, rep.getAccessCodeLifespanLogin().intValue());
         assertEquals(Boolean.TRUE, rep.isRegistrationAllowed());
         assertEquals(Boolean.TRUE, rep.isRegistrationEmailAsUsername());
+        assertEquals(Boolean.TRUE, rep.isEditUsernameAllowed());
 
         // second change
         rep.setRegistrationAllowed(false);
         rep.setRegistrationEmailAsUsername(false);
+        rep.setEditUsernameAllowed(false);
 
         realm.update(rep);
 
         rep = realm.toRepresentation();
         assertEquals(Boolean.FALSE, rep.isRegistrationAllowed());
         assertEquals(Boolean.FALSE, rep.isRegistrationEmailAsUsername());
+        assertEquals(Boolean.FALSE, rep.isEditUsernameAllowed());
     }
 
     @Test
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/UserTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/UserTest.java
index 5b3623d..42dd464 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/UserTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/UserTest.java
@@ -1,13 +1,13 @@
 package org.keycloak.testsuite.admin;
 
 import org.junit.Assert;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.keycloak.admin.client.resource.IdentityProviderResource;
 import org.keycloak.admin.client.resource.UserResource;
 import org.keycloak.representations.idm.ErrorRepresentation;
 import org.keycloak.representations.idm.FederatedIdentityRepresentation;
 import org.keycloak.representations.idm.IdentityProviderRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.representations.idm.UserRepresentation;
 
 import javax.ws.rs.ClientErrorException;
@@ -410,4 +410,78 @@ public class UserTest extends AbstractClientTest {
             Assert.assertEquals("invalidClientId not enabled", error.getErrorMessage());
         }
     }
+
+    @Test
+    public void updateUserWithNewUsername() {
+        switchEditUsernameAllowedOn();
+        String id = createUser();
+
+        UserResource user = realm.users().get(id);
+        UserRepresentation userRep = user.toRepresentation();
+        userRep.setUsername("user11");
+        user.update(userRep);
+
+        userRep = realm.users().get(id).toRepresentation();
+        assertEquals("user11", userRep.getUsername());
+    }
+
+    @Test
+    public void updateUserWithNewUsernameNotPossible() {
+        String id = createUser();
+
+        UserResource user = realm.users().get(id);
+        UserRepresentation userRep = user.toRepresentation();
+        userRep.setUsername("user11");
+        user.update(userRep);
+
+        userRep = realm.users().get(id).toRepresentation();
+        assertEquals("user1", userRep.getUsername());
+    }
+
+    @Test
+    public void updateUserWithNewUsernameAccessingViaOldUsername() {
+        switchEditUsernameAllowedOn();
+        createUser();
+
+        try {
+            UserResource user = realm.users().get("user1");
+            UserRepresentation userRep = user.toRepresentation();
+            userRep.setUsername("user1");
+            user.update(userRep);
+
+            realm.users().get("user11").toRepresentation();
+            fail("Expected failure");
+        } catch (ClientErrorException e) {
+            assertEquals(404, e.getResponse().getStatus());
+        }
+    }
+
+    @Test
+    public void updateUserWithExistingUsername() {
+        switchEditUsernameAllowedOn();
+        createUser();
+
+        UserRepresentation userRep = new UserRepresentation();
+        userRep.setUsername("user2");
+        Response response = realm.users().create(userRep);
+        String createdId = ApiUtil.getCreatedId(response);
+        response.close();
+
+        try {
+            UserResource user = realm.users().get(createdId);
+            userRep = user.toRepresentation();
+            userRep.setUsername("user1");
+            user.update(userRep);
+            fail("Expected failure");
+        } catch (ClientErrorException e) {
+            assertEquals(409, e.getResponse().getStatus());
+        }
+    }
+
+    private void switchEditUsernameAllowedOn() {
+        RealmRepresentation rep = realm.toRepresentation();
+        rep.setEditUsernameAllowed(true);
+        realm.update(rep);
+    }
+
 }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/AssertEvents.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/AssertEvents.java
index ce80527..21e5190 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/AssertEvents.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/AssertEvents.java
@@ -113,7 +113,7 @@ public class AssertEvents implements TestRule, EventListenerProviderFactory {
     }
 
     public ExpectedEvent expectRequiredAction(EventType event) {
-        return expectLogin().event(event).session(isUUID());
+        return expectLogin().event(event).removeDetail(Details.CONSENT).session(isUUID());
     }
 
     public ExpectedEvent expectLogin() {
@@ -123,6 +123,7 @@ public class AssertEvents implements TestRule, EventListenerProviderFactory {
                 .detail(Details.RESPONSE_TYPE, "code")
                 .detail(Details.AUTH_METHOD, "form")
                 .detail(Details.REDIRECT_URI, DEFAULT_REDIRECT_URI)
+                .detail(Details.CONSENT, Details.CONSENT_VALUE_NO_CONSENT_REQUIRED)
                 .session(isUUID());
     }
 
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java
index 1ad0207..3f4ffa5 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java
@@ -34,7 +34,9 @@ import org.keycloak.models.RoleModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.UserModel.RequiredAction;
 import org.keycloak.representations.IDToken;
+import org.keycloak.representations.idm.IdentityProviderRepresentation;
 import org.keycloak.services.Urls;
+import org.keycloak.testsuite.MailUtil;
 import org.keycloak.testsuite.OAuthClient;
 import org.keycloak.testsuite.broker.util.UserSessionStatusServlet.UserSessionStatus;
 import org.keycloak.testsuite.pages.AccountFederatedIdentityPage;
@@ -42,6 +44,8 @@ import org.keycloak.testsuite.pages.AccountPasswordPage;
 import org.keycloak.testsuite.pages.LoginPage;
 import org.keycloak.testsuite.pages.LoginUpdateProfilePage;
 import org.keycloak.testsuite.pages.OAuthGrantPage;
+import org.keycloak.testsuite.pages.VerifyEmailPage;
+import org.keycloak.testsuite.rule.GreenMailRule;
 import org.keycloak.testsuite.rule.WebResource;
 import org.keycloak.testsuite.rule.WebRule;
 import org.openqa.selenium.By;
@@ -49,6 +53,9 @@ import org.openqa.selenium.NoSuchElementException;
 import org.openqa.selenium.WebDriver;
 import org.openqa.selenium.WebElement;
 
+import javax.mail.MessagingException;
+import javax.mail.Multipart;
+import javax.mail.internet.MimeMessage;
 import javax.ws.rs.client.Client;
 import javax.ws.rs.client.ClientBuilder;
 import javax.ws.rs.client.ClientRequestContext;
@@ -58,6 +65,7 @@ import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.Status;
 import javax.ws.rs.core.UriBuilder;
+
 import java.io.IOException;
 import java.net.URI;
 import java.util.List;
@@ -91,6 +99,13 @@ public abstract class AbstractIdentityProviderTest {
     @WebResource
     private LoginUpdateProfilePage updateProfilePage;
 
+
+    @WebResource
+    protected VerifyEmailPage verifyEmailPage;
+
+    @Rule
+    public GreenMailRule greenMail = new GreenMailRule();
+
     @WebResource
     protected OAuthClient oauth;
 
@@ -123,17 +138,106 @@ public abstract class AbstractIdentityProviderTest {
     @Test
     public void testSuccessfulAuthentication() {
         IdentityProviderModel identityProviderModel = getIdentityProviderModel();
+        identityProviderModel.setUpdateProfileFirstLoginMode(IdentityProviderRepresentation.UPFLM_ON);
 
-        UserModel user = assertSuccessfulAuthentication(identityProviderModel, "test-user", "new@email.com");
+        UserModel user = assertSuccessfulAuthentication(identityProviderModel, "test-user", "new@email.com", true);
         Assert.assertEquals("617-666-7777", user.getAttribute("mobile"));
     }
 
     @Test
+    public void testSuccessfulAuthenticationUpdateProfileOnMissing_nothingMissing() {
+        IdentityProviderModel identityProviderModel = getIdentityProviderModel();
+        identityProviderModel.setUpdateProfileFirstLoginMode(IdentityProviderRepresentation.UPFLM_MISSING);
+
+        assertSuccessfulAuthentication(identityProviderModel, "test-user", "test-user@localhost", false);
+    }
+
+    @Test
+    public void testSuccessfulAuthenticationUpdateProfileOnMissing_missingEmail() {
+        IdentityProviderModel identityProviderModel = getIdentityProviderModel();
+        identityProviderModel.setUpdateProfileFirstLoginMode(IdentityProviderRepresentation.UPFLM_MISSING);
+
+        assertSuccessfulAuthentication(identityProviderModel, "test-user-noemail", "new@email.com", true);
+    }
+
+    @Test
     public void testSuccessfulAuthenticationWithoutUpdateProfile() {
         IdentityProviderModel identityProviderModel = getIdentityProviderModel();
-        identityProviderModel.setUpdateProfileFirstLogin(false);
+        identityProviderModel.setUpdateProfileFirstLoginMode(IdentityProviderRepresentation.UPFLM_OFF);
 
-        assertSuccessfulAuthentication(identityProviderModel, "test-user", "test-user@localhost");
+        assertSuccessfulAuthentication(identityProviderModel, "test-user", "test-user@localhost", false);
+    }
+
+    /**
+     * Test that verify email action is performed if email is provided and email trust is not enabled for the provider
+     * 
+     * @throws MessagingException
+     * @throws IOException
+     */
+    @Test
+    public void testSuccessfulAuthenticationWithoutUpdateProfile_emailProvided_emailVerifyEnabled() throws IOException, MessagingException {
+        getRealm().setVerifyEmail(true);
+        brokerServerRule.stopSession(this.session, true);
+        this.session = brokerServerRule.startSession();
+
+        IdentityProviderModel identityProviderModel = getIdentityProviderModel();
+        try {
+            identityProviderModel.setUpdateProfileFirstLoginMode(IdentityProviderRepresentation.UPFLM_OFF);
+            identityProviderModel.setTrustEmail(false);
+
+            UserModel federatedUser = assertSuccessfulAuthenticationWithEmailVerification(identityProviderModel, "test-user", "test-user@localhost", false);
+
+            // email is verified now
+            assertFalse(federatedUser.getRequiredActions().contains(RequiredAction.VERIFY_EMAIL.name()));
+
+        } finally {
+            getRealm().setVerifyEmail(false);
+        }
+    }
+
+    private UserModel assertSuccessfulAuthenticationWithEmailVerification(IdentityProviderModel identityProviderModel, String username, String expectedEmail,
+            boolean isProfileUpdateExpected)
+            throws IOException, MessagingException {
+        authenticateWithIdentityProvider(identityProviderModel, username, isProfileUpdateExpected);
+
+        // verify email is sent
+        Assert.assertTrue(verifyEmailPage.isCurrent());
+
+        // read email to take verification link from
+        Assert.assertEquals(1, greenMail.getReceivedMessages().length);
+        MimeMessage message = greenMail.getReceivedMessages()[0];
+        String verificationUrl = getVerificationEmailLink(message);
+
+        driver.navigate().to(verificationUrl.trim());
+
+        // authenticated and redirected to app
+        assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/test-app"));
+
+        UserModel federatedUser = getFederatedUser();
+
+        assertNotNull(federatedUser);
+
+        doAssertFederatedUser(federatedUser, identityProviderModel, expectedEmail, isProfileUpdateExpected);
+
+        brokerServerRule.stopSession(session, true);
+        session = brokerServerRule.startSession();
+
+        RealmModel realm = getRealm();
+
+        Set<FederatedIdentityModel> federatedIdentities = this.session.users().getFederatedIdentities(federatedUser, realm);
+
+        assertEquals(1, federatedIdentities.size());
+
+        FederatedIdentityModel federatedIdentityModel = federatedIdentities.iterator().next();
+
+        assertEquals(getProviderId(), federatedIdentityModel.getIdentityProvider());
+        assertEquals(federatedUser.getUsername(), federatedIdentityModel.getIdentityProvider() + "." + federatedIdentityModel.getUserName());
+
+        driver.navigate().to("http://localhost:8081/test-app/logout");
+        driver.navigate().to("http://localhost:8081/test-app");
+
+        assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/auth"));
+        return federatedUser;
     }
 
     /**
@@ -147,9 +251,9 @@ public abstract class AbstractIdentityProviderTest {
 
         try {
             IdentityProviderModel identityProviderModel = getIdentityProviderModel();
-            identityProviderModel.setUpdateProfileFirstLogin(false);
+            identityProviderModel.setUpdateProfileFirstLoginMode(IdentityProviderRepresentation.UPFLM_OFF);
 
-            UserModel federatedUser = assertSuccessfulAuthentication(identityProviderModel, "test-user-noemail", null);
+            UserModel federatedUser = assertSuccessfulAuthentication(identityProviderModel, "test-user-noemail", null, false);
 
             assertTrue(federatedUser.getRequiredActions().contains(RequiredAction.VERIFY_EMAIL.name()));
 
@@ -158,6 +262,55 @@ public abstract class AbstractIdentityProviderTest {
         }
     }
 
+    /**
+     * Test for KEYCLOAK-1372 - verify email action is not performed if email is provided but email trust is enabled for the provider
+     */
+    @Test
+    public void testSuccessfulAuthenticationWithoutUpdateProfile_emailProvided_emailVerifyEnabled_emailTrustEnabled() {
+        getRealm().setVerifyEmail(true);
+        brokerServerRule.stopSession(this.session, true);
+        this.session = brokerServerRule.startSession();
+
+        IdentityProviderModel identityProviderModel = getIdentityProviderModel();
+        try {
+            identityProviderModel.setUpdateProfileFirstLoginMode(IdentityProviderRepresentation.UPFLM_OFF);
+            identityProviderModel.setTrustEmail(true);
+
+            UserModel federatedUser = assertSuccessfulAuthentication(identityProviderModel, "test-user", "test-user@localhost", false);
+
+            assertFalse(federatedUser.getRequiredActions().contains(RequiredAction.VERIFY_EMAIL.name()));
+
+        } finally {
+            identityProviderModel.setTrustEmail(false);
+            getRealm().setVerifyEmail(false);
+        }
+    }
+
+    /**
+     * Test for KEYCLOAK-1372 - verify email action is performed if email is provided and email trust is enabled for the provider, but email is changed on First login update profile page
+     * 
+     * @throws MessagingException
+     * @throws IOException
+     */
+    @Test
+    public void testSuccessfulAuthentication_emailTrustEnabled_emailVerifyEnabled_emailUpdatedOnFirstLogin() throws IOException, MessagingException {
+        getRealm().setVerifyEmail(true);
+        brokerServerRule.stopSession(this.session, true);
+        this.session = brokerServerRule.startSession();
+
+        IdentityProviderModel identityProviderModel = getIdentityProviderModel();
+        try {
+            identityProviderModel.setUpdateProfileFirstLoginMode(IdentityProviderRepresentation.UPFLM_ON);
+            identityProviderModel.setTrustEmail(true);
+
+            UserModel user = assertSuccessfulAuthenticationWithEmailVerification(identityProviderModel, "test-user", "new@email.com", true);
+            Assert.assertEquals("617-666-7777", user.getAttribute("mobile"));
+        } finally {
+            identityProviderModel.setTrustEmail(false);
+            getRealm().setVerifyEmail(false);
+        }
+    }
+
     @Test
     public void testSuccessfulAuthenticationWithoutUpdateProfile_newUser_emailAsUsername() {
 
@@ -167,9 +320,9 @@ public abstract class AbstractIdentityProviderTest {
 
         try {
             IdentityProviderModel identityProviderModel = getIdentityProviderModel();
-            identityProviderModel.setUpdateProfileFirstLogin(false);
+            identityProviderModel.setUpdateProfileFirstLoginMode(IdentityProviderRepresentation.UPFLM_OFF);
 
-            authenticateWithIdentityProvider(identityProviderModel, "test-user");
+            authenticateWithIdentityProvider(identityProviderModel, "test-user", false);
 
             // authenticated and redirected to app
             assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/test-app"));
@@ -186,7 +339,7 @@ public abstract class AbstractIdentityProviderTest {
 
             assertEquals("test-user@localhost", federatedUser.getUsername());
 
-            doAssertFederatedUser(federatedUser, identityProviderModel, "test-user@localhost");
+            doAssertFederatedUser(federatedUser, identityProviderModel, "test-user@localhost", false);
 
             Set<FederatedIdentityModel> federatedIdentities = this.session.users().getFederatedIdentities(federatedUser, realm);
 
@@ -215,9 +368,9 @@ public abstract class AbstractIdentityProviderTest {
 
         try {
             IdentityProviderModel identityProviderModel = getIdentityProviderModel();
-            identityProviderModel.setUpdateProfileFirstLogin(false);
+            identityProviderModel.setUpdateProfileFirstLoginMode(IdentityProviderRepresentation.UPFLM_OFF);
 
-            authenticateWithIdentityProvider(identityProviderModel, "test-user-noemail");
+            authenticateWithIdentityProvider(identityProviderModel, "test-user-noemail", false);
 
             brokerServerRule.stopSession(session, true);
             session = brokerServerRule.startSession();
@@ -275,15 +428,10 @@ public abstract class AbstractIdentityProviderTest {
 
     @Test
     public void testProviderOnLoginPage() {
-        IdentityProviderModel identityProviderModel = getIdentityProviderModel();
-        RealmModel realm = getRealm();
-        ClientModel clientModel = realm.getClientByClientId("test-app");
-
         // Provider button is available on login page
         this.driver.navigate().to("http://localhost:8081/test-app/");
         assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/auth"));
         loginPage.findSocialButton(getProviderId());
-
      }
 
     @Test
@@ -325,7 +473,7 @@ public abstract class AbstractIdentityProviderTest {
     public void testUserAlreadyExistsWhenNotUpdatingProfile() {
         IdentityProviderModel identityProviderModel = getIdentityProviderModel();
 
-        identityProviderModel.setUpdateProfileFirstLogin(false);
+        identityProviderModel.setUpdateProfileFirstLoginMode(IdentityProviderRepresentation.UPFLM_OFF);
 
         this.driver.navigate().to("http://localhost:8081/test-app/");
 
@@ -390,7 +538,6 @@ public abstract class AbstractIdentityProviderTest {
         revokeGrant();
 
         // Logout from account management
-        String pageSource = driver.getPageSource();
         System.out.println("*** logout from account management");
         accountFederatedIdentityPage.logout();
         assertTrue(driver.getTitle().equals("Log in to realm-with-broker"));
@@ -400,7 +547,6 @@ public abstract class AbstractIdentityProviderTest {
         this.loginPage.clickSocial(identityProviderModel.getAlias());
         this.loginPage.login("test-user", "password");
         doAfterProviderAuthentication();
-        String current = driver.getCurrentUrl();
         this.updateProfilePage.assertCurrent();
     }
 
@@ -465,7 +611,7 @@ public abstract class AbstractIdentityProviderTest {
 
         identityProviderModel.setStoreToken(true);
 
-        authenticateWithIdentityProvider(identityProviderModel, "test-user");
+        authenticateWithIdentityProvider(identityProviderModel, "test-user", true);
 
         UserModel federatedUser = getFederatedUser();
         RealmModel realm = getRealm();
@@ -530,17 +676,18 @@ public abstract class AbstractIdentityProviderTest {
 
     protected abstract void doAssertTokenRetrieval(String pageSource);
 
-    private UserModel assertSuccessfulAuthentication(IdentityProviderModel identityProviderModel, String username, String expectedEmail) {
-        authenticateWithIdentityProvider(identityProviderModel, username);
+    private UserModel assertSuccessfulAuthentication(IdentityProviderModel identityProviderModel, String username, String expectedEmail, boolean isProfileUpdateExpected) {
+        authenticateWithIdentityProvider(identityProviderModel, username, isProfileUpdateExpected);
 
         // authenticated and redirected to app
-        assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/test-app"));
+        assertTrue("Bad current URL " + this.driver.getCurrentUrl() + " and page source: " + this.driver.getPageSource(),
+                this.driver.getCurrentUrl().startsWith("http://localhost:8081/test-app"));
 
         UserModel federatedUser = getFederatedUser();
 
         assertNotNull(federatedUser);
 
-        doAssertFederatedUser(federatedUser, identityProviderModel, expectedEmail);
+        doAssertFederatedUser(federatedUser, identityProviderModel, expectedEmail, isProfileUpdateExpected);
 
         brokerServerRule.stopSession(session, true);
         session = brokerServerRule.startSession();
@@ -563,11 +710,11 @@ public abstract class AbstractIdentityProviderTest {
         return federatedUser;
     }
 
-    private void authenticateWithIdentityProvider(IdentityProviderModel identityProviderModel, String username) {
+    private void authenticateWithIdentityProvider(IdentityProviderModel identityProviderModel, String username, boolean isProfileUpdateExpected) {
         loginIDP(username);
 
 
-        if (identityProviderModel.isUpdateProfileFirstLogin()) {
+        if (isProfileUpdateExpected) {
             String userEmail = "new@email.com";
             String userFirstName = "New first";
             String userLastName = "New last";
@@ -576,6 +723,7 @@ public abstract class AbstractIdentityProviderTest {
             this.updateProfilePage.assertCurrent();
             this.updateProfilePage.update(userFirstName, userLastName, userEmail);
         }
+
     }
 
     private void loginIDP(String username) {
@@ -621,7 +769,7 @@ public abstract class AbstractIdentityProviderTest {
 
         assertNotNull(identityProviderModel);
 
-        identityProviderModel.setUpdateProfileFirstLogin(true);
+        identityProviderModel.setUpdateProfileFirstLoginMode(IdentityProviderRepresentation.UPFLM_ON);
         identityProviderModel.setEnabled(true);
 
         return identityProviderModel;
@@ -631,8 +779,8 @@ public abstract class AbstractIdentityProviderTest {
         return this.session.realms().getRealm("realm-with-broker");
     }
 
-    protected void doAssertFederatedUser(UserModel federatedUser, IdentityProviderModel identityProviderModel, String expectedEmail) {
-        if (identityProviderModel.isUpdateProfileFirstLogin()) {
+    protected void doAssertFederatedUser(UserModel federatedUser, IdentityProviderModel identityProviderModel, String expectedEmail, boolean isProfileUpdateExpected) {
+        if (isProfileUpdateExpected) {
             String userFirstName = "New first";
             String userLastName = "New last";
 
@@ -677,4 +825,26 @@ public abstract class AbstractIdentityProviderTest {
             }
         }
     }
+    
+    private String getVerificationEmailLink(MimeMessage message) throws IOException, MessagingException {
+    	Multipart multipart = (Multipart) message.getContent();
+    	
+        final String textContentType = multipart.getBodyPart(0).getContentType();
+        
+        assertEquals("text/plain; charset=UTF-8", textContentType);
+        
+        final String textBody = (String) multipart.getBodyPart(0).getContent();
+        final String textVerificationUrl = MailUtil.getLink(textBody);
+    	
+        final String htmlContentType = multipart.getBodyPart(1).getContentType();
+        
+        assertEquals("text/html; charset=UTF-8", htmlContentType);
+        
+        final String htmlBody = (String) multipart.getBodyPart(1).getContent();
+        final String htmlVerificationUrl = MailUtil.getLink(htmlBody);
+        
+        assertEquals(htmlVerificationUrl, textVerificationUrl);
+
+        return htmlVerificationUrl;
+    }
 }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/BrokerKeyCloakRule.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/BrokerKeyCloakRule.java
index deb2611..438ab93 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/BrokerKeyCloakRule.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/BrokerKeyCloakRule.java
@@ -20,6 +20,7 @@ package org.keycloak.testsuite.broker;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.services.managers.RealmManager;
+import org.keycloak.testsuite.adapter.CustomerDatabaseServlet;
 import org.keycloak.testsuite.broker.util.UserSessionStatusServlet;
 import org.keycloak.testsuite.rule.AbstractKeycloakRule;
 
@@ -34,8 +35,16 @@ public class BrokerKeyCloakRule extends AbstractKeycloakRule {
     protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) {
         server.importRealm(getClass().getResourceAsStream("/broker-test/test-realm-with-broker.json"));
         URL url = getClass().getResource("/broker-test/test-app-keycloak.json");
-        deployApplication("test-app", "/test-app", UserSessionStatusServlet.class, url.getPath(), "manager");
-        deployApplication("test-app-allowed-providers", "/test-app-allowed-providers", UserSessionStatusServlet.class, url.getPath(), "manager");
+
+        createApplicationDeployment()
+                .name("test-app").contextPath("/test-app")
+                .servletClass(UserSessionStatusServlet.class).adapterConfigPath(url.getPath())
+                .role("manager").deployApplication();
+
+        createApplicationDeployment()
+                .name("test-app-allowed-providers").contextPath("/test-app-allowed-providers")
+                .servletClass(UserSessionStatusServlet.class).adapterConfigPath(url.getPath())
+                .role("manager").deployApplication();
     }
 
     @Override
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/ImportIdentityProviderTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/ImportIdentityProviderTest.java
index 9b1f643..b2e3605 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/ImportIdentityProviderTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/ImportIdentityProviderTest.java
@@ -33,6 +33,7 @@ import org.keycloak.broker.saml.SAMLIdentityProviderFactory;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.IdentityProviderModel;
 import org.keycloak.models.RealmModel;
+import org.keycloak.representations.idm.IdentityProviderRepresentation;
 import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.social.facebook.FacebookIdentityProvider;
 import org.keycloak.social.facebook.FacebookIdentityProviderFactory;
@@ -80,7 +81,8 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
 
         identityProviderModel.getConfig().put("config-added", "value-added");
         identityProviderModel.setEnabled(false);
-        identityProviderModel.setUpdateProfileFirstLogin(false);
+        identityProviderModel.setUpdateProfileFirstLoginMode(IdentityProviderRepresentation.UPFLM_OFF);
+        identityProviderModel.setTrustEmail(true);
         identityProviderModel.setStoreToken(true);
         identityProviderModel.setAuthenticateByDefault(true);
 
@@ -94,13 +96,15 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
 
         assertEquals("value-added", identityProviderModel.getConfig().get("config-added"));
         assertFalse(identityProviderModel.isEnabled());
-        assertFalse(identityProviderModel.isUpdateProfileFirstLogin());
+        assertEquals(IdentityProviderRepresentation.UPFLM_OFF, identityProviderModel.getUpdateProfileFirstLoginMode());
+        assertTrue(identityProviderModel.isTrustEmail());
         assertTrue(identityProviderModel.isStoreToken());
         assertTrue(identityProviderModel.isAuthenticateByDefault());
 
         identityProviderModel.getConfig().remove("config-added");
         identityProviderModel.setEnabled(true);
-        identityProviderModel.setUpdateProfileFirstLogin(true);
+        identityProviderModel.setUpdateProfileFirstLoginMode(IdentityProviderRepresentation.UPFLM_MISSING);
+        identityProviderModel.setTrustEmail(false);
         identityProviderModel.setAuthenticateByDefault(false);
 
         realm.updateIdentityProvider(identityProviderModel);
@@ -112,7 +116,8 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
 
         assertFalse(identityProviderModel.getConfig().containsKey("config-added"));
         assertTrue(identityProviderModel.isEnabled());
-        assertTrue(identityProviderModel.isUpdateProfileFirstLogin());
+        assertEquals(IdentityProviderRepresentation.UPFLM_MISSING, identityProviderModel.getUpdateProfileFirstLoginMode());
+        assertFalse(identityProviderModel.isTrustEmail());
         assertFalse(identityProviderModel.isAuthenticateByDefault());
         this.realmManager.removeRealm(realm);
     }
@@ -160,7 +165,8 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
         assertEquals("model-google", config.getAlias());
         assertEquals(GoogleIdentityProviderFactory.PROVIDER_ID, config.getProviderId());
         assertEquals(true, config.isEnabled());
-        assertEquals(true, config.isUpdateProfileFirstLogin());
+        assertEquals(IdentityProviderRepresentation.UPFLM_ON, config.getUpdateProfileFirstLoginMode());
+        assertEquals(true, config.isTrustEmail());
         assertEquals(false, config.isAuthenticateByDefault());
         assertEquals(true, config.isStoreToken());
         assertEquals("clientId", config.getClientId());
@@ -178,8 +184,9 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
         assertEquals("model-saml-signed-idp", config.getAlias());
         assertEquals(SAMLIdentityProviderFactory.PROVIDER_ID, config.getProviderId());
         assertEquals(true, config.isEnabled());
-        assertEquals(true, config.isUpdateProfileFirstLogin());
+        assertEquals(IdentityProviderRepresentation.UPFLM_ON, config.getUpdateProfileFirstLoginMode());
         assertEquals(false, config.isAuthenticateByDefault());
+        assertEquals(false, config.isTrustEmail());
         assertEquals(false, config.isStoreToken());
         assertEquals("http://localhost:8082/auth/realms/realm-with-saml-identity-provider/protocol/saml", config.getSingleSignOnServiceUrl());
         assertEquals("urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", config.getNameIDPolicyFormat());
@@ -198,7 +205,8 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
         assertEquals("model-oidc-idp", config.getAlias());
         assertEquals(OIDCIdentityProviderFactory.PROVIDER_ID, config.getProviderId());
         assertEquals(false, config.isEnabled());
-        assertEquals(false, config.isUpdateProfileFirstLogin());
+        assertEquals(IdentityProviderRepresentation.UPFLM_OFF, config.getUpdateProfileFirstLoginMode());
+        assertEquals(false, config.isTrustEmail());
         assertEquals(false, config.isAuthenticateByDefault());
         assertEquals(false, config.isStoreToken());
         assertEquals("clientId", config.getClientId());
@@ -212,7 +220,8 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
         assertEquals("model-facebook", config.getAlias());
         assertEquals(FacebookIdentityProviderFactory.PROVIDER_ID, config.getProviderId());
         assertEquals(true, config.isEnabled());
-        assertEquals(true, config.isUpdateProfileFirstLogin());
+        assertEquals(IdentityProviderRepresentation.UPFLM_OFF, config.getUpdateProfileFirstLoginMode());
+        assertEquals(false, config.isTrustEmail());
         assertEquals(false, config.isAuthenticateByDefault());
         assertEquals(false, config.isStoreToken());
         assertEquals("clientId", config.getClientId());
@@ -229,7 +238,8 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
         assertEquals("model-github", config.getAlias());
         assertEquals(GitHubIdentityProviderFactory.PROVIDER_ID, config.getProviderId());
         assertEquals(true, config.isEnabled());
-        assertEquals(true, config.isUpdateProfileFirstLogin());
+        assertEquals(IdentityProviderRepresentation.UPFLM_ON, config.getUpdateProfileFirstLoginMode());
+        assertEquals(false, config.isTrustEmail());
         assertEquals(false, config.isAuthenticateByDefault());
         assertEquals(false, config.isStoreToken());
         assertEquals("clientId", config.getClientId());
@@ -246,7 +256,8 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
         assertEquals("model-linkedin", config.getAlias());
       assertEquals(LinkedInIdentityProviderFactory.PROVIDER_ID, config.getProviderId());
       assertEquals(true, config.isEnabled());
-      assertEquals(true, config.isUpdateProfileFirstLogin());
+        assertEquals(IdentityProviderRepresentation.UPFLM_MISSING, config.getUpdateProfileFirstLoginMode());
+        assertEquals(false, config.isTrustEmail());
       assertEquals(false, config.isAuthenticateByDefault());
       assertEquals(false, config.isStoreToken());
       assertEquals("clientId", config.getClientId());
@@ -263,7 +274,8 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
         assertEquals("model-stackoverflow", config.getAlias());
         assertEquals(StackoverflowIdentityProviderFactory.PROVIDER_ID, config.getProviderId());
         assertEquals(true, config.isEnabled());
-        assertEquals(true, config.isUpdateProfileFirstLogin());
+        assertEquals(IdentityProviderRepresentation.UPFLM_OFF, config.getUpdateProfileFirstLoginMode());
+        assertEquals(false, config.isTrustEmail());
         assertEquals(false, config.isAuthenticateByDefault());
         assertEquals(false, config.isStoreToken());
         assertEquals("clientId", config.getClientId());
@@ -281,7 +293,8 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
         assertEquals("model-twitter", config.getAlias());
         assertEquals(TwitterIdentityProviderFactory.PROVIDER_ID, config.getProviderId());
         assertEquals(true, config.isEnabled());
-        assertEquals(true, config.isUpdateProfileFirstLogin());
+        assertEquals(IdentityProviderRepresentation.UPFLM_OFF, config.getUpdateProfileFirstLoginMode());
+        assertEquals(false, config.isTrustEmail());
         assertEquals(false, config.isAuthenticateByDefault());
         assertEquals(true, config.isStoreToken());
         assertEquals("clientId", config.getClientId());
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/SAMLKeyCloakServerBrokerBasicTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/SAMLKeyCloakServerBrokerBasicTest.java
index 46bfa3d..c0ffd00 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/SAMLKeyCloakServerBrokerBasicTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/SAMLKeyCloakServerBrokerBasicTest.java
@@ -6,6 +6,7 @@ import org.keycloak.models.IdentityProviderModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserModel;
+import org.keycloak.representations.idm.IdentityProviderRepresentation;
 import org.keycloak.services.managers.RealmManager;
 import org.keycloak.testsuite.rule.AbstractKeycloakRule;
 import org.keycloak.testsuite.KeycloakServer;
@@ -50,9 +51,9 @@ public class SAMLKeyCloakServerBrokerBasicTest extends AbstractIdentityProviderT
     }
 
     @Override
-    protected void doAssertFederatedUser(UserModel federatedUser, IdentityProviderModel identityProviderModel, String expectedEmail) {
-        if (identityProviderModel.isUpdateProfileFirstLogin()) {
-            super.doAssertFederatedUser(federatedUser, identityProviderModel, expectedEmail);
+    protected void doAssertFederatedUser(UserModel federatedUser, IdentityProviderModel identityProviderModel, String expectedEmail, boolean isProfileUpdateExpected) {
+        if (isProfileUpdateExpected) {
+            super.doAssertFederatedUser(federatedUser, identityProviderModel, expectedEmail, isProfileUpdateExpected);
         } else {
             if (expectedEmail == null) {
                 // Need to handle differences for various databases (like Oracle)
@@ -114,4 +115,9 @@ public class SAMLKeyCloakServerBrokerBasicTest extends AbstractIdentityProviderT
     public void testSuccessfulAuthenticationWithoutUpdateProfile_newUser_emailAsUsername() {
         super.testSuccessfulAuthenticationWithoutUpdateProfile_newUser_emailAsUsername();
     }
+
+    @Test
+    public void testSuccessfulAuthenticationUpdateProfileOnMissing_nothingMissing() {
+        // skip this test as this provider do not return name and surname so something is missing always
+    }
 }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/SAMLKeyCloakServerBrokerWithSignatureTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/SAMLKeyCloakServerBrokerWithSignatureTest.java
index 821fc0e..34c10d5 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/SAMLKeyCloakServerBrokerWithSignatureTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/SAMLKeyCloakServerBrokerWithSignatureTest.java
@@ -6,6 +6,7 @@ import org.keycloak.models.IdentityProviderModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserModel;
+import org.keycloak.representations.idm.IdentityProviderRepresentation;
 import org.keycloak.services.managers.RealmManager;
 import org.keycloak.testsuite.rule.AbstractKeycloakRule;
 import org.keycloak.testsuite.KeycloakServer;
@@ -50,9 +51,9 @@ public class SAMLKeyCloakServerBrokerWithSignatureTest extends AbstractIdentityP
     }
 
     @Override
-    protected void doAssertFederatedUser(UserModel federatedUser, IdentityProviderModel identityProviderModel, String expectedEmail) {
-        if (identityProviderModel.isUpdateProfileFirstLogin()) {
-            super.doAssertFederatedUser(federatedUser, identityProviderModel, expectedEmail);
+    protected void doAssertFederatedUser(UserModel federatedUser, IdentityProviderModel identityProviderModel, String expectedEmail, boolean isProfileUpdateExpected) {
+        if (isProfileUpdateExpected) {
+            super.doAssertFederatedUser(federatedUser, identityProviderModel, expectedEmail, isProfileUpdateExpected);
         } else {
             if (expectedEmail == null) {
                 // Need to handle differences for various databases (like Oracle)
@@ -102,4 +103,9 @@ public class SAMLKeyCloakServerBrokerWithSignatureTest extends AbstractIdentityP
     public void testAccountManagementLinkIdentity() {
         super.testAccountManagementLinkIdentity();
     }
+
+    @Test
+    public void testSuccessfulAuthenticationUpdateProfileOnMissing_nothingMissing() {
+        // skip this test as this provider do not return name and surname so something is missing always
+    }
 }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/FederationProvidersIntegrationTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/FederationProvidersIntegrationTest.java
index 2a2113d..c384651 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/FederationProvidersIntegrationTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/FederationProvidersIntegrationTest.java
@@ -11,13 +11,10 @@ import org.junit.runners.MethodSorters;
 import org.keycloak.OAuth2Constants;
 import org.keycloak.federation.ldap.LDAPFederationProvider;
 import org.keycloak.federation.ldap.LDAPFederationProviderFactory;
-import org.keycloak.federation.ldap.LDAPUtils;
 import org.keycloak.federation.ldap.idm.model.LDAPObject;
 import org.keycloak.federation.ldap.mappers.FullNameLDAPFederationMapper;
 import org.keycloak.federation.ldap.mappers.FullNameLDAPFederationMapperFactory;
 import org.keycloak.federation.ldap.mappers.UserAttributeLDAPFederationMapper;
-import org.keycloak.federation.ldap.mappers.UserAttributeLDAPFederationMapperFactory;
-import org.keycloak.models.ClientModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.LDAPConstants;
 import org.keycloak.models.ModelReadOnlyException;
@@ -42,9 +39,7 @@ import org.keycloak.testsuite.rule.WebResource;
 import org.keycloak.testsuite.rule.WebRule;
 import org.openqa.selenium.WebDriver;
 
-import java.util.List;
 import java.util.Map;
-import java.util.Set;
 
 /**
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@@ -71,7 +66,7 @@ public class FederationProvidersIntegrationTest {
 
             // Delete all LDAP users and add some new for testing
             LDAPFederationProvider ldapFedProvider = FederationTestUtils.getLdapProvider(session, ldapModel);
-            LDAPUtils.removeAllUsers(ldapFedProvider, appRealm);
+            FederationTestUtils.removeAllLDAPUsers(ldapFedProvider, appRealm);
 
             LDAPObject john = FederationTestUtils.addLDAPUser(ldapFedProvider, appRealm, "johnkeycloak", "John", "Doe", "john@email.org", "1234");
             ldapFedProvider.getLdapIdentityStore().updatePassword(john, "Password1");
@@ -284,15 +279,16 @@ public class FederationProvidersIntegrationTest {
             LDAPFederationProvider ldapFedProvider = FederationTestUtils.getLdapProvider(session, ldapModel);
             FederationTestUtils.addLDAPUser(ldapFedProvider, appRealm, "fullname", "James Dee", "Dee", "fullname@email.org", "4578");
 
-            // add fullname mapper to the provider and remove "firstNameMapper"
+            // add fullname mapper to the provider and remove "firstNameMapper". For this test, we will simply map full name to the LDAP attribute, which was before firstName ( "givenName" on active directory, "cn" on other LDAP servers)
+            firstNameMapper = appRealm.getUserFederationMapperByName(ldapModel.getId(), "first name");
+            String ldapFirstNameAttributeName = firstNameMapper.getConfig().get(UserAttributeLDAPFederationMapper.LDAP_ATTRIBUTE);
+            appRealm.removeUserFederationMapper(firstNameMapper);
+
             UserFederationMapperModel fullNameMapperModel = KeycloakModelUtils.createUserFederationMapperModel("full name", ldapModel.getId(), FullNameLDAPFederationMapperFactory.PROVIDER_ID,
-                    FullNameLDAPFederationMapper.LDAP_FULL_NAME_ATTRIBUTE, LDAPConstants.CN,
+                    FullNameLDAPFederationMapper.LDAP_FULL_NAME_ATTRIBUTE, ldapFirstNameAttributeName,
                     UserAttributeLDAPFederationMapper.READ_ONLY, "false");
             appRealm.addUserFederationMapper(fullNameMapperModel);
 
-            firstNameMapper = appRealm.getUserFederationMapperByName(ldapModel.getId(), "first name");
-            appRealm.removeUserFederationMapper(firstNameMapper);
-
             // Assert user is successfully imported in Keycloak DB now with correct firstName and lastName
             FederationTestUtils.assertUserImported(session.users(), appRealm, "fullname", "James", "Dee", "fullname@email.org", "4578");
         } finally {
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/FederationTestUtils.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/FederationTestUtils.java
index 80bf539..540ae64 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/FederationTestUtils.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/FederationTestUtils.java
@@ -1,10 +1,14 @@
 package org.keycloak.testsuite.federation;
 
+import java.util.List;
+
 import org.junit.Assert;
 import org.keycloak.federation.ldap.LDAPFederationProvider;
 import org.keycloak.federation.ldap.LDAPFederationProviderFactory;
 import org.keycloak.federation.ldap.LDAPUtils;
 import org.keycloak.federation.ldap.idm.model.LDAPObject;
+import org.keycloak.federation.ldap.idm.query.internal.LDAPIdentityQuery;
+import org.keycloak.federation.ldap.idm.store.ldap.LDAPIdentityStore;
 import org.keycloak.federation.ldap.mappers.RoleLDAPFederationMapper;
 import org.keycloak.federation.ldap.mappers.RoleLDAPFederationMapperFactory;
 import org.keycloak.federation.ldap.mappers.UserAttributeLDAPFederationMapper;
@@ -108,8 +112,9 @@ class FederationTestUtils {
             mapperModel.getConfig().put(RoleLDAPFederationMapper.MODE, mode.toString());
             realm.updateUserFederationMapper(mapperModel);
         } else {
+            String baseDn = providerModel.getConfig().get(LDAPConstants.BASE_DN);
             mapperModel = KeycloakModelUtils.createUserFederationMapperModel("realmRolesMapper", providerModel.getId(), RoleLDAPFederationMapperFactory.PROVIDER_ID,
-                    RoleLDAPFederationMapper.ROLES_DN, "ou=RealmRoles,dc=keycloak,dc=org",
+                    RoleLDAPFederationMapper.ROLES_DN, "ou=RealmRoles," + baseDn,
                     RoleLDAPFederationMapper.USE_REALM_ROLES_MAPPING, "true",
                     RoleLDAPFederationMapper.MODE, mode.toString());
             realm.addUserFederationMapper(mapperModel);
@@ -120,12 +125,39 @@ class FederationTestUtils {
             mapperModel.getConfig().put(RoleLDAPFederationMapper.MODE, mode.toString());
             realm.updateUserFederationMapper(mapperModel);
         } else {
+            String baseDn = providerModel.getConfig().get(LDAPConstants.BASE_DN);
             mapperModel = KeycloakModelUtils.createUserFederationMapperModel("financeRolesMapper", providerModel.getId(), RoleLDAPFederationMapperFactory.PROVIDER_ID,
-                    RoleLDAPFederationMapper.ROLES_DN, "ou=FinanceRoles,dc=keycloak,dc=org",
+                    RoleLDAPFederationMapper.ROLES_DN, "ou=FinanceRoles," + baseDn,
                     RoleLDAPFederationMapper.USE_REALM_ROLES_MAPPING, "false",
                     RoleLDAPFederationMapper.CLIENT_ID, "finance",
                     RoleLDAPFederationMapper.MODE, mode.toString());
             realm.addUserFederationMapper(mapperModel);
         }
     }
+
+    public static void removeAllLDAPUsers(LDAPFederationProvider ldapProvider, RealmModel realm) {
+        LDAPIdentityStore ldapStore = ldapProvider.getLdapIdentityStore();
+        LDAPIdentityQuery ldapQuery = LDAPUtils.createQueryForUserSearch(ldapProvider, realm);
+        List<LDAPObject> allUsers = ldapQuery.getResultList();
+
+        for (LDAPObject ldapUser : allUsers) {
+            ldapStore.remove(ldapUser);
+        }
+    }
+
+    public static void removeAllLDAPRoles(KeycloakSession session, RealmModel appRealm, UserFederationProviderModel ldapModel, String mapperName) {
+        UserFederationMapperModel mapperModel = appRealm.getUserFederationMapperByName(ldapModel.getId(), mapperName);
+        LDAPFederationProvider ldapProvider = FederationTestUtils.getLdapProvider(session, ldapModel);
+        LDAPIdentityQuery roleQuery = new RoleLDAPFederationMapper().createRoleQuery(mapperModel, ldapProvider);
+        List<LDAPObject> ldapRoles = roleQuery.getResultList();
+        for (LDAPObject ldapRole : ldapRoles) {
+            ldapProvider.getLdapIdentityStore().remove(ldapRole);
+        }
+    }
+
+    public static void createLDAPRole(KeycloakSession session, RealmModel appRealm, UserFederationProviderModel ldapModel, String mapperName, String roleName) {
+        UserFederationMapperModel mapperModel = appRealm.getUserFederationMapperByName(ldapModel.getId(), mapperName);
+        LDAPFederationProvider ldapProvider = FederationTestUtils.getLdapProvider(session, ldapModel);
+        new RoleLDAPFederationMapper().createLDAPRole(mapperModel, roleName, ldapProvider);
+    }
 }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/KerberosLdapTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/KerberosLdapTest.java
index 8086500..258f54d 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/KerberosLdapTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/KerberosLdapTest.java
@@ -20,6 +20,7 @@ import org.keycloak.models.UserFederationProvider;
 import org.keycloak.models.UserFederationProviderModel;
 import org.keycloak.services.managers.RealmManager;
 import org.keycloak.testsuite.AssertEvents;
+import org.keycloak.testsuite.adapter.CustomerServlet;
 import org.keycloak.testsuite.rule.KerberosRule;
 import org.keycloak.testsuite.rule.KeycloakRule;
 import org.keycloak.testsuite.rule.WebRule;
@@ -42,7 +43,10 @@ public class KerberosLdapTest extends AbstractKerberosTest {
         @Override
         public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
             URL url = getClass().getResource("/kerberos-test/kerberos-app-keycloak.json");
-            keycloakRule.deployApplication("kerberos-portal", "/kerberos-portal", KerberosCredDelegServlet.class, url.getPath(), "user");
+            keycloakRule.createApplicationDeployment()
+                    .name("kerberos-portal").contextPath("/kerberos-portal")
+                    .servletClass(KerberosCredDelegServlet.class).adapterConfigPath(url.getPath())
+                    .role("user").deployApplication();
 
             Map<String,String> ldapConfig = kerberosRule.getConfig();
             ldapModel = appRealm.addUserFederationProvider(LDAPFederationProviderFactory.PROVIDER_NAME, ldapConfig, 0, "kerberos-ldap", -1, -1, 0);
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/KerberosStandaloneTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/KerberosStandaloneTest.java
index 699d85b..749b009 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/KerberosStandaloneTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/KerberosStandaloneTest.java
@@ -42,7 +42,11 @@ public class KerberosStandaloneTest extends AbstractKerberosTest {
         @Override
         public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
             URL url = getClass().getResource("/kerberos-test/kerberos-app-keycloak.json");
-            keycloakRule.deployApplication("kerberos-portal", "/kerberos-portal", KerberosCredDelegServlet.class, url.getPath(), "user");
+            keycloakRule.createApplicationDeployment()
+                    .name("kerberos-portal").contextPath("/kerberos-portal")
+                    .servletClass(KerberosCredDelegServlet.class).adapterConfigPath(url.getPath())
+                    .role("user").deployApplication();
+
 
             Map<String,String> kerberosConfig = kerberosRule.getConfig();
             kerberosModel = appRealm.addUserFederationProvider(KerberosFederationProviderFactory.PROVIDER_NAME, kerberosConfig, 0, "kerberos-standalone", -1, -1, 0);
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/LDAPRoleMappingsTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/LDAPRoleMappingsTest.java
index a389fe5..f8a6944 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/LDAPRoleMappingsTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/LDAPRoleMappingsTest.java
@@ -13,7 +13,6 @@ import org.junit.rules.TestRule;
 import org.junit.runners.MethodSorters;
 import org.keycloak.federation.ldap.LDAPFederationProvider;
 import org.keycloak.federation.ldap.LDAPFederationProviderFactory;
-import org.keycloak.federation.ldap.LDAPUtils;
 import org.keycloak.federation.ldap.idm.model.LDAPObject;
 import org.keycloak.federation.ldap.idm.query.Condition;
 import org.keycloak.federation.ldap.idm.query.QueryParameter;
@@ -34,11 +33,8 @@ import org.keycloak.models.UserFederationProviderModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.services.managers.RealmManager;
 import org.keycloak.testsuite.OAuthClient;
-import org.keycloak.testsuite.pages.AccountPasswordPage;
-import org.keycloak.testsuite.pages.AccountUpdateProfilePage;
 import org.keycloak.testsuite.pages.AppPage;
 import org.keycloak.testsuite.pages.LoginPage;
-import org.keycloak.testsuite.pages.RegisterPage;
 import org.keycloak.testsuite.rule.KeycloakRule;
 import org.keycloak.testsuite.rule.LDAPRule;
 import org.keycloak.testsuite.rule.WebResource;
@@ -67,13 +63,19 @@ public class LDAPRoleMappingsTest {
 
             ldapModel = appRealm.addUserFederationProvider(LDAPFederationProviderFactory.PROVIDER_NAME, ldapConfig, 0, "test-ldap", -1, -1, 0);
 
-            // Delete all LDAP users and add some new for testing
+            // Delete all LDAP users
             LDAPFederationProvider ldapFedProvider = FederationTestUtils.getLdapProvider(session, ldapModel);
-            LDAPUtils.removeAllUsers(ldapFedProvider, appRealm);
+            FederationTestUtils.removeAllLDAPUsers(ldapFedProvider, appRealm);
 
             // Add sample application
             ClientModel finance = appRealm.addClient("finance");
 
+            // Delete all LDAP roles
+            FederationTestUtils.addOrUpdateRoleLDAPMappers(appRealm, ldapModel, RoleLDAPFederationMapper.Mode.LDAP_ONLY);
+            FederationTestUtils.removeAllLDAPRoles(manager.getSession(), appRealm, ldapModel, "realmRolesMapper");
+            FederationTestUtils.removeAllLDAPRoles(manager.getSession(), appRealm, ldapModel, "financeRolesMapper");
+
+            // Add some users for testing
             LDAPObject john = FederationTestUtils.addLDAPUser(ldapFedProvider, appRealm, "johnkeycloak", "John", "Doe", "john@email.org", "1234");
             ldapFedProvider.getLdapIdentityStore().updatePassword(john, "Password1");
 
@@ -83,34 +85,12 @@ public class LDAPRoleMappingsTest {
             LDAPObject rob = FederationTestUtils.addLDAPUser(ldapFedProvider, appRealm, "robkeycloak", "Rob", "Brown", "rob@email.org", "8910");
             ldapFedProvider.getLdapIdentityStore().updatePassword(rob, "Password1");
 
+            // Add some roles for testing
+            FederationTestUtils.createLDAPRole(manager.getSession(), appRealm, ldapModel, "realmRolesMapper", "realmRole1");
+            FederationTestUtils.createLDAPRole(manager.getSession(), appRealm, ldapModel, "realmRolesMapper", "realmRole2");
+            FederationTestUtils.createLDAPRole(manager.getSession(), appRealm, ldapModel, "financeRolesMapper", "financeRole1");
         }
-    }) {
-
-        @Override
-        protected void after() {
-            // Need to cleanup some LDAP objects after the test
-            update(new KeycloakRule.KeycloakSetup() {
-
-                @Override
-                public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
-                    RoleLDAPFederationMapper roleMapper = new RoleLDAPFederationMapper();
-
-                    FederationTestUtils.addOrUpdateRoleLDAPMappers(appRealm, ldapModel, RoleLDAPFederationMapper.Mode.LDAP_ONLY);
-                    UserFederationMapperModel roleMapperModel = appRealm.getUserFederationMapperByName(ldapModel.getId(), "realmRolesMapper");
-                    LDAPFederationProvider ldapProvider = FederationTestUtils.getLdapProvider(session, ldapModel);
-
-                    LDAPObject ldapRole = roleMapper.loadLDAPRoleByName(roleMapperModel, ldapProvider, "realmRole3");
-                    if (ldapRole != null) {
-                        ldapProvider.getLdapIdentityStore().remove(ldapRole);
-                    }
-                }
-
-            });
-
-            super.after();
-        }
-
-    };
+    });
 
     @ClassRule
     public static TestRule chain = RuleChain
@@ -153,7 +133,12 @@ public class LDAPRoleMappingsTest {
             RoleModel realmRole2 = appRealm.getRole("realmRole2");
             mary.grantRole(realmRole2);
 
-            RoleModel realmRole3 = appRealm.addRole("realmRole3");
+            // This role may already exists from previous test (was imported from LDAP), but may not
+            RoleModel realmRole3 = appRealm.getRole("realmRole3");
+            if (realmRole3 == null) {
+                realmRole3 = appRealm.addRole("realmRole3");
+            }
+
             john.grantRole(realmRole3);
             mary.grantRole(realmRole3);
 
@@ -270,12 +255,20 @@ public class LDAPRoleMappingsTest {
             // Delete role mappings directly in LDAP
             deleteRoleMappingsInLDAP(roleMapperModel, roleMapper, ldapProvider, maryLdap, "realmRole1");
             deleteRoleMappingsInLDAP(roleMapperModel, roleMapper, ldapProvider, maryLdap, "realmRole2");
+        } finally {
+            keycloakRule.stopSession(session, false);
+        }
+
+        session = keycloakRule.startSession();
+        try {
+            RealmModel appRealm = session.realms().getRealmByName("test");
+            UserModel mary = session.users().getUserByUsername("marykeycloak", appRealm);
 
             // Assert role mappings is not available
-            maryRoles = mary.getRealmRoleMappings();
-            Assert.assertFalse(maryRoles.contains(realmRole1));
-            Assert.assertFalse(maryRoles.contains(realmRole2));
-            Assert.assertFalse(maryRoles.contains(realmRole3));
+            Set<RoleModel> maryRoles = mary.getRealmRoleMappings();
+            Assert.assertFalse(maryRoles.contains(appRealm.getRole("realmRole1")));
+            Assert.assertFalse(maryRoles.contains(appRealm.getRole("realmRole2")));
+            Assert.assertFalse(maryRoles.contains(appRealm.getRole("realmRole3")));
         } finally {
             keycloakRule.stopSession(session, false);
         }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/SyncProvidersTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/SyncProvidersTest.java
index d92b8f0..bab44c1 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/SyncProvidersTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/SyncProvidersTest.java
@@ -9,9 +9,7 @@ import org.junit.rules.TestRule;
 import org.junit.runners.MethodSorters;
 import org.keycloak.federation.ldap.LDAPFederationProvider;
 import org.keycloak.federation.ldap.LDAPFederationProviderFactory;
-import org.keycloak.federation.ldap.LDAPUtils;
 import org.keycloak.federation.ldap.idm.model.LDAPObject;
-import org.keycloak.models.ClientModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.KeycloakSessionFactory;
 import org.keycloak.models.LDAPConstants;
@@ -60,7 +58,7 @@ public class SyncProvidersTest {
 
             // Delete all LDAP users and add 5 new users for testing
             LDAPFederationProvider ldapFedProvider = FederationTestUtils.getLdapProvider(session, ldapModel);
-            LDAPUtils.removeAllUsers(ldapFedProvider, appRealm);
+            FederationTestUtils.removeAllLDAPUsers(ldapFedProvider, appRealm);
 
             for (int i=1 ; i<=5 ; i++) {
                 LDAPObject ldapUser = FederationTestUtils.addLDAPUser(ldapFedProvider, appRealm, "user" + i, "User" + i + "FN", "User" + i + "LN", "user" + i + "@email.org", "12" + i);
@@ -77,6 +75,11 @@ public class SyncProvidersTest {
             .outerRule(ldapRule)
             .around(keycloakRule);
 
+//    @Test
+//    public void test01runit() throws Exception {
+//        Thread.sleep(10000000);
+//    }
+
     @Test
     public void testLDAPSync() {
         UsersSyncManager usersSyncManager = new UsersSyncManager();
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTest.java
index 644fff3..03da92f 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTest.java
@@ -127,7 +127,10 @@ public class LoginTest {
 
         Assert.assertEquals("Invalid username or password.", loginPage.getError());
 
-        events.expectLogin().user(userId).session((String) null).error("invalid_user_credentials").detail(Details.USERNAME, "login-test").assertEvent();
+        events.expectLogin().user(userId).session((String) null).error("invalid_user_credentials")
+                .detail(Details.USERNAME, "login-test")
+                .removeDetail(Details.CONSENT)
+                .assertEvent();
     }
 
     @Test
@@ -147,7 +150,10 @@ public class LoginTest {
 
             Assert.assertEquals("Invalid username or password.", loginPage.getError());
 
-            events.expectLogin().user(userId).session((String) null).error("invalid_user_credentials").detail(Details.USERNAME, "login-test").assertEvent();
+            events.expectLogin().user(userId).session((String) null).error("invalid_user_credentials")
+                    .detail(Details.USERNAME, "login-test")
+                    .removeDetail(Details.CONSENT)
+                    .assertEvent();
         } finally {
             keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
                 @Override
@@ -175,7 +181,10 @@ public class LoginTest {
 
             Assert.assertEquals("Account is disabled, contact admin.", loginPage.getError());
 
-            events.expectLogin().user(userId).session((String) null).error("user_disabled").detail(Details.USERNAME, "login-test").assertEvent();
+            events.expectLogin().user(userId).session((String) null).error("user_disabled")
+                    .detail(Details.USERNAME, "login-test")
+                    .removeDetail(Details.CONSENT)
+                    .assertEvent();
         } finally {
             keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
                 @Override
@@ -195,7 +204,10 @@ public class LoginTest {
 
         Assert.assertEquals("Invalid username or password.", loginPage.getError());
 
-        events.expectLogin().user((String) null).session((String) null).error("user_not_found").detail(Details.USERNAME, "invalid").assertEvent();
+        events.expectLogin().user((String) null).session((String) null).error("user_not_found")
+                .detail(Details.USERNAME, "invalid")
+                .removeDetail(Details.CONSENT)
+                .assertEvent();
     }
 
     @Test
@@ -413,7 +425,10 @@ public class LoginTest {
         Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
         Assert.assertEquals("access_denied", oauth.getCurrentQuery().get(OAuth2Constants.ERROR));
 
-        events.expectLogin().error("rejected_by_user").user((String) null).session((String) null).removeDetail(Details.USERNAME).assertEvent();
+        events.expectLogin().error("rejected_by_user").user((String) null).session((String) null)
+                .removeDetail(Details.USERNAME)
+                .removeDetail(Details.CONSENT)
+                .assertEvent();
     }
 
     // KEYCLOAK-1037
@@ -427,7 +442,10 @@ public class LoginTest {
             loginPage.assertCurrent();
             Assert.assertEquals("Login timeout. Please login again.", loginPage.getError());
 
-            events.expectLogin().user((String) null).session((String) null).error("expired_code").clearDetails().detail(Details.CODE_ID, AssertEvents.isCodeId()).assertEvent();
+            events.expectLogin().user((String) null).session((String) null).error("expired_code").clearDetails()
+                    .detail(Details.CODE_ID, AssertEvents.isCodeId())
+                    .removeDetail(Details.CONSENT)
+                    .assertEvent();
 
         } finally {
             Time.setOffset(0);
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTotpTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTotpTest.java
index 45795da..8eea530 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTotpTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTotpTest.java
@@ -114,7 +114,9 @@ public class LoginTotpTest {
         loginPage.assertCurrent();
         Assert.assertEquals("Invalid username or password.", loginPage.getError());
 
-        events.expectLogin().error("invalid_user_credentials").session((String) null).assertEvent();
+        events.expectLogin().error("invalid_user_credentials").session((String) null)
+                .removeDetail(Details.CONSENT)
+                .assertEvent();
     }
 
     @Test
@@ -140,7 +142,9 @@ public class LoginTotpTest {
 
         Assert.assertEquals("Invalid username or password.", loginPage.getError());
 
-        events.expectLogin().error("invalid_user_credentials").session((String) null).assertEvent();
+        events.expectLogin().error("invalid_user_credentials").session((String) null)
+                .removeDetail(Details.CONSENT)
+                .assertEvent();
     }
 
     @Test
@@ -159,7 +163,8 @@ public class LoginTotpTest {
             Assert.assertEquals("Invalid username or password.", loginPage.getError());
 
             AssertEvents.ExpectedEvent expectedEvent = events.expectLogin().error("invalid_user_credentials")
-                    .session((String) null);
+                    .session((String) null)
+                    .removeDetail(Details.CONSENT);
             expectedEvent.assertEvent();
         } finally {
             Time.setOffset(0);
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java
index ed94502..26b1f79 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java
@@ -52,7 +52,9 @@ import org.keycloak.util.Time;
 import org.openqa.selenium.WebDriver;
 
 import javax.mail.MessagingException;
+import javax.mail.Multipart;
 import javax.mail.internet.MimeMessage;
+
 import java.io.IOException;
 import java.util.Collections;
 
@@ -146,9 +148,8 @@ public class ResetPasswordTest {
         assertEquals(1, greenMail.getReceivedMessages().length);
 
         MimeMessage message = greenMail.getReceivedMessages()[0];
-
-        String body = (String) message.getContent();
-        String changePasswordUrl = MailUtil.getLink(body);
+        
+        final String changePasswordUrl = getPasswordResetEmailLink(message);
 
         driver.navigate().to(changePasswordUrl.trim());
 
@@ -211,8 +212,7 @@ public class ResetPasswordTest {
 
         MimeMessage message = greenMail.getReceivedMessages()[0];
 
-        String body = (String) message.getContent();
-        String changePasswordUrl = MailUtil.getLink(body);
+        String changePasswordUrl = getPasswordResetEmailLink(message);
 
         driver.navigate().to(changePasswordUrl.trim());
 
@@ -256,8 +256,7 @@ public class ResetPasswordTest {
 
         MimeMessage message = greenMail.getReceivedMessages()[greenMail.getReceivedMessages().length - 1];
 
-        String body = (String) message.getContent();
-        String changePasswordUrl = MailUtil.getLink(body);
+        String changePasswordUrl = getPasswordResetEmailLink(message);
 
         driver.navigate().to(changePasswordUrl.trim());
 
@@ -294,8 +293,7 @@ public class ResetPasswordTest {
 
         MimeMessage message = greenMail.getReceivedMessages()[greenMail.getReceivedMessages().length - 1];
 
-        String body = (String) message.getContent();
-        String changePasswordUrl = MailUtil.getLink(body);
+        String changePasswordUrl = getPasswordResetEmailLink(message);
 
         driver.navigate().to(changePasswordUrl.trim());
 
@@ -364,8 +362,7 @@ public class ResetPasswordTest {
 
             MimeMessage message = greenMail.getReceivedMessages()[0];
 
-            String body = (String) message.getContent();
-            String changePasswordUrl = MailUtil.getLink(body);
+            String changePasswordUrl = getPasswordResetEmailLink(message);
 
             Time.setOffset(350);
 
@@ -513,8 +510,7 @@ public class ResetPasswordTest {
 
         MimeMessage message = greenMail.getReceivedMessages()[0];
 
-        String body = (String) message.getContent();
-        String changePasswordUrl = MailUtil.getLink(body);
+        String changePasswordUrl = getPasswordResetEmailLink(message);
 
         String sessionId = events.expectRequiredAction(EventType.SEND_RESET_PASSWORD).user(userId).detail(Details.USERNAME, "login-test").detail(Details.EMAIL, "login@test.com").assertEvent().getSessionId();
 
@@ -609,8 +605,7 @@ public class ResetPasswordTest {
 
         MimeMessage message = greenMail.getReceivedMessages()[0];
 
-        String body = (String) message.getContent();
-        String changePasswordUrl = MailUtil.getLink(body);
+        String changePasswordUrl = getPasswordResetEmailLink(message);
 
         driver.manage().deleteAllCookies();
 
@@ -629,5 +624,27 @@ public class ResetPasswordTest {
 
         assertTrue(loginPage.isCurrent());
     }
+    
+    private String getPasswordResetEmailLink(MimeMessage message) throws IOException, MessagingException {
+    	Multipart multipart = (Multipart) message.getContent();
+    	
+        final String textContentType = multipart.getBodyPart(0).getContentType();
+        
+        assertEquals("text/plain; charset=UTF-8", textContentType);
+        
+        final String textBody = (String) multipart.getBodyPart(0).getContent();
+        final String textChangePwdUrl = MailUtil.getLink(textBody);
+        
+        final String htmlContentType = multipart.getBodyPart(1).getContentType();
+        
+        assertEquals("text/html; charset=UTF-8", htmlContentType);
+        
+        final String htmlBody = (String) multipart.getBodyPart(1).getContent();
+        final String htmlChangePwdUrl = MailUtil.getLink(htmlBody);
+        
+        assertEquals(htmlChangePwdUrl, textChangePwdUrl);
+
+        return htmlChangePwdUrl;
+    }
 
 }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/ldap/LDAPTestConfiguration.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/ldap/LDAPTestConfiguration.java
index 8b96bc7..e5d8408 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/ldap/LDAPTestConfiguration.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/ldap/LDAPTestConfiguration.java
@@ -28,8 +28,7 @@ public class LDAPTestConfiguration {
 
     static {
         PROP_MAPPINGS.put(LDAPConstants.CONNECTION_URL, "idm.test.ldap.connection.url");
-        PROP_MAPPINGS.put("rolesDnSuffix", "idm.test.ldap.roles.dn.suffix");
-        PROP_MAPPINGS.put("groupDnSuffix", "idm.test.ldap.group.dn.suffix");
+        PROP_MAPPINGS.put(LDAPConstants.BASE_DN, "idm.test.ldap.base.dn");
         PROP_MAPPINGS.put(LDAPConstants.USERS_DN, "idm.test.ldap.user.dn.suffix");
         PROP_MAPPINGS.put(LDAPConstants.BIND_DN, "idm.test.ldap.bind.dn");
         PROP_MAPPINGS.put(LDAPConstants.BIND_CREDENTIAL, "idm.test.ldap.bind.credential");
@@ -38,6 +37,7 @@ public class LDAPTestConfiguration {
         PROP_MAPPINGS.put(LDAPConstants.PAGINATION, "idm.test.ldap.pagination");
         PROP_MAPPINGS.put(LDAPConstants.BATCH_SIZE_FOR_SYNC, "idm.test.ldap.batch.size.for.sync");
         PROP_MAPPINGS.put(LDAPConstants.USERNAME_LDAP_ATTRIBUTE, "idm.test.ldap.username.ldap.attribute");
+        PROP_MAPPINGS.put(LDAPConstants.RDN_LDAP_ATTRIBUTE, "idm.test.ldap.rdn.ldap.attribute");
         PROP_MAPPINGS.put(LDAPConstants.USER_OBJECT_CLASSES, "idm.test.ldap.user.object.classes");
         PROP_MAPPINGS.put(LDAPConstants.USER_ACCOUNT_CONTROLS_AFTER_PASSWORD_UPDATE, "idm.test.ldap.user.account.controls.after.password.update");
         PROP_MAPPINGS.put(LDAPConstants.EDIT_MODE, "idm.test.ldap.edit.mode");
@@ -52,8 +52,7 @@ public class LDAPTestConfiguration {
         PROP_MAPPINGS.put(KerberosConstants.USE_KERBEROS_FOR_PASSWORD_AUTHENTICATION, "idm.test.kerberos.use.kerberos.for.password.authentication");
 
         DEFAULT_VALUES.put(LDAPConstants.CONNECTION_URL, "ldap://localhost:10389");
-        DEFAULT_VALUES.put("rolesDnSuffix", "ou=Roles,dc=keycloak,dc=org");
-        DEFAULT_VALUES.put("groupDnSuffix", "ou=Groups,dc=keycloak,dc=org");
+        DEFAULT_VALUES.put(LDAPConstants.BASE_DN, "dc=keycloak,dc=org");
         DEFAULT_VALUES.put(LDAPConstants.USERS_DN, "ou=People,dc=keycloak,dc=org");
         DEFAULT_VALUES.put(LDAPConstants.BIND_DN, "uid=admin,ou=system");
         DEFAULT_VALUES.put(LDAPConstants.BIND_CREDENTIAL, "secret");
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/MailUtil.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/MailUtil.java
index 9691301..f29ae4e 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/MailUtil.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/MailUtil.java
@@ -8,7 +8,7 @@ import java.util.regex.Pattern;
  */
 public class MailUtil {
 
-    private static Pattern mailPattern = Pattern.compile("http[^\\s]*");
+    private static Pattern mailPattern = Pattern.compile("http[^\\s\"]*");
 
     public static String getLink(String body) {
         Matcher matcher = mailPattern.matcher(body);
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ModelTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ModelTest.java
index 9a4fb5f..7637f1d 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ModelTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ModelTest.java
@@ -21,6 +21,7 @@ public class ModelTest extends AbstractModelTest {
         realm.setRegistrationAllowed(true);
         realm.setRegistrationEmailAsUsername(true);
         realm.setResetPasswordAllowed(true);
+        realm.setEditUsernameAllowed(true);
         realm.setSslRequired(SslRequired.EXTERNAL);
         realm.setVerifyEmail(true);
         realm.setAccessTokenLifespan(1000);
@@ -55,6 +56,7 @@ public class ModelTest extends AbstractModelTest {
         Assert.assertEquals(expected.isRegistrationAllowed(), actual.isRegistrationAllowed());
         Assert.assertEquals(expected.isRegistrationEmailAsUsername(), actual.isRegistrationEmailAsUsername());
         Assert.assertEquals(expected.isResetPasswordAllowed(), actual.isResetPasswordAllowed());
+        Assert.assertEquals(expected.isEditUsernameAllowed(), actual.isEditUsernameAllowed());
         Assert.assertEquals(expected.getSslRequired(), actual.getSslRequired());
         Assert.assertEquals(expected.isVerifyEmail(), actual.isVerifyEmail());
         Assert.assertEquals(expected.getAccessTokenLifespan(), actual.getAccessTokenLifespan());
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserFederationModelTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserFederationModelTest.java
index 51fc446..17e0e31 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserFederationModelTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserFederationModelTest.java
@@ -1,5 +1,9 @@
 package org.keycloak.testsuite.model;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeMap;
@@ -97,6 +101,43 @@ public class UserFederationModelTest extends AbstractModelTest {
         commit();
     }
 
+    @Test
+    public void federationProvidersSetTest() {
+        RealmModel realm = realmManager.createRealm("test-realm");
+        UserFederationProviderModel ldapProvider = new UserFederationProviderModel(null, "ldap", new TreeMap<String, String>(), 1, "my-cool-provider", -1, -1, 0);
+        realm.setUserFederationProviders(Arrays.asList(ldapProvider));
+
+        commit();
+
+        realm = realmManager.getRealmByName("test-realm");
+        List<UserFederationProviderModel> fedProviders = realm.getUserFederationProviders();
+        Assert.assertEquals(1, fedProviders.size());
+        ldapProvider = fedProviders.get(0);
+        Set<UserFederationMapperModel> fedMappers = realmManager.getRealmByName("test-realm").getUserFederationMappersByFederationProvider(ldapProvider.getId());
+
+        UserFederationProviderModel dummyProvider = new UserFederationProviderModel(null, "dummy", new TreeMap<String, String>(), 1, "my-cool-provider", -1, -1, 0);
+        try {
+            realm.setUserFederationProviders(Arrays.asList(ldapProvider, dummyProvider));
+            commit();
+            Assert.fail("Don't expect to end here");
+        } catch (ModelDuplicateException expected) {
+        }
+
+        dummyProvider.setDisplayName("my-cool-provider2");
+        realm.setUserFederationProviders(Arrays.asList(ldapProvider, dummyProvider));
+
+        commit();
+
+        realm = realmManager.getRealmByName("test-realm");
+        Assert.assertEquals(fedMappers.size(), realm.getUserFederationMappersByFederationProvider(ldapProvider.getId()).size());
+        realm.setUserFederationProviders(new ArrayList<UserFederationProviderModel>());
+
+        commit();
+
+        realm = realmManager.getRealmByName("test-realm");
+        Assert.assertTrue(realm.getUserFederationMappersByFederationProvider(ldapProvider.getId()).isEmpty());
+    }
+
     private UserFederationMapperModel createMapper(String name, String fedProviderId, String... config) {
         UserFederationMapperModel mapperModel = new UserFederationMapperModel();
         mapperModel.setName(name);
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AuthorizationCodeTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AuthorizationCodeTest.java
index 0a70da0..784318f 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AuthorizationCodeTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AuthorizationCodeTest.java
@@ -141,6 +141,7 @@ public class AuthorizationCodeTest {
 
         events.expectLogin().error("rejected_by_user").user((String) null).session((String) null)
                 .removeDetail(Details.USERNAME)
+                .removeDetail(Details.CONSENT)
                 .detail(Details.REDIRECT_URI, "http://localhost:8081/auth/realms/test/protocol/openid-connect/oauth/oob")
                 .assertEvent().getDetails().get(Details.CODE_ID);
 
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OAuthDanceClientSessionExtensionTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OAuthDanceClientSessionExtensionTest.java
new file mode 100644
index 0000000..f097892
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OAuthDanceClientSessionExtensionTest.java
@@ -0,0 +1,71 @@
+package org.keycloak.testsuite.oauth;
+
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.keycloak.OAuth2Constants;
+import org.keycloak.events.Details;
+import org.keycloak.events.Event;
+import org.keycloak.testsuite.AssertEvents;
+import org.keycloak.testsuite.OAuthClient;
+import org.keycloak.testsuite.rule.KeycloakRule;
+import org.keycloak.testsuite.rule.WebResource;
+import org.keycloak.testsuite.rule.WebRule;
+
+/**
+ * @author Sebastian Rose, AOE on 02.06.15.
+ */
+public class OAuthDanceClientSessionExtensionTest {
+
+    @ClassRule
+    public static KeycloakRule keycloakRule = new KeycloakRule();
+
+    @Rule
+    public WebRule webRule = new WebRule(this);
+
+    @WebResource
+    protected OAuthClient oauth;
+
+    @Rule
+    public AssertEvents events = new AssertEvents(keycloakRule);
+
+    @Test
+    public void doOauthDanceWithClientSessionStateAndHost() throws Exception {
+        oauth.doLogin("test-user@localhost", "password");
+
+        Event loginEvent = events.expectLogin().assertEvent();
+
+        String sessionId = loginEvent.getSessionId();
+        String codeId = loginEvent.getDetails().get(Details.CODE_ID);
+
+        String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
+
+        String clientSessionState = "1234";
+        String clientSessionHost = "test-client-host";
+
+        OAuthClient.AccessTokenResponse tokenResponse = oauth.clientSessionState(clientSessionState)
+                                                             .clientSessionHost(clientSessionHost)
+                                                             .doAccessTokenRequest(code, "password");
+
+        String refreshTokenString = tokenResponse.getRefreshToken();
+
+        Event tokenEvent = events.expectCodeToToken(codeId, sessionId)
+                                 .detail(Details.CLIENT_SESSION_STATE, clientSessionState)
+                                 .detail(Details.CLIENT_SESSION_HOST, clientSessionHost)
+                                 .assertEvent();
+
+
+        String updatedClientSessionState = "5678";
+
+        oauth.clientSessionState(updatedClientSessionState)
+             .clientSessionHost(clientSessionHost)
+             .doRefreshTokenRequest(refreshTokenString, "password");
+
+        events.expectRefresh(tokenEvent.getDetails().get(Details.REFRESH_TOKEN_ID), sessionId)
+              .detail(Details.CLIENT_SESSION_STATE, updatedClientSessionState)
+              .detail(Details.CLIENT_SESSION_HOST, clientSessionHost)
+              .assertEvent();
+
+    }
+
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OAuthGrantTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OAuthGrantTest.java
index 939231f..bfff4bd 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OAuthGrantTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OAuthGrantTest.java
@@ -36,7 +36,6 @@ import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.protocol.oidc.OIDCLoginProtocol;
-import org.keycloak.protocol.oidc.OIDCLoginProtocolFactory;
 import org.keycloak.protocol.oidc.mappers.UserSessionNoteMapper;
 import org.keycloak.representations.AccessToken;
 import org.keycloak.services.managers.RealmManager;
@@ -51,7 +50,6 @@ import org.keycloak.testsuite.rule.WebResource;
 import org.keycloak.testsuite.rule.WebRule;
 import org.openqa.selenium.WebDriver;
 
-import java.io.IOException;
 import java.util.Map;
 
 import static org.junit.Assert.assertEquals;
@@ -104,7 +102,10 @@ public class OAuthGrantTest {
 
         Assert.assertTrue(oauth.getCurrentQuery().containsKey(OAuth2Constants.CODE));
 
-        Event loginEvent = events.expectLogin().client("third-party").assertEvent();
+        Event loginEvent = events.expectLogin()
+                .client("third-party")
+                .detail(Details.CONSENT, Details.CONSENT_VALUE_CONSENT_GRANTED)
+                .assertEvent();
         String codeId = loginEvent.getDetails().get(Details.CODE_ID);
         String sessionId = loginEvent.getSessionId();
 
@@ -147,7 +148,11 @@ public class OAuthGrantTest {
         Assert.assertTrue(oauth.getCurrentQuery().containsKey(OAuth2Constants.ERROR));
         assertEquals("access_denied", oauth.getCurrentQuery().get(OAuth2Constants.ERROR));
 
-        events.expectLogin().client("third-party").error("rejected_by_user").assertEvent();
+        events.expectLogin()
+                .client("third-party")
+                .error("rejected_by_user")
+                .removeDetail(Details.CONSENT)
+                .assertEvent();
     }
 
     @Test
@@ -159,7 +164,10 @@ public class OAuthGrantTest {
         grantPage.assertCurrent();
         grantPage.accept();
 
-        events.expectLogin().client("third-party").assertEvent();
+        events.expectLogin()
+                .client("third-party")
+                .detail(Details.CONSENT, Details.CONSENT_VALUE_CONSENT_GRANTED)
+                .assertEvent();
 
         // Assert permissions granted on Account mgmt. applications page
         accountAppsPage.open();
@@ -172,7 +180,11 @@ public class OAuthGrantTest {
         // Open login form and assert grantPage not shown
         oauth.openLoginForm();
         appPage.assertCurrent();
-        events.expectLogin().detail(Details.AUTH_METHOD, "sso").removeDetail(Details.USERNAME).client("third-party").assertEvent();
+        events.expectLogin()
+                .detail(Details.AUTH_METHOD, "sso")
+                .detail(Details.CONSENT, Details.CONSENT_VALUE_PERSISTED_CONSENT)
+                .removeDetail(Details.USERNAME)
+                .client("third-party").assertEvent();
 
         // Revoke grant in account mgmt.
         accountAppsPage.open();
@@ -219,7 +231,10 @@ public class OAuthGrantTest {
         // Confirm grant page
         grantPage.assertCurrent();
         grantPage.accept();
-        events.expectLogin().client("third-party").assertEvent();
+        events.expectLogin()
+                .client("third-party")
+                .detail(Details.CONSENT, Details.CONSENT_VALUE_CONSENT_GRANTED)
+                .assertEvent();
 
         // Assert new role and protocol mapper not in account mgmt.
         accountAppsPage.open();
@@ -235,7 +250,10 @@ public class OAuthGrantTest {
         Assert.assertTrue(driver.getPageSource().contains("new-role"));
         Assert.assertTrue(driver.getPageSource().contains(KerberosConstants.GSS_DELEGATION_CREDENTIAL_DISPLAY_NAME));
         grantPage.accept();
-        events.expectLogin().client("third-party").assertEvent();
+        events.expectLogin()
+                .client("third-party")
+                .detail(Details.CONSENT, Details.CONSENT_VALUE_CONSENT_GRANTED)
+                .assertEvent();
 
         // Go to account mgmt. Everything is granted now
         accountAppsPage.open();
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/ResourceOwnerPasswordCredentialsGrantTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/ResourceOwnerPasswordCredentialsGrantTest.java
index 90a88e2..23d2e5e 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/ResourceOwnerPasswordCredentialsGrantTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/ResourceOwnerPasswordCredentialsGrantTest.java
@@ -1,6 +1,10 @@
 package org.keycloak.testsuite.oauth;
 
 import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.DefaultHttpClient;
 import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
@@ -33,7 +37,6 @@ public class ResourceOwnerPasswordCredentialsGrantTest {
         public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
             ClientModel app = appRealm.addClient("resource-owner");
             app.setSecret("secret");
-            appRealm.setPasswordCredentialGrantAllowed(true);
 
             UserModel user = session.users().addUser(appRealm, "direct-login");
             user.setEmail("direct-login@localhost");
@@ -90,6 +93,7 @@ public class ResourceOwnerPasswordCredentialsGrantTest {
                 .detail(Details.USERNAME, login)
                 .removeDetail(Details.CODE_ID)
                 .removeDetail(Details.REDIRECT_URI)
+                .removeDetail(Details.CONSENT)
                 .assertEvent();
 
         assertEquals(accessToken.getSessionState(), refreshToken.getSessionState());
@@ -106,33 +110,6 @@ public class ResourceOwnerPasswordCredentialsGrantTest {
     }
 
     @Test
-    public void grantAccessTokenNotEnabled() throws Exception {
-        try {
-            keycloakRule.update(new KeycloakRule.KeycloakSetup() {
-                @Override
-                public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
-                    appRealm.setPasswordCredentialGrantAllowed(false);
-                }
-            });
-
-            oauth.clientId("resource-owner");
-
-            OAuthClient.AccessTokenResponse response = oauth.doGrantAccessTokenRequest("secret", "test-user@localhost", "password");
-
-            assertEquals(403, response.getStatusCode());
-            assertEquals("not_enabled", response.getError());
-
-        } finally {
-            keycloakRule.update(new KeycloakRule.KeycloakSetup() {
-                @Override
-                public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
-                    appRealm.setPasswordCredentialGrantAllowed(true);
-                }
-            });
-        }
-    }
-
-    @Test
     public void grantAccessTokenLogout() throws Exception {
         oauth.clientId("resource-owner");
 
@@ -152,6 +129,7 @@ public class ResourceOwnerPasswordCredentialsGrantTest {
                 .detail(Details.REFRESH_TOKEN_ID, refreshToken.getId())
                 .removeDetail(Details.CODE_ID)
                 .removeDetail(Details.REDIRECT_URI)
+                .removeDetail(Details.CONSENT)
                 .assertEvent();
 
         HttpResponse logoutResponse = oauth.doLogout(response.getRefreshToken(), "secret");
@@ -204,6 +182,7 @@ public class ResourceOwnerPasswordCredentialsGrantTest {
                 .detail(Details.RESPONSE_TYPE, "token")
                 .removeDetail(Details.CODE_ID)
                 .removeDetail(Details.REDIRECT_URI)
+                .removeDetail(Details.CONSENT)
                 .error(Errors.INVALID_USER_CREDENTIALS)
                 .assertEvent();
     }
@@ -227,8 +206,27 @@ public class ResourceOwnerPasswordCredentialsGrantTest {
                 .detail(Details.USERNAME, "invalid")
                 .removeDetail(Details.CODE_ID)
                 .removeDetail(Details.REDIRECT_URI)
+                .removeDetail(Details.CONSENT)
                 .error(Errors.INVALID_USER_CREDENTIALS)
                 .assertEvent();
     }
 
+    @Test
+    public void grantAccessTokenMissingGrantType() throws Exception {
+        oauth.clientId("resource-owner");
+
+        DefaultHttpClient client = new DefaultHttpClient();
+        try {
+            HttpPost post = new HttpPost(oauth.getResourceOwnerPasswordCredentialGrantUrl());
+            OAuthClient.AccessTokenResponse response = new OAuthClient.AccessTokenResponse(client.execute(post));
+
+            assertEquals(400, response.getStatusCode());
+
+            assertEquals("invalid_request", response.getError());
+            assertEquals("Missing form parameter: grant_type", response.getErrorDescription());
+        } finally {
+            client.close();
+        }
+    }
+
 }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/OAuthClient.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/OAuthClient.java
index 3c81b8a..2ad8e1b 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/OAuthClient.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/OAuthClient.java
@@ -28,6 +28,7 @@ import org.apache.http.client.HttpClient;
 import org.apache.http.client.entity.UrlEncodedFormEntity;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.client.utils.URLEncodedUtils;
+import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.impl.client.DefaultHttpClient;
 import org.apache.http.message.BasicNameValuePair;
 import org.json.JSONObject;
@@ -35,6 +36,7 @@ import org.junit.Assert;
 import org.keycloak.OAuth2Constants;
 import org.keycloak.RSATokenVerifier;
 import org.keycloak.VerificationException;
+import org.keycloak.constants.AdapterConstants;
 import org.keycloak.freemarker.LocaleHelper;
 import org.keycloak.jose.jws.JWSInput;
 import org.keycloak.jose.jws.crypto.RSAProvider;
@@ -78,6 +80,10 @@ public class OAuthClient {
 
     private PublicKey realmPublicKey;
 
+    private String clientSessionState;
+
+    private String clientSessionHost;
+
     public OAuthClient(WebDriver driver) {
         this.driver = driver;
 
@@ -108,121 +114,164 @@ public class OAuthClient {
     }
 
     public AccessTokenResponse doAccessTokenRequest(String code, String password) {
-        HttpClient client = new DefaultHttpClient();
-        HttpPost post = new HttpPost(getAccessTokenUrl());
+        CloseableHttpClient client = new DefaultHttpClient();
+        try {
+            HttpPost post = new HttpPost(getAccessTokenUrl());
 
-        List<NameValuePair> parameters = new LinkedList<NameValuePair>();
-        parameters.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, OAuth2Constants.AUTHORIZATION_CODE));
+            List<NameValuePair> parameters = new LinkedList<NameValuePair>();
+            parameters.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, OAuth2Constants.AUTHORIZATION_CODE));
 
-        if (code != null) {
-            parameters.add(new BasicNameValuePair(OAuth2Constants.CODE, code));
-        }
-        if (redirectUri != null) {
-            parameters.add(new BasicNameValuePair(OAuth2Constants.REDIRECT_URI, redirectUri));
-        }
-        if (clientId != null && password != null) {
-            String authorization = BasicAuthHelper.createHeader(clientId, password);
-            post.setHeader("Authorization", authorization);
-        }
-        else if (clientId != null) {
-            parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ID, clientId));
-        }
+            if (code != null) {
+                parameters.add(new BasicNameValuePair(OAuth2Constants.CODE, code));
+            }
+            if (redirectUri != null) {
+                parameters.add(new BasicNameValuePair(OAuth2Constants.REDIRECT_URI, redirectUri));
+            }
+            if (clientId != null && password != null) {
+                String authorization = BasicAuthHelper.createHeader(clientId, password);
+                post.setHeader("Authorization", authorization);
+            } else if (clientId != null) {
+                parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ID, clientId));
+            }
 
-        UrlEncodedFormEntity formEntity = null;
-        try {
-            formEntity = new UrlEncodedFormEntity(parameters, "UTF-8");
-        } catch (UnsupportedEncodingException e) {
-            throw new RuntimeException(e);
-        }
-        post.setEntity(formEntity);
+            if (clientSessionState != null) {
+                parameters.add(new BasicNameValuePair(AdapterConstants.CLIENT_SESSION_STATE, clientSessionState));
+            }
 
-        try {
-            return new AccessTokenResponse(client.execute(post));
-        } catch (Exception e) {
-            throw new RuntimeException("Failed to retrieve access token", e);
+            if (clientSessionHost != null) {
+                parameters.add(new BasicNameValuePair(AdapterConstants.CLIENT_SESSION_HOST, clientSessionHost));
+            }
+
+            UrlEncodedFormEntity formEntity = null;
+            try {
+                formEntity = new UrlEncodedFormEntity(parameters, "UTF-8");
+            } catch (UnsupportedEncodingException e) {
+                throw new RuntimeException(e);
+            }
+            post.setEntity(formEntity);
+
+            try {
+                return new AccessTokenResponse(client.execute(post));
+            } catch (Exception e) {
+                throw new RuntimeException("Failed to retrieve access token", e);
+            }
+        } finally {
+            closeClient(client);
         }
     }
 
     public AccessTokenResponse doGrantAccessTokenRequest(String clientSecret, String username,  String password) throws Exception {
-        HttpClient client = new DefaultHttpClient();
-        HttpPost post = new HttpPost(getResourceOwnerPasswordCredentialGrantUrl());
+        CloseableHttpClient client = new DefaultHttpClient();
+        try {
+            HttpPost post = new HttpPost(getResourceOwnerPasswordCredentialGrantUrl());
 
-        String authorization = BasicAuthHelper.createHeader(clientId, clientSecret);
-        post.setHeader("Authorization", authorization);
+            String authorization = BasicAuthHelper.createHeader(clientId, clientSecret);
+            post.setHeader("Authorization", authorization);
 
-        List<NameValuePair> parameters = new LinkedList<NameValuePair>();
-        parameters.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, OAuth2Constants.PASSWORD));
-        parameters.add(new BasicNameValuePair("username", username));
-        parameters.add(new BasicNameValuePair("password", password));
+            List<NameValuePair> parameters = new LinkedList<NameValuePair>();
+            parameters.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, OAuth2Constants.PASSWORD));
+            parameters.add(new BasicNameValuePair("username", username));
+            parameters.add(new BasicNameValuePair("password", password));
 
-        UrlEncodedFormEntity formEntity;
-        try {
-            formEntity = new UrlEncodedFormEntity(parameters, "UTF-8");
-        } catch (UnsupportedEncodingException e) {
-            throw new RuntimeException(e);
-        }
-        post.setEntity(formEntity);
+            if (clientSessionState != null) {
+                parameters.add(new BasicNameValuePair(AdapterConstants.CLIENT_SESSION_STATE, clientSessionState));
+            }
+            if (clientSessionHost != null) {
+                parameters.add(new BasicNameValuePair(AdapterConstants.CLIENT_SESSION_HOST, clientSessionHost));
+            }
 
-        return new AccessTokenResponse(client.execute(post));
+            UrlEncodedFormEntity formEntity;
+            try {
+                formEntity = new UrlEncodedFormEntity(parameters, "UTF-8");
+            } catch (UnsupportedEncodingException e) {
+                throw new RuntimeException(e);
+            }
+            post.setEntity(formEntity);
+
+            return new AccessTokenResponse(client.execute(post));
+        } finally {
+            closeClient(client);
+        }
     }
 
     public HttpResponse doLogout(String refreshToken, String clientSecret) throws IOException {
-        HttpClient client = new DefaultHttpClient();
-        HttpPost post = new HttpPost(getLogoutUrl(null, null));
+        CloseableHttpClient client = new DefaultHttpClient();
+        try {
+            HttpPost post = new HttpPost(getLogoutUrl(null, null));
 
-        List<NameValuePair> parameters = new LinkedList<NameValuePair>();
-        if (refreshToken != null) {
-            parameters.add(new BasicNameValuePair(OAuth2Constants.REFRESH_TOKEN, refreshToken));
-        }
-        if (clientId != null && clientSecret != null) {
-            String authorization = BasicAuthHelper.createHeader(clientId, clientSecret);
-            post.setHeader("Authorization", authorization);
-        }
-        else if (clientId != null) {
-            parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ID, clientId));
-        }
+            List<NameValuePair> parameters = new LinkedList<NameValuePair>();
+            if (refreshToken != null) {
+                parameters.add(new BasicNameValuePair(OAuth2Constants.REFRESH_TOKEN, refreshToken));
+            }
+            if (clientId != null && clientSecret != null) {
+                String authorization = BasicAuthHelper.createHeader(clientId, clientSecret);
+                post.setHeader("Authorization", authorization);
+            } else if (clientId != null) {
+                parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ID, clientId));
+            }
 
-        UrlEncodedFormEntity formEntity;
-        try {
-            formEntity = new UrlEncodedFormEntity(parameters, "UTF-8");
-        } catch (UnsupportedEncodingException e) {
-            throw new RuntimeException(e);
-        }
-        post.setEntity(formEntity);
+            UrlEncodedFormEntity formEntity;
+            try {
+                formEntity = new UrlEncodedFormEntity(parameters, "UTF-8");
+            } catch (UnsupportedEncodingException e) {
+                throw new RuntimeException(e);
+            }
+            post.setEntity(formEntity);
 
-        return client.execute(post);
+            return client.execute(post);
+        } finally {
+            closeClient(client);
+        }
     }
 
     public AccessTokenResponse doRefreshTokenRequest(String refreshToken, String password) {
-        HttpClient client = new DefaultHttpClient();
-        HttpPost post = new HttpPost(getRefreshTokenUrl());
+        CloseableHttpClient client = new DefaultHttpClient();
+        try {
+            HttpPost post = new HttpPost(getRefreshTokenUrl());
 
-        List<NameValuePair> parameters = new LinkedList<NameValuePair>();
-        parameters.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, OAuth2Constants.REFRESH_TOKEN));
+            List<NameValuePair> parameters = new LinkedList<NameValuePair>();
+            parameters.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, OAuth2Constants.REFRESH_TOKEN));
 
-        if (refreshToken != null) {
-            parameters.add(new BasicNameValuePair(OAuth2Constants.REFRESH_TOKEN, refreshToken));
-        }
-        if (clientId != null && password != null) {
-            String authorization = BasicAuthHelper.createHeader(clientId, password);
-            post.setHeader("Authorization", authorization);
-        }
-        else if (clientId != null) {
-            parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ID, clientId));
-        }
+            if (refreshToken != null) {
+                parameters.add(new BasicNameValuePair(OAuth2Constants.REFRESH_TOKEN, refreshToken));
+            }
+            if (clientId != null && password != null) {
+                String authorization = BasicAuthHelper.createHeader(clientId, password);
+                post.setHeader("Authorization", authorization);
+            } else if (clientId != null) {
+                parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ID, clientId));
+            }
 
-        UrlEncodedFormEntity formEntity;
-        try {
-            formEntity = new UrlEncodedFormEntity(parameters, "UTF-8");
-        } catch (UnsupportedEncodingException e) {
-            throw new RuntimeException(e);
+            if (clientSessionState != null) {
+                parameters.add(new BasicNameValuePair(AdapterConstants.CLIENT_SESSION_STATE, clientSessionState));
+            }
+            if (clientSessionHost != null) {
+                parameters.add(new BasicNameValuePair(AdapterConstants.CLIENT_SESSION_HOST, clientSessionHost));
+            }
+
+            UrlEncodedFormEntity formEntity;
+            try {
+                formEntity = new UrlEncodedFormEntity(parameters, "UTF-8");
+            } catch (UnsupportedEncodingException e) {
+                throw new RuntimeException(e);
+            }
+            post.setEntity(formEntity);
+
+            try {
+                return new AccessTokenResponse(client.execute(post));
+            } catch (Exception e) {
+                throw new RuntimeException("Failed to retrieve access token", e);
+            }
+        } finally {
+            closeClient(client);
         }
-        post.setEntity(formEntity);
+    }
 
+    private void closeClient(CloseableHttpClient client) {
         try {
-            return new AccessTokenResponse(client.execute(post));
-        } catch (Exception e) {
-            throw new RuntimeException("Failed to retrieve access token", e);
+            client.close();
+        } catch (IOException ioe) {
+            throw new RuntimeException(ioe);
         }
     }
 
@@ -360,6 +409,16 @@ public class OAuthClient {
         return this;
     }
 
+    public OAuthClient clientSessionState(String client_session_state) {
+        this.clientSessionState = client_session_state;
+        return this;
+    }
+
+    public OAuthClient clientSessionHost(String client_session_host) {
+        this.clientSessionHost = client_session_host;
+        return this;
+    }
+
     public String getRealm() {
         return realm;
     }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/offlineconfig/AdminRecoveryTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/offlineconfig/AdminRecoveryTest.java
new file mode 100644
index 0000000..506a154
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/offlineconfig/AdminRecoveryTest.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2015 Red Hat Inc. and/or its affiliates and other contributors
+ * as indicated by the @author tags. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package org.keycloak.testsuite.offlineconfig;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserCredentialValueModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.UserModel.RequiredAction;
+import org.keycloak.offlineconfig.AdminRecovery;
+import org.keycloak.offlineconfig.OfflineConfigException;
+import org.keycloak.services.managers.RealmManager;
+import org.keycloak.testsuite.rule.KeycloakRule;
+import org.keycloak.testsuite.rule.WebRule;
+
+/**
+ * Test the AdminRecovery class.
+ *
+ * @author Stan Silvert ssilvert@redhat.com (C) 2015 Red Hat Inc.
+ */
+public class AdminRecoveryTest {
+    @ClassRule
+    public static KeycloakRule keycloakRule = new KeycloakRule() {
+
+        @Override
+        protected void after() {
+
+            // Need to reset admin user to default password and remove required action to not break next tests
+            update(new KeycloakSetup() {
+
+                @Override
+                public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+                    UserModel adminUser = session.users().getUserByUsername("admin", adminstrationRealm);
+                    UserCredentialModel password = UserCredentialModel.password("admin");
+                    adminUser.updateCredential(password);
+
+                    adminUser.removeRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD);
+                }
+            });
+
+            super.after();
+        }
+    };
+
+    @Rule
+    public WebRule webRule = new WebRule(this);
+
+    // Verifies that system properties were cleared at the end of recovery
+    @After
+    public void verifySysPropsCleared() {
+        Assert.assertNull(System.getProperty(AdminRecovery.RECOVER_ADMIN_ACCOUNT));
+        Assert.assertNull(System.getProperty(AdminRecovery.TEMP_ADMIN_PASSWORD));
+    }
+
+    @Test
+    public void testAdminDeletedRecovery() {
+        KeycloakSession session = keycloakRule.startSession();
+        RealmModel masterRealm = session.realms().getRealmByName("master");
+        UserModel adminUser = session.users().getUserByUsername("admin", masterRealm);
+        session.users().removeUser(masterRealm, adminUser);
+        adminUser = session.users().getUserByUsername("admin", masterRealm);
+        keycloakRule.stopSession(session, true);
+
+        Assert.assertNull(adminUser);
+
+        doAdminRecovery(session);
+
+        session = keycloakRule.startSession();
+        adminUser = session.users().getUserByUsername("admin", masterRealm);
+        Assert.assertNotNull(adminUser);
+        Assert.assertTrue(adminUser.getRequiredActions().contains(RequiredAction.UPDATE_PASSWORD.toString()));
+    }
+
+    @Test
+    public void testAdminPasswordRecovery() {
+        KeycloakSession session = keycloakRule.startSession();
+        RealmModel masterRealm = session.realms().getRealmByName("master");
+        UserModel adminUser = session.users().getUserByUsername("admin", masterRealm);
+        UserCredentialValueModel password = adminUser.getCredentialsDirectly().get(0);
+        password.setValue("forgotten-password");
+        adminUser.updateCredentialDirectly(password);
+        keycloakRule.stopSession(session, true);
+
+        Assert.assertEquals("forgotten-password", getAdminPassword());
+
+        doAdminRecovery(session);
+
+        Assert.assertNotEquals("forgotten-password", getAdminPassword());
+    }
+
+    @Test(expected = OfflineConfigException.class)
+    public void testAdminRecoveryWithoutPassword() {
+        KeycloakSession session = keycloakRule.startSession();
+        System.setProperty(AdminRecovery.RECOVER_ADMIN_ACCOUNT, "true");
+        AdminRecovery.recover(session.getKeycloakSessionFactory());
+    }
+
+    private void doAdminRecovery(KeycloakSession session) {
+        System.setProperty(AdminRecovery.RECOVER_ADMIN_ACCOUNT, "true");
+        System.setProperty(AdminRecovery.TEMP_ADMIN_PASSWORD, "foo");
+        AdminRecovery.recover(session.getKeycloakSessionFactory());
+    }
+
+    private String getAdminPassword() {
+        KeycloakSession session = keycloakRule.startSession();
+        RealmModel masterRealm = session.realms().getRealmByName("master");
+        UserModel adminUser = session.users().getUserByUsername("admin", masterRealm);
+        UserCredentialValueModel password = adminUser.getCredentialsDirectly().get(0);
+        keycloakRule.stopSession(session, true);
+        return password.getValue();
+    }
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/AccountUpdateProfilePage.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/AccountUpdateProfilePage.java
index 1aa7b21..18bc795 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/AccountUpdateProfilePage.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/AccountUpdateProfilePage.java
@@ -35,6 +35,9 @@ public class AccountUpdateProfilePage extends AbstractAccountPage {
 
     public static String PATH = RealmsResource.accountUrl(UriBuilder.fromUri(Constants.AUTH_SERVER_ROOT)).build("test").toString();
 
+    @FindBy(id = "username")
+    private WebElement usernameInput;
+
     @FindBy(id = "firstName")
     private WebElement firstNameInput;
 
@@ -74,11 +77,28 @@ public class AccountUpdateProfilePage extends AbstractAccountPage {
         submitButton.click();
     }
 
+    public void updateProfile(String username, String firstName, String lastName, String email) {
+        usernameInput.clear();
+        usernameInput.sendKeys(username);
+        firstNameInput.clear();
+        firstNameInput.sendKeys(firstName);
+        lastNameInput.clear();
+        lastNameInput.sendKeys(lastName);
+        emailInput.clear();
+        emailInput.sendKeys(email);
+
+        submitButton.click();
+    }
+
     public void clickCancel() {
         cancelButton.click();
     }
 
 
+    public String getUsername() {
+        return usernameInput.getAttribute("value");
+    }
+
     public String getFirstName() {
         return firstNameInput.getAttribute("value");
     }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/AbstractKeycloakRule.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/AbstractKeycloakRule.java
index 7641d6f..257b7aa 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/AbstractKeycloakRule.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/AbstractKeycloakRule.java
@@ -148,40 +148,9 @@ public abstract class AbstractKeycloakRule extends ExternalResource {
         return deploymentInfo;
     }
 
-    public void deployApplication(String name, String contextPath, Class<? extends Servlet> servletClass, String adapterConfigPath, String role) {
-        deployApplication(name, contextPath, servletClass, adapterConfigPath, role, true);
 
-    }
-
-    public void deployApplication(String name, String contextPath, Class<? extends Servlet> servletClass, String adapterConfigPath, String role, boolean isConstrained) {
-        deployApplication(name, contextPath, servletClass, adapterConfigPath, role, isConstrained, null);
-    }
-
-    public void deployApplication(String name, String contextPath, Class<? extends Servlet> servletClass, String adapterConfigPath, String role, boolean isConstrained, Class<? extends KeycloakConfigResolver> keycloakConfigResolver) {
-        String constraintUrl = "/*";
-        deployApplication(name, contextPath, servletClass, adapterConfigPath, role, isConstrained, keycloakConfigResolver, constraintUrl);
-    }
-
-    public void deployApplication(String name, String contextPath, Class<? extends Servlet> servletClass, String adapterConfigPath, String role, boolean isConstrained, Class<? extends KeycloakConfigResolver> keycloakConfigResolver, String constraintUrl) {
-        DeploymentInfo di = createDeploymentInfo(name, contextPath, servletClass);
-        if (null == keycloakConfigResolver) {
-            di.addInitParameter("keycloak.config.file", adapterConfigPath);
-        } else {
-            di.addInitParameter("keycloak.config.resolver", keycloakConfigResolver.getCanonicalName());
-        }
-        if (isConstrained) {
-            SecurityConstraint constraint = new SecurityConstraint();
-            WebResourceCollection collection = new WebResourceCollection();
-            collection.addUrlPattern(constraintUrl);
-            constraint.addWebResourceCollection(collection);
-            constraint.addRoleAllowed(role);
-            di.addSecurityConstraint(constraint);
-        }
-        LoginConfig loginConfig = new LoginConfig("KEYCLOAK", "demo", null, "/error.html");
-        di.setLoginConfig(loginConfig);
-        addErrorPage(di);
-
-        server.getServer().deploy(di);
+    public DeploymentBuilder createApplicationDeployment() {
+        return new DeploymentBuilder();
     }
 
     public void addErrorPage(DeploymentInfo di) {
@@ -302,4 +271,85 @@ public abstract class AbstractKeycloakRule extends ExternalResource {
         return new String[]{"test", "demo"};
     }
 
+    public class DeploymentBuilder {
+
+        private String name;
+        private String contextPath;
+        private Class<? extends Servlet> servletClass;
+        private String adapterConfigPath;
+        private String role;
+        private boolean isConstrained = true;
+        private Class<? extends KeycloakConfigResolver> keycloakConfigResolver;
+        private String constraintUrl = "/*";
+        private String errorPage = "/error.html";
+
+        public DeploymentBuilder name(String name) {
+            this.name = name;
+            return this;
+        }
+
+        public DeploymentBuilder contextPath(String contextPath) {
+            this.contextPath = contextPath;
+            return this;
+        }
+
+        public DeploymentBuilder servletClass(Class<? extends Servlet> servletClass) {
+            this.servletClass = servletClass;
+            return this;
+        }
+
+        public DeploymentBuilder adapterConfigPath(String adapterConfigPath) {
+            this.adapterConfigPath = adapterConfigPath;
+            return this;
+        }
+
+        public DeploymentBuilder role(String role) {
+            this.role = role;
+            return this;
+        }
+
+        public DeploymentBuilder isConstrained(boolean isConstrained) {
+            this.isConstrained = isConstrained;
+            return this;
+        }
+
+        public DeploymentBuilder keycloakConfigResolver(Class<? extends KeycloakConfigResolver> keycloakConfigResolver) {
+            this.keycloakConfigResolver = keycloakConfigResolver;
+            return this;
+        }
+
+        public DeploymentBuilder constraintUrl(String constraintUrl) {
+            this.constraintUrl = constraintUrl;
+            return this;
+        }
+
+        public DeploymentBuilder errorPage(String errorPage) {
+            this.errorPage = errorPage;
+            return this;
+        }
+
+        public void deployApplication() {
+            DeploymentInfo di = createDeploymentInfo(name, contextPath, servletClass);
+            if (null == keycloakConfigResolver) {
+                di.addInitParameter("keycloak.config.file", adapterConfigPath);
+            } else {
+                di.addInitParameter("keycloak.config.resolver", keycloakConfigResolver.getCanonicalName());
+            }
+            if (isConstrained) {
+                SecurityConstraint constraint = new SecurityConstraint();
+                WebResourceCollection collection = new WebResourceCollection();
+                collection.addUrlPattern(constraintUrl);
+                constraint.addWebResourceCollection(collection);
+                constraint.addRoleAllowed(role);
+                di.addSecurityConstraint(constraint);
+            }
+            LoginConfig loginConfig = new LoginConfig("KEYCLOAK", "demo", null, errorPage);
+            di.setLoginConfig(loginConfig);
+            addErrorPage(di);
+
+            server.getServer().deploy(di);
+        }
+
+    }
+
 }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/saml/SamlBindingTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/saml/SamlBindingTest.java
index 5470041..e82b04a 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/saml/SamlBindingTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/saml/SamlBindingTest.java
@@ -1,473 +1,495 @@
-package org.keycloak.testsuite.saml;
-
-import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataOutput;
-import org.junit.Assert;
-import org.junit.ClassRule;
-import org.junit.Rule;
-import org.junit.Test;
-import org.keycloak.Config;
-import org.keycloak.models.ClientModel;
-import org.keycloak.models.ClientSessionModel;
-import org.keycloak.models.Constants;
-import org.keycloak.models.KeycloakSession;
-import org.keycloak.models.ProtocolMapperModel;
-import org.keycloak.models.RealmModel;
-import org.keycloak.models.UserModel;
-import org.keycloak.models.UserSessionModel;
-import org.keycloak.protocol.oidc.OIDCLoginProtocol;
-import org.keycloak.protocol.oidc.TokenManager;
-import org.keycloak.protocol.saml.mappers.AttributeStatementHelper;
-import org.keycloak.protocol.saml.mappers.HardcodedAttributeMapper;
-import org.keycloak.protocol.saml.mappers.HardcodedRole;
-import org.keycloak.protocol.saml.mappers.RoleListMapper;
-import org.keycloak.protocol.saml.mappers.RoleNameMapper;
-import org.keycloak.representations.AccessToken;
-import org.keycloak.services.managers.RealmManager;
-import org.keycloak.services.resources.admin.AdminRoot;
-import org.keycloak.testsuite.pages.LoginPage;
-import org.keycloak.testsuite.rule.KeycloakRule;
-import org.keycloak.testsuite.rule.WebResource;
-import org.keycloak.testsuite.rule.WebRule;
-import org.openqa.selenium.WebDriver;
-import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
-import org.keycloak.saml.processing.api.saml.v2.response.SAML2Response;
-import org.keycloak.saml.processing.core.saml.v2.constants.X500SAMLProfileConstants;
-import org.keycloak.dom.saml.v2.assertion.AssertionType;
-import org.keycloak.dom.saml.v2.assertion.AttributeStatementType;
-import org.keycloak.dom.saml.v2.assertion.AttributeType;
-import org.keycloak.dom.saml.v2.protocol.ResponseType;
-import org.keycloak.saml.processing.web.util.PostBindingUtil;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.ws.rs.client.Client;
-import javax.ws.rs.client.ClientBuilder;
-import javax.ws.rs.client.ClientRequestContext;
-import javax.ws.rs.client.ClientRequestFilter;
-import javax.ws.rs.client.Entity;
-import javax.ws.rs.client.WebTarget;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriBuilder;
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
- * @version $Revision: 1 $
- */
-public class SamlBindingTest {
-
-    @ClassRule
-    public static SamlKeycloakRule keycloakRule = new SamlKeycloakRule() {
-        @Override
-        public void initWars() {
-             ClassLoader classLoader = SamlBindingTest.class.getClassLoader();
-
-            initializeSamlSecuredWar("/saml/simple-post", "/sales-post",  "post.war", classLoader);
-            initializeSamlSecuredWar("/saml/signed-post", "/sales-post-sig",  "post-sig.war", classLoader);
-            initializeSamlSecuredWar("/saml/signed-post-email", "/sales-post-sig-email",  "post-sig-email.war", classLoader);
-            initializeSamlSecuredWar("/saml/signed-post-transient", "/sales-post-sig-transient",  "post-sig-transient.war", classLoader);
-            initializeSamlSecuredWar("/saml/signed-post-persistent", "/sales-post-sig-persistent",  "post-sig-persistent.war", classLoader);
-            initializeSamlSecuredWar("/saml/signed-metadata", "/sales-metadata",  "post-metadata.war", classLoader);
-            initializeSamlSecuredWar("/saml/signed-get", "/employee-sig",  "employee-sig.war", classLoader);
-            //initializeSamlSecuredWar("/saml/simple-get", "/employee",  "employee.war", classLoader);
-            initializeSamlSecuredWar("/saml/signed-front-get", "/employee-sig-front",  "employee-sig-front.war", classLoader);
-            initializeSamlSecuredWar("/saml/bad-client-signed-post", "/bad-client-sales-post-sig",  "bad-client-post-sig.war", classLoader);
-            initializeSamlSecuredWar("/saml/bad-realm-signed-post", "/bad-realm-sales-post-sig",  "bad-realm-post-sig.war", classLoader);
-            initializeSamlSecuredWar("/saml/encrypted-post", "/sales-post-enc",  "post-enc.war", classLoader);
-            uploadSP();
-            server.getServer().deploy(createDeploymentInfo("employee.war", "/employee", SamlSPFacade.class));
-
-
-
-        }
-
-        @Override
-        public String getRealmJson() {
-            return "/saml/testsaml.json";
-        }
-    };
-
-    public static class SamlSPFacade extends HttpServlet {
-        public static String samlResponse;
-
-        @Override
-        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
-            handler(req, resp);
-        }
-
-        @Override
-        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
-            handler(req, resp);
-        }
-
-        private void handler(HttpServletRequest req, HttpServletResponse resp) {
-            System.out.println("********* HERE ******");
-            if (req.getParameterMap().isEmpty()) {
-                System.out.println("redirecting");
-                resp.setStatus(302);
-                resp.setHeader("Location", "http://localhost:8081/auth/realms/demo/protocol/saml?SAMLRequest=jVJbT8IwFP4rS99HuwluNIwEIUYSLwugD76Y2h2kSdfOng7l31uGRn0ATfrQ9HznfJfTEYpaN3zS%2Bo1ZwGsL6KP3WhvkXaEgrTPcClTIjagBuZd8Obm55mmP8cZZb6XV5NByGiwQwXllDYkmX9epNdjW4JbgtkrC%2FeK6IBvvG06ptlLojUXPc5YnFOpG2x0AJdEsaFRG7PuPoUWwQx0IXSOtoLb0SynduyLRpXUSOs8FWQuNQKL5rCDz2VO%2FymEgIY2zlJ3H%2FSx9jkU%2BzOK0ys8yNmSSsUEAYxnsqC18tyO2MDfohfEFSVkyiNlZzM5XacrDSbJePug%2Fkqj8FHKhTKXMy%2BnIng8g5FerVRmXd8sViR7AYec8AMh4tPfDO3L3Y2%2F%2F3cT4j7BH9Mf8A1nDb8PA%2Bay0WsldNNHavk1D1D5k4V0LXbi18MclJL2ke1FVvO6gvDXYgFRrBRWh4wPp7z85%2FgA%3D");
-                return;
-            }
-            System.out.println("received response");
-            samlResponse = req.getParameter("SAMLResponse");
-        }
-    }
-
-    @Rule
-    public WebRule webRule = new WebRule(this);
-    @WebResource
-    protected WebDriver driver;
-    @WebResource
-    protected LoginPage loginPage;
-
-    protected void checkLoggedOut(String mainUrl) {
-        String pageSource = driver.getPageSource();
-        System.out.println("*** logout pagesouce ***");
-        System.out.println(pageSource);
-        System.out.println("driver url: " + driver.getCurrentUrl());
-        Assert.assertTrue(pageSource.contains("request-path: /logout.jsp"));
-        driver.navigate().to(mainUrl);
-        Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml"));
-    }
-
-
-    @Test
-    public void testPostSimpleLoginLogout() {
-        driver.navigate().to("http://localhost:8081/sales-post/");
-        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
-        loginPage.login("bburke", "password");
-        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post/");
-        System.out.println(driver.getPageSource());
-        Assert.assertTrue(driver.getPageSource().contains("bburke"));
-        driver.navigate().to("http://localhost:8081/sales-post?GLO=true");
-        checkLoggedOut("http://localhost:8081/sales-post/");
-    }
-    @Test
-    public void testPostSignedLoginLogout() {
-        driver.navigate().to("http://localhost:8081/sales-post-sig/");
-        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
-        loginPage.login("bburke", "password");
-        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post-sig/");
-        Assert.assertTrue(driver.getPageSource().contains("bburke"));
-        driver.navigate().to("http://localhost:8081/sales-post-sig?GLO=true");
-        checkLoggedOut("http://localhost:8081/sales-post-sig/");
-
-    }
-    @Test
-    public void testPostSignedLoginLogoutTransientNameID() {
-        driver.navigate().to("http://localhost:8081/sales-post-sig-transient/");
-        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
-        loginPage.login("bburke", "password");
-        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post-sig-transient/");
-        System.out.println(driver.getPageSource());
-        Assert.assertFalse(driver.getPageSource().contains("bburke"));
-        Assert.assertTrue(driver.getPageSource().contains("principal=G-"));
-        driver.navigate().to("http://localhost:8081/sales-post-sig-transient?GLO=true");
-        checkLoggedOut("http://localhost:8081/sales-post-sig-transient/");
-
-    }
-    @Test
-    public void testPostSignedLoginLogoutPersistentNameID() {
-        driver.navigate().to("http://localhost:8081/sales-post-sig-persistent/");
-        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
-        loginPage.login("bburke", "password");
-        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post-sig-persistent/");
-        System.out.println(driver.getPageSource());
-        Assert.assertFalse(driver.getPageSource().contains("bburke"));
-        Assert.assertTrue(driver.getPageSource().contains("principal=G-"));
-        driver.navigate().to("http://localhost:8081/sales-post-sig-persistent?GLO=true");
-        checkLoggedOut("http://localhost:8081/sales-post-sig-persistent/");
-
-    }
-    @Test
-    public void testPostSignedLoginLogoutEmailNameID() {
-        driver.navigate().to("http://localhost:8081/sales-post-sig-email/");
-        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
-        loginPage.login("bburke", "password");
-        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post-sig-email/");
-        System.out.println(driver.getPageSource());
-        Assert.assertTrue(driver.getPageSource().contains("principal=bburke@redhat.com"));
-        driver.navigate().to("http://localhost:8081/sales-post-sig-email?GLO=true");
-        checkLoggedOut("http://localhost:8081/sales-post-sig-email/");
-
-    }
-
-
-    @Test
-    public void testAttributes() throws Exception {
-        // this test has a hardcoded SAMLRequest and we hack a SP face servlet to get the SAMLResponse so we can look
-        // at the assertions sent.  This is because Picketlink, AFAICT, does not give you any way to get access to
-        // the assertion.
-
-        {
-            SamlSPFacade.samlResponse = null;
-            driver.navigate().to("http://localhost:8081/employee/");
-            Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml"));
-            System.out.println(driver.getCurrentUrl());
-            loginPage.login("bburke", "password");
-            Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee/");
-            Assert.assertNotNull(SamlSPFacade.samlResponse);
-            SAML2Response saml2Response = new SAML2Response();
-            byte[] samlResponse = PostBindingUtil.base64Decode(SamlSPFacade.samlResponse);
-            ResponseType rt = saml2Response.getResponseType(new ByteArrayInputStream(samlResponse));
-            Assert.assertTrue(rt.getAssertions().size() == 1);
-            AssertionType assertion = rt.getAssertions().get(0).getAssertion();
-
-            // test attributes and roles
-
-            boolean email = false;
-            boolean phone = false;
-            boolean userRole = false;
-            boolean managerRole = false;
-            for (AttributeStatementType statement : assertion.getAttributeStatements()) {
-                for (AttributeStatementType.ASTChoiceType choice : statement.getAttributes()) {
-                    AttributeType attr = choice.getAttribute();
-                    if (X500SAMLProfileConstants.EMAIL.getFriendlyName().equals(attr.getFriendlyName())) {
-                        Assert.assertEquals(X500SAMLProfileConstants.EMAIL.get(), attr.getName());
-                        Assert.assertEquals(JBossSAMLURIConstants.ATTRIBUTE_FORMAT_URI.get(), attr.getNameFormat());
-                        Assert.assertEquals(attr.getAttributeValue().get(0), "bburke@redhat.com");
-                        email = true;
-                    } else if (attr.getName().equals("phone")) {
-                        Assert.assertEquals(JBossSAMLURIConstants.ATTRIBUTE_FORMAT_BASIC.get(), attr.getNameFormat());
-                        Assert.assertEquals(attr.getAttributeValue().get(0), "617");
-                        phone = true;
-                    } else if (attr.getName().equals("Role")) {
-                        if (attr.getAttributeValue().get(0).equals("manager")) managerRole = true;
-                        if (attr.getAttributeValue().get(0).equals("user")) userRole = true;
-                    }
-                }
-
-            }
-
-            Assert.assertTrue(email);
-            Assert.assertTrue(phone);
-            Assert.assertTrue(userRole);
-            Assert.assertTrue(managerRole);
-        }
-
-        keycloakRule.update(new KeycloakRule.KeycloakSetup() {
-            @Override
-            public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
-                ClientModel app = appRealm.getClientByClientId("http://localhost:8081/employee/");
-                for (ProtocolMapperModel mapper : app.getProtocolMappers()) {
-                    if (mapper.getName().equals("role-list")) {
-                        app.removeProtocolMapper(mapper);
-                        mapper.setId(null);
-                        mapper.getConfig().put(RoleListMapper.SINGLE_ROLE_ATTRIBUTE, "true");
-                        mapper.getConfig().put(AttributeStatementHelper.SAML_ATTRIBUTE_NAME, "memberOf");
-                        app.addProtocolMapper(mapper);
-                    }
-                }
-                app.addProtocolMapper(HardcodedAttributeMapper.create("hardcoded-attribute", "hardcoded-attribute", "Basic", null, "hard", false, null));
-                app.addProtocolMapper(HardcodedRole.create("hardcoded-role", "hardcoded-role"));
-                app.addProtocolMapper(RoleNameMapper.create("renamed-role", "manager", "el-jefe"));
-                app.addProtocolMapper(RoleNameMapper.create("renamed-employee-role", "http://localhost:8081/employee/.employee", "pee-on"));
-            }
-        }, "demo");
-
-        System.out.println(">>>>>>>>>> single role attribute <<<<<<<<");
-
-        {
-            SamlSPFacade.samlResponse = null;
-            driver.navigate().to("http://localhost:8081/employee/");
-            System.out.println(driver.getCurrentUrl());
-            Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee/");
-            Assert.assertNotNull(SamlSPFacade.samlResponse);
-            SAML2Response saml2Response = new SAML2Response();
-            byte[] samlResponse = PostBindingUtil.base64Decode(SamlSPFacade.samlResponse);
-            ResponseType rt = saml2Response.getResponseType(new ByteArrayInputStream(samlResponse));
-            Assert.assertTrue(rt.getAssertions().size() == 1);
-            AssertionType assertion = rt.getAssertions().get(0).getAssertion();
-
-            // test attributes and roles
-
-            boolean userRole = false;
-            boolean managerRole = false;
-            boolean single = false;
-            boolean hardcodedRole = false;
-            boolean hardcodedAttribute = false;
-            boolean peeOn = false;
-            for (AttributeStatementType statement : assertion.getAttributeStatements()) {
-                for (AttributeStatementType.ASTChoiceType choice : statement.getAttributes()) {
-                    AttributeType attr = choice.getAttribute();
-                    if (attr.getName().equals("memberOf")) {
-                        if (single) Assert.fail("too many role attributes");
-                        single = true;
-                        for (Object value : attr.getAttributeValue()) {
-                            if (value.equals("el-jefe")) managerRole = true;
-                            if (value.equals("user")) userRole = true;
-                            if (value.equals("hardcoded-role")) hardcodedRole = true;
-                            if (value.equals("pee-on")) peeOn = true;
-                        }
-                    } else if (attr.getName().equals("hardcoded-attribute")) {
-                        hardcodedAttribute = true;
-                        Assert.assertEquals(attr.getAttributeValue().get(0), "hard");
-                    }
-                }
-
-            }
-
-            Assert.assertTrue(single);
-            Assert.assertTrue(hardcodedAttribute);
-            Assert.assertTrue(hardcodedRole);
-            Assert.assertTrue(peeOn);
-            Assert.assertTrue(userRole);
-            Assert.assertTrue(managerRole);
-        }
-    }
-
-    @Test
-    public void testRedirectSignedLoginLogout() {
-        driver.navigate().to("http://localhost:8081/employee-sig/");
-        Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml"));
-        loginPage.login("bburke", "password");
-        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee-sig/");
-        Assert.assertTrue(driver.getPageSource().contains("bburke"));
-        driver.navigate().to("http://localhost:8081/employee-sig?GLO=true");
-        checkLoggedOut("http://localhost:8081/employee-sig/");
-
-    }
-
-    @Test
-    public void testRedirectSignedLoginLogoutFrontNoSSO() {
-        driver.navigate().to("http://localhost:8081/employee-sig-front/");
-        Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml"));
-        loginPage.login("bburke", "password");
-        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee-sig-front/");
-        Assert.assertTrue(driver.getPageSource().contains("bburke"));
-        driver.navigate().to("http://localhost:8081/employee-sig-front?GLO=true");
-        checkLoggedOut("http://localhost:8081/employee-sig-front/");
-
-    }
-
-    @Test
-    public void testRedirectSignedLoginLogoutFront() {
-        // visit 1st app an logg in
-        System.out.println("visit 1st app ");
-        driver.navigate().to("http://localhost:8081/employee-sig/");
-        Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml"));
-        System.out.println("login to form");
-        loginPage.login("bburke", "password");
-        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee-sig/");
-        Assert.assertTrue(driver.getPageSource().contains("bburke"));
-
-        // visit 2nd app
-        System.out.println("visit 2nd app ");
-        driver.navigate().to("http://localhost:8081/employee-sig-front/");
-        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee-sig-front/");
-        Assert.assertTrue(driver.getPageSource().contains("bburke"));
-
-        // visit 3rd app
-        System.out.println("visit 3rd app ");
-        driver.navigate().to("http://localhost:8081/sales-post-sig/");
-        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post-sig/");
-        Assert.assertTrue(driver.getPageSource().contains("bburke"));
-
-        // logout of first app
-        System.out.println("GLO");
-        driver.navigate().to("http://localhost:8081/employee-sig?GLO=true");
-        checkLoggedOut("http://localhost:8081/employee-sig/");
-        driver.navigate().to("http://localhost:8081/employee-sig-front/");
-        Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml"));
-        driver.navigate().to("http://localhost:8081/sales-post-sig/");
-        Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml"));
-
-    }
-
-    @Test
-    public void testPostEncryptedLoginLogout() {
-        driver.navigate().to("http://localhost:8081/sales-post-enc/");
-        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
-        loginPage.login("bburke", "password");
-        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post-enc/");
-        Assert.assertTrue(driver.getPageSource().contains("bburke"));
-        driver.navigate().to("http://localhost:8081/sales-post-enc?GLO=true");
-        checkLoggedOut("http://localhost:8081/sales-post-enc/");
-
-    }
-    @Test
-    public void testPostBadClientSignature() {
-        driver.navigate().to("http://localhost:8081/bad-client-sales-post-sig/");
-        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
-        Assert.assertEquals(driver.getTitle(), "We're sorry...");
-
-    }
-
-    @Test
-    public void testPostBadRealmSignature() {
-        driver.navigate().to("http://localhost:8081/bad-realm-sales-post-sig/");
-        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
-        loginPage.login("bburke", "password");
-        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/bad-realm-sales-post-sig/");
-        Assert.assertTrue(driver.getPageSource().contains("null"));
-    }
-
-    private static String createToken() {
-        KeycloakSession session = keycloakRule.startSession();
-        try {
-            RealmManager manager = new RealmManager(session);
-
-            RealmModel adminRealm = manager.getRealm(Config.getAdminRealm());
-            ClientModel adminConsole = adminRealm.getClientByClientId(Constants.ADMIN_CONSOLE_CLIENT_ID);
-            TokenManager tm = new TokenManager();
-            UserModel admin = session.users().getUserByUsername("admin", adminRealm);
-            ClientSessionModel clientSession = session.sessions().createClientSession(adminRealm, adminConsole);
-            clientSession.setNote(OIDCLoginProtocol.ISSUER, "http://localhost:8081/auth/realms/master");
-            UserSessionModel userSession = session.sessions().createUserSession(adminRealm, admin, "admin", null, "form", false, null, null);
-            AccessToken token = tm.createClientAccessToken(session, tm.getAccess(null, adminConsole, admin), adminRealm, adminConsole, admin, userSession, clientSession);
-            return tm.encodeToken(adminRealm, token);
-        } finally {
-            keycloakRule.stopSession(session, true);
-        }
-    }
-
-
-    @Test
-    public void testMetadataPostSignedLoginLogout() throws Exception {
-
-        driver.navigate().to("http://localhost:8081/sales-metadata/");
-        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
-        loginPage.login("bburke", "password");
-        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-metadata/");
-        String pageSource = driver.getPageSource();
-        Assert.assertTrue(pageSource.contains("bburke"));
-        driver.navigate().to("http://localhost:8081/sales-metadata?GLO=true");
-        checkLoggedOut("http://localhost:8081/sales-metadata/");
-
-    }
-
-    public static void uploadSP() {
-        String token = createToken();
-        final String authHeader = "Bearer " + token;
-        ClientRequestFilter authFilter = new ClientRequestFilter() {
-            @Override
-            public void filter(ClientRequestContext requestContext) throws IOException {
-                requestContext.getHeaders().add(HttpHeaders.AUTHORIZATION, authHeader);
-            }
-        };
-        Client client = ClientBuilder.newBuilder().register(authFilter).build();
-        UriBuilder authBase = UriBuilder.fromUri("http://localhost:8081/auth");
-        WebTarget adminRealms = client.target(AdminRoot.realmsUrl(authBase));
-
-
-        MultipartFormDataOutput formData = new MultipartFormDataOutput();
-        InputStream is = SamlBindingTest.class.getResourceAsStream("/saml/sp-metadata.xml");
-        Assert.assertNotNull(is);
-        formData.addFormData("file", is, MediaType.APPLICATION_XML_TYPE);
-
-        WebTarget upload = adminRealms.path("demo/client-importers/saml2-entity-descriptor/upload");
-        System.out.println(upload.getUri());
-        Response response = upload.request().post(Entity.entity(formData, MediaType.MULTIPART_FORM_DATA));
-        Assert.assertEquals(204, response.getStatus());
-        response.close();
-        client.close();
-    }
-
-
-}
+package org.keycloak.testsuite.saml;
+
+import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataOutput;
+import org.junit.Assert;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.keycloak.Config;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.ClientSessionModel;
+import org.keycloak.models.Constants;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.ProtocolMapperModel;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.UserSessionModel;
+import org.keycloak.protocol.oidc.OIDCLoginProtocol;
+import org.keycloak.protocol.oidc.TokenManager;
+import org.keycloak.protocol.saml.mappers.AttributeStatementHelper;
+import org.keycloak.protocol.saml.mappers.HardcodedAttributeMapper;
+import org.keycloak.protocol.saml.mappers.HardcodedRole;
+import org.keycloak.protocol.saml.mappers.RoleListMapper;
+import org.keycloak.protocol.saml.mappers.RoleNameMapper;
+import org.keycloak.representations.AccessToken;
+import org.keycloak.services.managers.RealmManager;
+import org.keycloak.services.resources.admin.AdminRoot;
+import org.keycloak.testsuite.pages.LoginPage;
+import org.keycloak.testsuite.rule.KeycloakRule;
+import org.keycloak.testsuite.rule.WebResource;
+import org.keycloak.testsuite.rule.WebRule;
+import org.openqa.selenium.WebDriver;
+import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
+import org.keycloak.saml.processing.api.saml.v2.response.SAML2Response;
+import org.keycloak.saml.processing.core.saml.v2.constants.X500SAMLProfileConstants;
+import org.keycloak.dom.saml.v2.assertion.AssertionType;
+import org.keycloak.dom.saml.v2.assertion.AttributeStatementType;
+import org.keycloak.dom.saml.v2.assertion.AttributeType;
+import org.keycloak.dom.saml.v2.protocol.ResponseType;
+import org.keycloak.saml.processing.web.util.PostBindingUtil;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.ClientRequestContext;
+import javax.ws.rs.client.ClientRequestFilter;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class SamlBindingTest {
+
+    @ClassRule
+    public static SamlKeycloakRule keycloakRule = new SamlKeycloakRule() {
+        @Override
+        public void initWars() {
+             ClassLoader classLoader = SamlBindingTest.class.getClassLoader();
+
+            initializeSamlSecuredWar("/saml/simple-post", "/sales-post",  "post.war", classLoader);
+            initializeSamlSecuredWar("/saml/signed-post", "/sales-post-sig",  "post-sig.war", classLoader);
+            initializeSamlSecuredWar("/saml/signed-post-email", "/sales-post-sig-email",  "post-sig-email.war", classLoader);
+            initializeSamlSecuredWar("/saml/signed-post-transient", "/sales-post-sig-transient",  "post-sig-transient.war", classLoader);
+            initializeSamlSecuredWar("/saml/signed-post-persistent", "/sales-post-sig-persistent",  "post-sig-persistent.war", classLoader);
+            initializeSamlSecuredWar("/saml/signed-metadata", "/sales-metadata",  "post-metadata.war", classLoader);
+            initializeSamlSecuredWar("/saml/signed-get", "/employee-sig",  "employee-sig.war", classLoader);
+            //initializeSamlSecuredWar("/saml/simple-get", "/employee",  "employee.war", classLoader);
+            initializeSamlSecuredWar("/saml/signed-front-get", "/employee-sig-front",  "employee-sig-front.war", classLoader);
+            initializeSamlSecuredWar("/saml/bad-client-signed-post", "/bad-client-sales-post-sig",  "bad-client-post-sig.war", classLoader);
+            initializeSamlSecuredWar("/saml/bad-realm-signed-post", "/bad-realm-sales-post-sig",  "bad-realm-post-sig.war", classLoader);
+            initializeSamlSecuredWar("/saml/encrypted-post", "/sales-post-enc",  "post-enc.war", classLoader);
+            uploadSP();
+            server.getServer().deploy(createDeploymentInfo("employee.war", "/employee", SamlSPFacade.class));
+
+
+
+        }
+
+        @Override
+        public String getRealmJson() {
+            return "/saml/testsaml.json";
+        }
+    };
+
+    public static class SamlSPFacade extends HttpServlet {
+        public static String samlResponse;
+        public static String RELAY_STATE = "http://test.com/foo/bar";
+        public static String sentRelayState;
+
+        @Override
+        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+            handler(req, resp);
+        }
+
+        @Override
+        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+            handler(req, resp);
+        }
+
+        private void handler(HttpServletRequest req, HttpServletResponse resp) {
+            System.out.println("********* HERE ******");
+            if (req.getParameterMap().isEmpty()) {
+                System.out.println("redirecting");
+                resp.setStatus(302);
+                // Redirect
+                // UriBuilder builder = UriBuilder.fromUri("http://localhost:8081/auth/realms/demo/protocol/saml?SAMLRequest=jVLRTsIwFP2Vpe%2BjG4wxG0YyWYxL0BBAH3wx3XYnTbp29nYof%2B8YEvEBNOlD03vOveec2ynyWjYsae1WreC9BbTOZy0Vsr4Qk9YopjkKZIrXgMwWbJ08LNhw4LHGaKsLLcmRch3MEcFYoRVxktN1rhW2NZg1mJ0o4Gm1iMnW2oZRKnXB5VajZZEX%2BRTqRuo9ACVO2mkUih%2F4l9C8s0MNcFkjLaHW9KSUHlwR506bAnrPMam4RCBOlsYkS1%2BD3MvLcDJxAx9KN4jCkXszrG5cP%2BCVH4y8IM8PYFx2dsQOfuiILWQKLVc2JkPPH7te6HrRxh%2BzUdidwSSIXoiz%2FBZyK1Qp1Nv1yPIjCNn9ZrN0V1AKA4UlzjMY7N13IDKbHjyxXoA5291%2FtzH7I%2FApPet%2FHNawx65hli61FMXeSaTUH%2FMubtvlYU0LfcA1t5cl%2BAO%2FfxGlW%2FVQ1ipsoBCVgJLQ2XHo7385%2BwI%3D");
+                UriBuilder builder = UriBuilder.fromUri("http://localhost:8081/auth/realms/demo/protocol/saml?SAMLRequest=jVJbT8IwFP4rS99HuwluNIwEIUYSLwugD76Y2h2kSdfOng7l31uGRn0ATfrQ9HznfJfTEYpaN3zS%2Bo1ZwGsL6KP3WhvkXaEgrTPcClTIjagBuZd8Obm55mmP8cZZb6XV5NByGiwQwXllDYkmX9epNdjW4JbgtkrC%2FeK6IBvvG06ptlLojUXPc5YnFOpG2x0AJdEsaFRG7PuPoUWwQx0IXSOtoLb0SynduyLRpXUSOs8FWQuNQKL5rCDz2VO%2FymEgIY2zlJ3H%2FSx9jkU%2BzOK0ys8yNmSSsUEAYxnsqC18tyO2MDfohfEFSVkyiNlZzM5XacrDSbJePug%2Fkqj8FHKhTKXMy%2BnIng8g5FerVRmXd8sViR7AYec8AMh4tPfDO3L3Y2%2F%2F3cT4j7BH9Mf8A1nDb8PA%2Bay0WsldNNHavk1D1D5k4V0LXbi18MclJL2ke1FVvO6gvDXYgFRrBRWh4wPp7z85%2FgA%3D");
+                builder.queryParam("RelayState", RELAY_STATE);
+                resp.setHeader("Location", builder.build().toString());
+                return;
+            }
+            System.out.println("received response");
+            samlResponse = req.getParameter("SAMLResponse");
+            sentRelayState = req.getParameter("RelayState");
+        }
+    }
+
+    @Rule
+    public WebRule webRule = new WebRule(this);
+    @WebResource
+    protected WebDriver driver;
+    @WebResource
+    protected LoginPage loginPage;
+
+    protected void checkLoggedOut(String mainUrl) {
+        String pageSource = driver.getPageSource();
+        System.out.println("*** logout pagesouce ***");
+        System.out.println(pageSource);
+        System.out.println("driver url: " + driver.getCurrentUrl());
+        Assert.assertTrue(pageSource.contains("request-path: /logout.jsp"));
+        driver.navigate().to(mainUrl);
+        Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml"));
+    }
+
+
+    @Test
+    public void testPostSimpleLoginLogout() {
+        driver.navigate().to("http://localhost:8081/sales-post/");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
+        loginPage.login("bburke", "password");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post/");
+        System.out.println(driver.getPageSource());
+        Assert.assertTrue(driver.getPageSource().contains("bburke"));
+        driver.navigate().to("http://localhost:8081/sales-post?GLO=true");
+        checkLoggedOut("http://localhost:8081/sales-post/");
+    }
+    @Test
+    public void testPostSignedLoginLogout() {
+        driver.navigate().to("http://localhost:8081/sales-post-sig/");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
+        loginPage.login("bburke", "password");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post-sig/");
+        Assert.assertTrue(driver.getPageSource().contains("bburke"));
+        driver.navigate().to("http://localhost:8081/sales-post-sig?GLO=true");
+        checkLoggedOut("http://localhost:8081/sales-post-sig/");
+
+    }
+    @Test
+    public void testPostSignedLoginLogoutTransientNameID() {
+        driver.navigate().to("http://localhost:8081/sales-post-sig-transient/");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
+        loginPage.login("bburke", "password");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post-sig-transient/");
+        System.out.println(driver.getPageSource());
+        Assert.assertFalse(driver.getPageSource().contains("bburke"));
+        Assert.assertTrue(driver.getPageSource().contains("principal=G-"));
+        driver.navigate().to("http://localhost:8081/sales-post-sig-transient?GLO=true");
+        checkLoggedOut("http://localhost:8081/sales-post-sig-transient/");
+
+    }
+    @Test
+    public void testPostSignedLoginLogoutPersistentNameID() {
+        driver.navigate().to("http://localhost:8081/sales-post-sig-persistent/");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
+        loginPage.login("bburke", "password");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post-sig-persistent/");
+        System.out.println(driver.getPageSource());
+        Assert.assertFalse(driver.getPageSource().contains("bburke"));
+        Assert.assertTrue(driver.getPageSource().contains("principal=G-"));
+        driver.navigate().to("http://localhost:8081/sales-post-sig-persistent?GLO=true");
+        checkLoggedOut("http://localhost:8081/sales-post-sig-persistent/");
+
+    }
+    @Test
+    public void testPostSignedLoginLogoutEmailNameID() {
+        driver.navigate().to("http://localhost:8081/sales-post-sig-email/");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
+        loginPage.login("bburke", "password");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post-sig-email/");
+        System.out.println(driver.getPageSource());
+        Assert.assertTrue(driver.getPageSource().contains("principal=bburke@redhat.com"));
+        driver.navigate().to("http://localhost:8081/sales-post-sig-email?GLO=true");
+        checkLoggedOut("http://localhost:8081/sales-post-sig-email/");
+
+    }
+
+    @Test
+    public void testRelayStateEncoding() throws Exception {
+        // this test has a hardcoded SAMLRequest and we hack a SP face servlet to get the SAMLResponse so we can look
+        // at the relay state
+        SamlSPFacade.samlResponse = null;
+        driver.navigate().to("http://localhost:8081/employee/");
+        Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml"));
+        System.out.println(driver.getCurrentUrl());
+        loginPage.login("bburke", "password");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee/");
+        Assert.assertEquals(SamlSPFacade.sentRelayState, SamlSPFacade.RELAY_STATE);
+        Assert.assertNotNull(SamlSPFacade.samlResponse);
+
+    }
+
+
+    @Test
+    public void testAttributes() throws Exception {
+        // this test has a hardcoded SAMLRequest and we hack a SP face servlet to get the SAMLResponse so we can look
+        // at the assertions sent.  This is because Picketlink, AFAICT, does not give you any way to get access to
+        // the assertion.
+
+        {
+            SamlSPFacade.samlResponse = null;
+            driver.navigate().to("http://localhost:8081/employee/");
+            Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml"));
+            System.out.println(driver.getCurrentUrl());
+            loginPage.login("bburke", "password");
+            Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee/");
+            Assert.assertNotNull(SamlSPFacade.samlResponse);
+            SAML2Response saml2Response = new SAML2Response();
+            byte[] samlResponse = PostBindingUtil.base64Decode(SamlSPFacade.samlResponse);
+            ResponseType rt = saml2Response.getResponseType(new ByteArrayInputStream(samlResponse));
+            Assert.assertTrue(rt.getAssertions().size() == 1);
+            AssertionType assertion = rt.getAssertions().get(0).getAssertion();
+
+            // test attributes and roles
+
+            boolean email = false;
+            boolean phone = false;
+            boolean userRole = false;
+            boolean managerRole = false;
+            for (AttributeStatementType statement : assertion.getAttributeStatements()) {
+                for (AttributeStatementType.ASTChoiceType choice : statement.getAttributes()) {
+                    AttributeType attr = choice.getAttribute();
+                    if (X500SAMLProfileConstants.EMAIL.getFriendlyName().equals(attr.getFriendlyName())) {
+                        Assert.assertEquals(X500SAMLProfileConstants.EMAIL.get(), attr.getName());
+                        Assert.assertEquals(JBossSAMLURIConstants.ATTRIBUTE_FORMAT_URI.get(), attr.getNameFormat());
+                        Assert.assertEquals(attr.getAttributeValue().get(0), "bburke@redhat.com");
+                        email = true;
+                    } else if (attr.getName().equals("phone")) {
+                        Assert.assertEquals(JBossSAMLURIConstants.ATTRIBUTE_FORMAT_BASIC.get(), attr.getNameFormat());
+                        Assert.assertEquals(attr.getAttributeValue().get(0), "617");
+                        phone = true;
+                    } else if (attr.getName().equals("Role")) {
+                        if (attr.getAttributeValue().get(0).equals("manager")) managerRole = true;
+                        if (attr.getAttributeValue().get(0).equals("user")) userRole = true;
+                    }
+                }
+
+            }
+
+            Assert.assertTrue(email);
+            Assert.assertTrue(phone);
+            Assert.assertTrue(userRole);
+            Assert.assertTrue(managerRole);
+        }
+
+        keycloakRule.update(new KeycloakRule.KeycloakSetup() {
+            @Override
+            public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+                ClientModel app = appRealm.getClientByClientId("http://localhost:8081/employee/");
+                for (ProtocolMapperModel mapper : app.getProtocolMappers()) {
+                    if (mapper.getName().equals("role-list")) {
+                        app.removeProtocolMapper(mapper);
+                        mapper.setId(null);
+                        mapper.getConfig().put(RoleListMapper.SINGLE_ROLE_ATTRIBUTE, "true");
+                        mapper.getConfig().put(AttributeStatementHelper.SAML_ATTRIBUTE_NAME, "memberOf");
+                        app.addProtocolMapper(mapper);
+                    }
+                }
+                app.addProtocolMapper(HardcodedAttributeMapper.create("hardcoded-attribute", "hardcoded-attribute", "Basic", null, "hard", false, null));
+                app.addProtocolMapper(HardcodedRole.create("hardcoded-role", "hardcoded-role"));
+                app.addProtocolMapper(RoleNameMapper.create("renamed-role", "manager", "el-jefe"));
+                app.addProtocolMapper(RoleNameMapper.create("renamed-employee-role", "http://localhost:8081/employee/.employee", "pee-on"));
+            }
+        }, "demo");
+
+        System.out.println(">>>>>>>>>> single role attribute <<<<<<<<");
+
+        {
+            SamlSPFacade.samlResponse = null;
+            driver.navigate().to("http://localhost:8081/employee/");
+            System.out.println(driver.getCurrentUrl());
+            Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee/");
+            Assert.assertNotNull(SamlSPFacade.samlResponse);
+            SAML2Response saml2Response = new SAML2Response();
+            byte[] samlResponse = PostBindingUtil.base64Decode(SamlSPFacade.samlResponse);
+            ResponseType rt = saml2Response.getResponseType(new ByteArrayInputStream(samlResponse));
+            Assert.assertTrue(rt.getAssertions().size() == 1);
+            AssertionType assertion = rt.getAssertions().get(0).getAssertion();
+
+            // test attributes and roles
+
+            boolean userRole = false;
+            boolean managerRole = false;
+            boolean single = false;
+            boolean hardcodedRole = false;
+            boolean hardcodedAttribute = false;
+            boolean peeOn = false;
+            for (AttributeStatementType statement : assertion.getAttributeStatements()) {
+                for (AttributeStatementType.ASTChoiceType choice : statement.getAttributes()) {
+                    AttributeType attr = choice.getAttribute();
+                    if (attr.getName().equals("memberOf")) {
+                        if (single) Assert.fail("too many role attributes");
+                        single = true;
+                        for (Object value : attr.getAttributeValue()) {
+                            if (value.equals("el-jefe")) managerRole = true;
+                            if (value.equals("user")) userRole = true;
+                            if (value.equals("hardcoded-role")) hardcodedRole = true;
+                            if (value.equals("pee-on")) peeOn = true;
+                        }
+                    } else if (attr.getName().equals("hardcoded-attribute")) {
+                        hardcodedAttribute = true;
+                        Assert.assertEquals(attr.getAttributeValue().get(0), "hard");
+                    }
+                }
+
+            }
+
+            Assert.assertTrue(single);
+            Assert.assertTrue(hardcodedAttribute);
+            Assert.assertTrue(hardcodedRole);
+            Assert.assertTrue(peeOn);
+            Assert.assertTrue(userRole);
+            Assert.assertTrue(managerRole);
+        }
+    }
+
+    @Test
+    public void testRedirectSignedLoginLogout() {
+        driver.navigate().to("http://localhost:8081/employee-sig/");
+        Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml"));
+        loginPage.login("bburke", "password");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee-sig/");
+        Assert.assertTrue(driver.getPageSource().contains("bburke"));
+        driver.navigate().to("http://localhost:8081/employee-sig?GLO=true");
+        checkLoggedOut("http://localhost:8081/employee-sig/");
+
+    }
+
+    @Test
+    public void testRedirectSignedLoginLogoutFrontNoSSO() {
+        driver.navigate().to("http://localhost:8081/employee-sig-front/");
+        Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml"));
+        loginPage.login("bburke", "password");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee-sig-front/");
+        Assert.assertTrue(driver.getPageSource().contains("bburke"));
+        driver.navigate().to("http://localhost:8081/employee-sig-front?GLO=true");
+        checkLoggedOut("http://localhost:8081/employee-sig-front/");
+
+    }
+
+    @Test
+    public void testRedirectSignedLoginLogoutFront() {
+        // visit 1st app an logg in
+        System.out.println("visit 1st app ");
+        driver.navigate().to("http://localhost:8081/employee-sig/");
+        Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml"));
+        System.out.println("login to form");
+        loginPage.login("bburke", "password");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee-sig/");
+        Assert.assertTrue(driver.getPageSource().contains("bburke"));
+
+        // visit 2nd app
+        System.out.println("visit 2nd app ");
+        driver.navigate().to("http://localhost:8081/employee-sig-front/");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee-sig-front/");
+        Assert.assertTrue(driver.getPageSource().contains("bburke"));
+
+        // visit 3rd app
+        System.out.println("visit 3rd app ");
+        driver.navigate().to("http://localhost:8081/sales-post-sig/");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post-sig/");
+        Assert.assertTrue(driver.getPageSource().contains("bburke"));
+
+        // logout of first app
+        System.out.println("GLO");
+        driver.navigate().to("http://localhost:8081/employee-sig?GLO=true");
+        checkLoggedOut("http://localhost:8081/employee-sig/");
+        driver.navigate().to("http://localhost:8081/employee-sig-front/");
+        Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml"));
+        driver.navigate().to("http://localhost:8081/sales-post-sig/");
+        Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml"));
+
+    }
+
+    @Test
+    public void testPostEncryptedLoginLogout() {
+        driver.navigate().to("http://localhost:8081/sales-post-enc/");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
+        loginPage.login("bburke", "password");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post-enc/");
+        Assert.assertTrue(driver.getPageSource().contains("bburke"));
+        driver.navigate().to("http://localhost:8081/sales-post-enc?GLO=true");
+        checkLoggedOut("http://localhost:8081/sales-post-enc/");
+
+    }
+    @Test
+    public void testPostBadClientSignature() {
+        driver.navigate().to("http://localhost:8081/bad-client-sales-post-sig/");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
+        Assert.assertEquals(driver.getTitle(), "We're sorry...");
+
+    }
+
+    @Test
+    public void testPostBadRealmSignature() {
+        driver.navigate().to("http://localhost:8081/bad-realm-sales-post-sig/");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
+        loginPage.login("bburke", "password");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/bad-realm-sales-post-sig/");
+        Assert.assertTrue(driver.getPageSource().contains("null"));
+    }
+
+    private static String createToken() {
+        KeycloakSession session = keycloakRule.startSession();
+        try {
+            RealmManager manager = new RealmManager(session);
+
+            RealmModel adminRealm = manager.getRealm(Config.getAdminRealm());
+            ClientModel adminConsole = adminRealm.getClientByClientId(Constants.ADMIN_CONSOLE_CLIENT_ID);
+            TokenManager tm = new TokenManager();
+            UserModel admin = session.users().getUserByUsername("admin", adminRealm);
+            ClientSessionModel clientSession = session.sessions().createClientSession(adminRealm, adminConsole);
+            clientSession.setNote(OIDCLoginProtocol.ISSUER, "http://localhost:8081/auth/realms/master");
+            UserSessionModel userSession = session.sessions().createUserSession(adminRealm, admin, "admin", null, "form", false, null, null);
+            AccessToken token = tm.createClientAccessToken(session, tm.getAccess(null, adminConsole, admin), adminRealm, adminConsole, admin, userSession, clientSession);
+            return tm.encodeToken(adminRealm, token);
+        } finally {
+            keycloakRule.stopSession(session, true);
+        }
+    }
+
+
+    @Test
+    public void testMetadataPostSignedLoginLogout() throws Exception {
+
+        driver.navigate().to("http://localhost:8081/sales-metadata/");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
+        loginPage.login("bburke", "password");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-metadata/");
+        String pageSource = driver.getPageSource();
+        Assert.assertTrue(pageSource.contains("bburke"));
+        driver.navigate().to("http://localhost:8081/sales-metadata?GLO=true");
+        checkLoggedOut("http://localhost:8081/sales-metadata/");
+
+    }
+
+    public static void uploadSP() {
+        String token = createToken();
+        final String authHeader = "Bearer " + token;
+        ClientRequestFilter authFilter = new ClientRequestFilter() {
+            @Override
+            public void filter(ClientRequestContext requestContext) throws IOException {
+                requestContext.getHeaders().add(HttpHeaders.AUTHORIZATION, authHeader);
+            }
+        };
+        Client client = ClientBuilder.newBuilder().register(authFilter).build();
+        UriBuilder authBase = UriBuilder.fromUri("http://localhost:8081/auth");
+        WebTarget adminRealms = client.target(AdminRoot.realmsUrl(authBase));
+
+
+        MultipartFormDataOutput formData = new MultipartFormDataOutput();
+        InputStream is = SamlBindingTest.class.getResourceAsStream("/saml/sp-metadata.xml");
+        Assert.assertNotNull(is);
+        formData.addFormData("file", is, MediaType.APPLICATION_XML_TYPE);
+
+        WebTarget upload = adminRealms.path("demo/client-importers/saml2-entity-descriptor/upload");
+        System.out.println(upload.getUri());
+        Response response = upload.request().post(Entity.entity(formData, MediaType.MULTIPART_FORM_DATA));
+        Assert.assertEquals(204, response.getStatus());
+        response.close();
+        client.close();
+    }
+
+
+}
diff --git a/testsuite/integration/src/test/resources/adapter-test/demorealm.json b/testsuite/integration/src/test/resources/adapter-test/demorealm.json
index 32a79c7..c0b6003 100755
--- a/testsuite/integration/src/test/resources/adapter-test/demorealm.json
+++ b/testsuite/integration/src/test/resources/adapter-test/demorealm.json
@@ -7,7 +7,6 @@
     "accessCodeLifespanUserAction": 6000,
     "sslRequired": "external",
     "registrationAllowed": false,
-    "passwordCredentialGrantAllowed": true,
     "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
     "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
     "requiredCredentials": [ "password" ],
diff --git a/testsuite/integration/src/test/resources/adapter-test/tenant1-realm.json b/testsuite/integration/src/test/resources/adapter-test/tenant1-realm.json
index 3f6649c..8f0adda 100644
--- a/testsuite/integration/src/test/resources/adapter-test/tenant1-realm.json
+++ b/testsuite/integration/src/test/resources/adapter-test/tenant1-realm.json
@@ -7,7 +7,6 @@
     "accessCodeLifespanUserAction": 6000,
     "sslRequired": "external",
     "registrationAllowed": false,
-    "passwordCredentialGrantAllowed": true,
     "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
     "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
     "requiredCredentials": [ "password" ],
diff --git a/testsuite/integration/src/test/resources/adapter-test/tenant2-realm.json b/testsuite/integration/src/test/resources/adapter-test/tenant2-realm.json
index 1a5ccc4..a1b0357 100644
--- a/testsuite/integration/src/test/resources/adapter-test/tenant2-realm.json
+++ b/testsuite/integration/src/test/resources/adapter-test/tenant2-realm.json
@@ -7,7 +7,6 @@
     "accessCodeLifespanUserAction": 6000,
     "sslRequired": "external",
     "registrationAllowed": false,
-    "passwordCredentialGrantAllowed": true,
     "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
     "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
     "requiredCredentials": [ "password" ],
diff --git a/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json b/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json
index 009fda5..a6ace52 100755
--- a/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json
+++ b/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json
@@ -7,12 +7,18 @@
     "registrationAllowed": true,
     "privateKey": "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCCPyvTTb14vSMkpe/pds2P5Cqxk7bkeFnQiNMS1vyZ+HS2O79fxzp1eAguHnBTs4XTRT7SZJhIT/6utgqZjmDigKV5N7X5ptq8BM/W1qa1cYBRip261pc+tWf3IywJYQ9yFI9mUQarmIEl0D7GH16NSZklheaWfbodRVarvX+ML0amNtGYVDft/RftYmgbKKrK218qQp9R4GZFtf/Q/RmboNXN7weMINU8GWVkTRrccKBIXSunT6zXGfuj3Wp1YpVq20BWwY2OMM/P+yDAc7LKEO1LJqPBdT4r9BRn2lXiaga3AL24gTKZPKU/tu7uqfFciF+i4Rr58SMDNOzQcnklAgMBAAECggEAc0eibJYEO5d8QXW1kPgcHV2gBChv2mxDYnWYDLbIQSdNdfYP/qABt/MTmm5KkWr16fcCEYoD1w0mqFBrtVn1msSusUmEAYGTXJMNumOmjjX1kzaTQMmqeFBrwqwYz/xehWR5P+A7fSmwNV3KEeW19GvN5w5K96w0TLAQdFV3TQVPSytusDunwuR1yltMe1voaEDZ9z0Pi08YiEk2f6xhj5CMkoiw3mNImzfruphHullxU4FD05fH6tDeJ381527ILpAzDsgYZh4aFLKjUHem96bX4EL7FIzBJ6okgN78AZnUC/EaVfgFTw0qfhoWvZV4ruVXXiMhCg4CMMRDq/k9iQKBgQDBNWsJMT84OnnWmQoJmZogkFV+tsGrSK6Re+aJxLWpishh7dwAnT2OcagZvVdUb0FwNWu1D0B9/SKDDMRnnHBhOGDpH57m/eQdRU0oX1BD27xvffk0lLcfD4BTxnR5e9jss8K4twc9jf0P1rxC/loGJ2NtCH0BrPHgz54Ea+96ewKBgQCsk3JDaaPnFwzVYm2BXlhxOxLPsF4wvD2rIRAswZV4C5xebjand8nwiMmVpNd0PRLkEnkI+waURGv2EY/P3JsssoiY8Xqe8f/1G+SQKre7lbqOas8rFoALepC0BYDiZDFy0Z9ZnRAFzRI5sgIt7jpoMRD4xDNlmiV8X+yBxc3Y3wKBgQChDQsU1YUyNKQ8+sLAL9anEEkD4Ald4q8JPHN2IY+gLLxNzT0XEfsu0pTiJ8805axxgUYv3e/PVYNAJBNPnrqaf6lgiegl+jr9Hzhqz9CTUAYqFaL2boSakoxQyNtsLI0s+cb1vDN/3uy0GDZDzcty18BsMagqDmRtFgNNAj/UIwKBgQCahbeFBv0cOPZjxisY8Bou4N8aGehsqNBq/0LVYExuXa8YmoTTdJ3bgw9Er4G/ccQNdUDsuqAMeCtW/CiRzQ0ge4d1sprB4Rv3I4+HSsiS7SFKzfZLtWzXWlpg5qCdlWr1TR7qhYjIOPO9t1beO3YOvwhcRoliyyAPenBxTmTfbwKBgDtm2WJ5VlQgNpIdOs1CCiqd0DFmWOmvBPspPC1kySiy+Ndr9jNohRZkR7pEjgqA5E8rdzc88LirUN7bY5HFHRWN9KXrs5/o3O1K3GFCp64N6nvnPEYZ2zSJalcMC2fjSsJg26z8Dg1H+gfTIDUMoGiEAAnJXuqk+WayPU+fZMLn",
     "publicKey": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgj8r0029eL0jJKXv6XbNj+QqsZO25HhZ0IjTEtb8mfh0tju/X8c6dXgILh5wU7OF00U+0mSYSE/+rrYKmY5g4oCleTe1+abavATP1tamtXGAUYqdutaXPrVn9yMsCWEPchSPZlEGq5iBJdA+xh9ejUmZJYXmln26HUVWq71/jC9GpjbRmFQ37f0X7WJoGyiqyttfKkKfUeBmRbX/0P0Zm6DVze8HjCDVPBllZE0a3HCgSF0rp0+s1xn7o91qdWKVattAVsGNjjDPz/sgwHOyyhDtSyajwXU+K/QUZ9pV4moGtwC9uIEymTylP7bu7qnxXIhfouEa+fEjAzTs0HJ5JQIDAQAB",
+    "smtpServer": {
+        "from": "auto@keycloak.org",
+        "host": "localhost",
+        "port":"3025"
+    },
     "identityProviders" : [
         {
             "alias" : "model-google",
             "providerId" : "google",
             "enabled": true,
             "updateProfileFirstLogin" : "true",
+            "trustEmail" : "true",
             "storeToken": "true",
             "config": {
                 "clientId": "clientId",
@@ -23,7 +29,7 @@
             "alias" : "model-facebook",
             "providerId" : "facebook",
             "enabled": true,
-            "updateProfileFirstLogin" : "true",
+            "updateProfileFirstLogin" : "false",
             "config": {
                 "authorizationUrl": "authorizationUrl",
                 "tokenUrl": "tokenUrl",
@@ -36,7 +42,7 @@
             "alias" : "model-github",
             "providerId" : "github",
             "enabled": true,
-            "updateProfileFirstLogin" : "true",
+            "updateProfileFirstLoginMode" : "on",
             "storeToken": "false",
             "config": {
                 "authorizationUrl": "authorizationUrl",
@@ -50,7 +56,7 @@
             "alias" : "model-twitter",
             "providerId" : "twitter",
             "enabled": true,
-            "updateProfileFirstLogin" : "true",
+            "updateProfileFirstLoginMode" : "off",
             "storeToken": true,
             "config": {
                 "authorizationUrl": "authorizationUrl",
@@ -64,7 +70,7 @@
             "alias" : "model-linkedin",
             "providerId" : "linkedin",
             "enabled": true,
-            "updateProfileFirstLogin" : "true",
+            "updateProfileFirstLoginMode" : "missing",
             "storeToken": false,
             "config": {
                 "authorizationUrl": "authorizationUrl",
@@ -78,7 +84,7 @@
             "alias" : "model-stackoverflow",
             "providerId" : "stackoverflow",
             "enabled": true,
-            "updateProfileFirstLogin" : "true",
+            "updateProfileFirstLoginMode" : "off",
             "storeToken": false,
             "config": {
                 "key": "keyValue",
@@ -93,7 +99,7 @@
           "alias" : "model-saml-signed-idp",
           "providerId" : "saml",
           "enabled": true,
-          "updateProfileFirstLogin" : "true",
+          "updateProfileFirstLoginMode" : "on",
           "config": {
             "singleSignOnServiceUrl": "http://localhost:8082/auth/realms/realm-with-saml-identity-provider/protocol/saml",
             "nameIDPolicyFormat": "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress",
@@ -109,7 +115,7 @@
             "alias" : "kc-saml-signed-idp",
             "providerId" : "saml",
             "enabled": true,
-            "updateProfileFirstLogin" : true,
+            "updateProfileFirstLoginMode" : "on",
             "addReadTokenRoleOnCreate": true,
             "config": {
                 "singleSignOnServiceUrl": "http://localhost:8082/auth/realms/realm-with-saml-signed-idp/protocol/saml",
@@ -128,7 +134,8 @@
             "alias" : "kc-saml-idp-basic",
             "providerId" : "saml",
             "enabled": true,
-            "updateProfileFirstLogin" : true,
+            "updateProfileFirstLoginMode" : "on",
+            "trustEmail" : false,
             "addReadTokenRoleOnCreate": true,
             "config": {
                 "singleSignOnServiceUrl": "http://localhost:8082/auth/realms/realm-with-saml-idp-basic/protocol/saml",
@@ -143,7 +150,7 @@
             "alias" : "model-oidc-idp",
             "providerId" : "oidc",
             "enabled": false,
-            "updateProfileFirstLogin" : "false",
+            "updateProfileFirstLoginMode" : "off",
             "authenticateByDefault" : "false",
             "config": {
                 "clientId": "clientId",
@@ -159,7 +166,7 @@
             "alias" : "kc-oidc-idp",
             "providerId" : "keycloak-oidc",
             "enabled": true,
-            "updateProfileFirstLogin" : "false",
+            "updateProfileFirstLoginMode" : "off",
             "storeToken" : true,
             "addReadTokenRoleOnCreate": true,
             "config": {
diff --git a/testsuite/integration/src/test/resources/kerberos-test/kerberosrealm.json b/testsuite/integration/src/test/resources/kerberos-test/kerberosrealm.json
index b0fb903..d9616db 100644
--- a/testsuite/integration/src/test/resources/kerberos-test/kerberosrealm.json
+++ b/testsuite/integration/src/test/resources/kerberos-test/kerberosrealm.json
@@ -5,7 +5,6 @@
     "sslRequired": "external",
     "registrationAllowed": true,
     "resetPasswordAllowed": true,
-    "passwordCredentialGrantAllowed": true,
     "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
     "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
     "requiredCredentials": [ "password", "kerberos" ],
diff --git a/testsuite/integration/src/test/resources/ldap/ldap-connection.properties b/testsuite/integration/src/test/resources/ldap/ldap-connection.properties
index c759f4a..c279f49 100644
--- a/testsuite/integration/src/test/resources/ldap/ldap-connection.properties
+++ b/testsuite/integration/src/test/resources/ldap/ldap-connection.properties
@@ -1,7 +1,5 @@
 idm.test.ldap.connection.url=ldap\://localhost\:10389
 idm.test.ldap.base.dn=dc\=keycloak,dc\=org
-idm.test.ldap.roles.dn.suffix=ou\=Roles,dc\=keycloak,dc\=org
-idm.test.ldap.group.dn.suffix=ou\=Groups,dc\=keycloak,dc\=org
 idm.test.ldap.user.dn.suffix=ou\=People,dc\=keycloak,dc\=org
 idm.test.ldap.start.embedded.ldap.server=true
 idm.test.ldap.bind.dn=uid\=admin,ou\=system
diff --git a/testsuite/integration/src/test/resources/ldap/users.ldif b/testsuite/integration/src/test/resources/ldap/users.ldif
index b1777d7..9450126 100644
--- a/testsuite/integration/src/test/resources/ldap/users.ldif
+++ b/testsuite/integration/src/test/resources/ldap/users.ldif
@@ -14,26 +14,9 @@ objectclass: top
 objectclass: organizationalUnit
 ou: RealmRoles
 
-dn: cn=realmRole1,ou=RealmRoles,dc=keycloak,dc=org
-objectclass: top
-objectclass: groupOfNames
-cn: realmRole1
-member:
-
-dn: cn=realmRole2,ou=RealmRoles,dc=keycloak,dc=org
-objectclass: top
-objectclass: groupOfNames
-cn: realmRole2
-member:
-
 dn: ou=FinanceRoles,dc=keycloak,dc=org
 objectclass: top
 objectclass: organizationalUnit
 ou: FinanceRoles
 
-dn: cn=financeRole1,ou=FinanceRoles,dc=keycloak,dc=org
-objectclass: top
-objectclass: groupOfNames
-cn: financeRole1
-member:
 
diff --git a/testsuite/integration/src/test/resources/saml/signed-get/WEB-INF/picketlink.xml b/testsuite/integration/src/test/resources/saml/signed-get/WEB-INF/picketlink.xml
index e2e7e3b..2dd9522 100755
--- a/testsuite/integration/src/test/resources/saml/signed-get/WEB-INF/picketlink.xml
+++ b/testsuite/integration/src/test/resources/saml/signed-get/WEB-INF/picketlink.xml
@@ -1,6 +1,6 @@
 <PicketLink xmlns="urn:picketlink:identity-federation:config:2.1">
 	<PicketLinkSP xmlns="urn:picketlink:identity-federation:config:2.1"
-		ServerEnvironment="tomcat" BindingType="REDIRECT" SupportsSignatures="true">
+		ServerEnvironment="tomcat" BindingType="REDIRECT" SupportsSignatures="true" IDPUsesPostBinding="false">
 		<IdentityURL>${idp-sig.url::http://localhost:8081/auth/realms/demo/protocol/saml}
 		</IdentityURL>
 		<ServiceURL>${employee-sig.url::http://localhost:8081/employee-sig/}
diff --git a/testsuite/integration/src/test/resources/saml/simple-get/WEB-INF/picketlink.xml b/testsuite/integration/src/test/resources/saml/simple-get/WEB-INF/picketlink.xml
index 7636260..ade45d1 100755
--- a/testsuite/integration/src/test/resources/saml/simple-get/WEB-INF/picketlink.xml
+++ b/testsuite/integration/src/test/resources/saml/simple-get/WEB-INF/picketlink.xml
@@ -1,6 +1,6 @@
 <PicketLink xmlns="urn:picketlink:identity-federation:config:2.1">
 	<PicketLinkSP xmlns="urn:picketlink:identity-federation:config:2.1"
-		ServerEnvironment="tomcat" BindingType="REDIRECT" RelayState="someURL">
+		ServerEnvironment="tomcat" BindingType="REDIRECT" IDPUsesPostBinding="false">
 		<IdentityURL>${idp.url::http://localhost:8081/auth/realms/demo/protocol/saml}</IdentityURL>
 		<ServiceURL>${employee.url::http://localhost:8081/employee/}
 		</ServiceURL>
diff --git a/testsuite/integration/src/test/resources/saml/testsaml.json b/testsuite/integration/src/test/resources/saml/testsaml.json
index ed67040..8b297ec 100755
--- a/testsuite/integration/src/test/resources/saml/testsaml.json
+++ b/testsuite/integration/src/test/resources/saml/testsaml.json
@@ -5,7 +5,6 @@
     "sslRequired": "external",
     "registrationAllowed": true,
     "resetPasswordAllowed": true,
-    "passwordCredentialGrantAllowed": true,
     "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
     "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
     "requiredCredentials": [ "password" ],
diff --git a/testsuite/integration/src/test/resources/testrealm.json b/testsuite/integration/src/test/resources/testrealm.json
index c9b6708..a20c18f 100755
--- a/testsuite/integration/src/test/resources/testrealm.json
+++ b/testsuite/integration/src/test/resources/testrealm.json
@@ -5,7 +5,6 @@
     "sslRequired": "external",
     "registrationAllowed": true,
     "resetPasswordAllowed": true,
-    "passwordCredentialGrantAllowed": true,
     "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
     "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
     "requiredCredentials": [ "password" ],
diff --git a/testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/ui/page/settings/GeneralSettingsPage.java b/testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/ui/page/settings/GeneralSettingsPage.java
index bfab15d..744b364 100644
--- a/testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/ui/page/settings/GeneralSettingsPage.java
+++ b/testsuite/integration-arquillian/src/test/java/org/keycloak/testsuite/ui/page/settings/GeneralSettingsPage.java
@@ -39,10 +39,7 @@ public class GeneralSettingsPage extends AbstractPage {
     
     @FindBy(id = "updateProfileOnInitialSocialLogin")
     private WebElement updateProfileOnInitialSocialLogin;
-    
-    @FindBy(id = "passwordCredentialGrantAllowed")
-    private WebElement passwordCredentialGrantAllowed;
-    
+
     @FindBy(id = "loginTheme")
     private Select loginThemeSelect;
     
diff --git a/testsuite/jetty/jetty81/src/test/java/org/keycloak/testsuite/Jetty8Test.java b/testsuite/jetty/jetty81/src/test/java/org/keycloak/testsuite/Jetty8Test.java
index 6232ae5..2453aab 100755
--- a/testsuite/jetty/jetty81/src/test/java/org/keycloak/testsuite/Jetty8Test.java
+++ b/testsuite/jetty/jetty81/src/test/java/org/keycloak/testsuite/Jetty8Test.java
@@ -66,6 +66,7 @@ public class Jetty8Test {
         File base = new File(dir.getFile()).getParentFile();
         list.add(new WebAppContext(new File(base, "customer-portal").toString(), "/customer-portal"));
         list.add(new WebAppContext(new File(base, "customer-db").toString(), "/customer-db"));
+        list.add(new WebAppContext(new File(base, "customer-db-error-page").toString(), "/customer-db-error-page"));
         list.add(new WebAppContext(new File(base, "product-portal").toString(), "/product-portal"));
         list.add(new WebAppContext(new File(base, "session-portal").toString(), "/session-portal"));
         list.add(new WebAppContext(new File(base, "input-portal").toString(), "/input-portal"));
@@ -132,6 +133,15 @@ public class Jetty8Test {
     }
 
     /**
+     * KEYCLOAK-1368
+     * @throws Exception
+     */
+    @Test
+    public void testNullBearerTokenCustomErrorPage() throws Exception {
+        testStrategy.testNullBearerTokenCustomErrorPage();
+    }
+
+    /**
      * KEYCLOAK-518
      * @throws Exception
      */
diff --git a/testsuite/jetty/jetty81/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/jetty-web.xml b/testsuite/jetty/jetty81/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/jetty-web.xml
new file mode 100755
index 0000000..1ec566d
--- /dev/null
+++ b/testsuite/jetty/jetty81/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/jetty-web.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+    <Get name="securityHandler">
+        <Set name="authenticator">
+            <New class="org.keycloak.adapters.jetty.KeycloakJettyAuthenticator">
+                <!--
+                <Set name="adapterConfig">
+                    <New class="org.keycloak.representations.adapters.config.AdapterConfig">
+                        <Set name="realm">tomcat</Set>
+                        <Set name="resource">customer-portal</Set>
+                        <Set name="authServerUrl">http://localhost:8081/auth</Set>
+                        <Set name="sslRequired">external</Set>
+                        <Set name="credentials">
+                            <Map>
+                                <Entry>
+                                    <Item>secret</Item>
+                                    <Item>password</Item>
+                                </Entry>
+                            </Map>
+                        </Set>
+                        <Set name="realmKey">MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</Set>
+                    </New>
+                </Set>
+                -->
+            </New>
+        </Set>
+    </Get>
+</Configure>
\ No newline at end of file
diff --git a/testsuite/jetty/jetty81/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/keycloak.json b/testsuite/jetty/jetty81/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/keycloak.json
new file mode 100755
index 0000000..38d1179
--- /dev/null
+++ b/testsuite/jetty/jetty81/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/keycloak.json
@@ -0,0 +1,10 @@
+{
+  "realm" : "demo",
+  "resource" : "customer-db",
+  "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+  "auth-server-url": "http://localhost:8081/auth",
+  "ssl-required" : "external",
+  "bearer-only" : true,
+  "enable-cors" : true
+
+}
diff --git a/testsuite/jetty/jetty81/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/web.xml b/testsuite/jetty/jetty81/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/web.xml
new file mode 100755
index 0000000..f44a60b
--- /dev/null
+++ b/testsuite/jetty/jetty81/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/web.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+      version="3.0">
+
+	<module-name>adapter-test</module-name>
+
+    <servlet>
+        <servlet-name>Servlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.adapter.CustomerDatabaseServlet</servlet-class>
+    </servlet>
+    <servlet>
+        <servlet-name>Error Servlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.rule.ErrorServlet</servlet-class>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>Servlet</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Error Servlet</servlet-name>
+        <url-pattern>/error.html</url-pattern>
+    </servlet-mapping>
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Users</web-resource-name>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>user</role-name>
+        </auth-constraint>
+    </security-constraint>
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Errors</web-resource-name>
+            <url-pattern>/error.html</url-pattern>
+        </web-resource-collection>
+    </security-constraint>
+
+    <login-config>
+        <auth-method>FORM</auth-method>
+        <realm-name>demo</realm-name>
+        <form-login-config>
+            <form-login-page>/error.html</form-login-page>
+            <form-error-page>/error.html</form-error-page>
+        </form-login-config>
+    </login-config>
+
+    <security-role>
+        <role-name>admin</role-name>
+    </security-role>
+    <security-role>
+        <role-name>user</role-name>
+    </security-role>
+</web-app>
diff --git a/testsuite/jetty/jetty81/src/test/resources/adapter-test/demorealm.json b/testsuite/jetty/jetty81/src/test/resources/adapter-test/demorealm.json
index 9db9064..a21838e 100755
--- a/testsuite/jetty/jetty81/src/test/resources/adapter-test/demorealm.json
+++ b/testsuite/jetty/jetty81/src/test/resources/adapter-test/demorealm.json
@@ -7,7 +7,6 @@
     "accessCodeLifespanUserAction": 6000,
     "sslRequired": "external",
     "registrationAllowed": false,
-    "passwordCredentialGrantAllowed": true,
     "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
     "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
     "requiredCredentials": [ "password" ],
diff --git a/testsuite/jetty/jetty81/src/test/resources/jetty-test/demorealm.json b/testsuite/jetty/jetty81/src/test/resources/jetty-test/demorealm.json
index ee13db5..0efd923 100755
--- a/testsuite/jetty/jetty81/src/test/resources/jetty-test/demorealm.json
+++ b/testsuite/jetty/jetty81/src/test/resources/jetty-test/demorealm.json
@@ -7,7 +7,6 @@
     "accessCodeLifespanUserAction": 6000,
     "sslRequired": "external",
     "registrationAllowed": false,
-    "passwordCredentialGrantAllowed": true,
     "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
     "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
     "requiredCredentials": [ "password" ],
diff --git a/testsuite/jetty/jetty91/src/test/java/org/keycloak/testsuite/Jetty9Test.java b/testsuite/jetty/jetty91/src/test/java/org/keycloak/testsuite/Jetty9Test.java
index 09bffc7..ba6b2e9 100755
--- a/testsuite/jetty/jetty91/src/test/java/org/keycloak/testsuite/Jetty9Test.java
+++ b/testsuite/jetty/jetty91/src/test/java/org/keycloak/testsuite/Jetty9Test.java
@@ -66,6 +66,7 @@ public class Jetty9Test {
         File base = new File(dir.getFile()).getParentFile();
         list.add(new WebAppContext(new File(base, "customer-portal").toString(), "/customer-portal"));
         list.add(new WebAppContext(new File(base, "customer-db").toString(), "/customer-db"));
+        list.add(new WebAppContext(new File(base, "customer-db-error-page").toString(), "/customer-db-error-page"));
         list.add(new WebAppContext(new File(base, "product-portal").toString(), "/product-portal"));
         list.add(new WebAppContext(new File(base, "session-portal").toString(), "/session-portal"));
         list.add(new WebAppContext(new File(base, "input-portal").toString(), "/input-portal"));
@@ -132,6 +133,15 @@ public class Jetty9Test {
     }
 
     /**
+     * KEYCLOAK-1368
+     * @throws Exception
+     */
+    @Test
+    public void testNullBearerTokenCustomErrorPage() throws Exception {
+        testStrategy.testNullBearerTokenCustomErrorPage();
+    }
+
+    /**
      * KEYCLOAK-518
      * @throws Exception
      */
diff --git a/testsuite/jetty/jetty91/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/jetty-web.xml b/testsuite/jetty/jetty91/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/jetty-web.xml
new file mode 100755
index 0000000..1ec566d
--- /dev/null
+++ b/testsuite/jetty/jetty91/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/jetty-web.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+    <Get name="securityHandler">
+        <Set name="authenticator">
+            <New class="org.keycloak.adapters.jetty.KeycloakJettyAuthenticator">
+                <!--
+                <Set name="adapterConfig">
+                    <New class="org.keycloak.representations.adapters.config.AdapterConfig">
+                        <Set name="realm">tomcat</Set>
+                        <Set name="resource">customer-portal</Set>
+                        <Set name="authServerUrl">http://localhost:8081/auth</Set>
+                        <Set name="sslRequired">external</Set>
+                        <Set name="credentials">
+                            <Map>
+                                <Entry>
+                                    <Item>secret</Item>
+                                    <Item>password</Item>
+                                </Entry>
+                            </Map>
+                        </Set>
+                        <Set name="realmKey">MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</Set>
+                    </New>
+                </Set>
+                -->
+            </New>
+        </Set>
+    </Get>
+</Configure>
\ No newline at end of file
diff --git a/testsuite/jetty/jetty91/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/keycloak.json b/testsuite/jetty/jetty91/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/keycloak.json
new file mode 100755
index 0000000..38d1179
--- /dev/null
+++ b/testsuite/jetty/jetty91/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/keycloak.json
@@ -0,0 +1,10 @@
+{
+  "realm" : "demo",
+  "resource" : "customer-db",
+  "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+  "auth-server-url": "http://localhost:8081/auth",
+  "ssl-required" : "external",
+  "bearer-only" : true,
+  "enable-cors" : true
+
+}
diff --git a/testsuite/jetty/jetty91/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/web.xml b/testsuite/jetty/jetty91/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/web.xml
new file mode 100755
index 0000000..f44a60b
--- /dev/null
+++ b/testsuite/jetty/jetty91/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/web.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+      version="3.0">
+
+	<module-name>adapter-test</module-name>
+
+    <servlet>
+        <servlet-name>Servlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.adapter.CustomerDatabaseServlet</servlet-class>
+    </servlet>
+    <servlet>
+        <servlet-name>Error Servlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.rule.ErrorServlet</servlet-class>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>Servlet</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Error Servlet</servlet-name>
+        <url-pattern>/error.html</url-pattern>
+    </servlet-mapping>
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Users</web-resource-name>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>user</role-name>
+        </auth-constraint>
+    </security-constraint>
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Errors</web-resource-name>
+            <url-pattern>/error.html</url-pattern>
+        </web-resource-collection>
+    </security-constraint>
+
+    <login-config>
+        <auth-method>FORM</auth-method>
+        <realm-name>demo</realm-name>
+        <form-login-config>
+            <form-login-page>/error.html</form-login-page>
+            <form-error-page>/error.html</form-error-page>
+        </form-login-config>
+    </login-config>
+
+    <security-role>
+        <role-name>admin</role-name>
+    </security-role>
+    <security-role>
+        <role-name>user</role-name>
+    </security-role>
+</web-app>
diff --git a/testsuite/jetty/jetty91/src/test/resources/adapter-test/demorealm.json b/testsuite/jetty/jetty91/src/test/resources/adapter-test/demorealm.json
index 9db9064..a21838e 100755
--- a/testsuite/jetty/jetty91/src/test/resources/adapter-test/demorealm.json
+++ b/testsuite/jetty/jetty91/src/test/resources/adapter-test/demorealm.json
@@ -7,7 +7,6 @@
     "accessCodeLifespanUserAction": 6000,
     "sslRequired": "external",
     "registrationAllowed": false,
-    "passwordCredentialGrantAllowed": true,
     "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
     "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
     "requiredCredentials": [ "password" ],
diff --git a/testsuite/jetty/jetty91/src/test/resources/jetty-test/demorealm.json b/testsuite/jetty/jetty91/src/test/resources/jetty-test/demorealm.json
index ee13db5..0efd923 100755
--- a/testsuite/jetty/jetty91/src/test/resources/jetty-test/demorealm.json
+++ b/testsuite/jetty/jetty91/src/test/resources/jetty-test/demorealm.json
@@ -7,7 +7,6 @@
     "accessCodeLifespanUserAction": 6000,
     "sslRequired": "external",
     "registrationAllowed": false,
-    "passwordCredentialGrantAllowed": true,
     "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
     "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
     "requiredCredentials": [ "password" ],
diff --git a/testsuite/jetty/jetty92/src/test/java/org/keycloak/testsuite/Jetty9Test.java b/testsuite/jetty/jetty92/src/test/java/org/keycloak/testsuite/Jetty9Test.java
index 26db13a..037769f 100755
--- a/testsuite/jetty/jetty92/src/test/java/org/keycloak/testsuite/Jetty9Test.java
+++ b/testsuite/jetty/jetty92/src/test/java/org/keycloak/testsuite/Jetty9Test.java
@@ -66,6 +66,7 @@ public class Jetty9Test {
         File base = new File(dir.getFile()).getParentFile();
         list.add(new WebAppContext(new File(base, "customer-portal").toString(), "/customer-portal"));
         list.add(new WebAppContext(new File(base, "customer-db").toString(), "/customer-db"));
+        list.add(new WebAppContext(new File(base, "customer-db-error-page").toString(), "/customer-db-error-page"));
         list.add(new WebAppContext(new File(base, "product-portal").toString(), "/product-portal"));
         list.add(new WebAppContext(new File(base, "session-portal").toString(), "/session-portal"));
         list.add(new WebAppContext(new File(base, "input-portal").toString(), "/input-portal"));
@@ -132,6 +133,15 @@ public class Jetty9Test {
     }
 
     /**
+     * KEYCLOAK-1368
+     * @throws Exception
+     */
+    @Test
+    public void testNullBearerTokenCustomErrorPage() throws Exception {
+        testStrategy.testNullBearerTokenCustomErrorPage();
+    }
+
+    /**
      * KEYCLOAK-518
      * @throws Exception
      */
diff --git a/testsuite/jetty/jetty92/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/jetty-web.xml b/testsuite/jetty/jetty92/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/jetty-web.xml
new file mode 100755
index 0000000..1ec566d
--- /dev/null
+++ b/testsuite/jetty/jetty92/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/jetty-web.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+    <Get name="securityHandler">
+        <Set name="authenticator">
+            <New class="org.keycloak.adapters.jetty.KeycloakJettyAuthenticator">
+                <!--
+                <Set name="adapterConfig">
+                    <New class="org.keycloak.representations.adapters.config.AdapterConfig">
+                        <Set name="realm">tomcat</Set>
+                        <Set name="resource">customer-portal</Set>
+                        <Set name="authServerUrl">http://localhost:8081/auth</Set>
+                        <Set name="sslRequired">external</Set>
+                        <Set name="credentials">
+                            <Map>
+                                <Entry>
+                                    <Item>secret</Item>
+                                    <Item>password</Item>
+                                </Entry>
+                            </Map>
+                        </Set>
+                        <Set name="realmKey">MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</Set>
+                    </New>
+                </Set>
+                -->
+            </New>
+        </Set>
+    </Get>
+</Configure>
\ No newline at end of file
diff --git a/testsuite/jetty/jetty92/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/keycloak.json b/testsuite/jetty/jetty92/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/keycloak.json
new file mode 100755
index 0000000..38d1179
--- /dev/null
+++ b/testsuite/jetty/jetty92/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/keycloak.json
@@ -0,0 +1,10 @@
+{
+  "realm" : "demo",
+  "resource" : "customer-db",
+  "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+  "auth-server-url": "http://localhost:8081/auth",
+  "ssl-required" : "external",
+  "bearer-only" : true,
+  "enable-cors" : true
+
+}
diff --git a/testsuite/jetty/jetty92/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/web.xml b/testsuite/jetty/jetty92/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/web.xml
new file mode 100755
index 0000000..f44a60b
--- /dev/null
+++ b/testsuite/jetty/jetty92/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/web.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+      version="3.0">
+
+	<module-name>adapter-test</module-name>
+
+    <servlet>
+        <servlet-name>Servlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.adapter.CustomerDatabaseServlet</servlet-class>
+    </servlet>
+    <servlet>
+        <servlet-name>Error Servlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.rule.ErrorServlet</servlet-class>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>Servlet</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Error Servlet</servlet-name>
+        <url-pattern>/error.html</url-pattern>
+    </servlet-mapping>
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Users</web-resource-name>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>user</role-name>
+        </auth-constraint>
+    </security-constraint>
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Errors</web-resource-name>
+            <url-pattern>/error.html</url-pattern>
+        </web-resource-collection>
+    </security-constraint>
+
+    <login-config>
+        <auth-method>FORM</auth-method>
+        <realm-name>demo</realm-name>
+        <form-login-config>
+            <form-login-page>/error.html</form-login-page>
+            <form-error-page>/error.html</form-error-page>
+        </form-login-config>
+    </login-config>
+
+    <security-role>
+        <role-name>admin</role-name>
+    </security-role>
+    <security-role>
+        <role-name>user</role-name>
+    </security-role>
+</web-app>
diff --git a/testsuite/jetty/jetty92/src/test/resources/adapter-test/demorealm.json b/testsuite/jetty/jetty92/src/test/resources/adapter-test/demorealm.json
index 9db9064..a21838e 100755
--- a/testsuite/jetty/jetty92/src/test/resources/adapter-test/demorealm.json
+++ b/testsuite/jetty/jetty92/src/test/resources/adapter-test/demorealm.json
@@ -7,7 +7,6 @@
     "accessCodeLifespanUserAction": 6000,
     "sslRequired": "external",
     "registrationAllowed": false,
-    "passwordCredentialGrantAllowed": true,
     "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
     "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
     "requiredCredentials": [ "password" ],
diff --git a/testsuite/proxy/src/test/resources/demorealm.json b/testsuite/proxy/src/test/resources/demorealm.json
index 5c83e0f..bb66dc8 100755
--- a/testsuite/proxy/src/test/resources/demorealm.json
+++ b/testsuite/proxy/src/test/resources/demorealm.json
@@ -7,7 +7,6 @@
     "accessCodeLifespanUserAction": 6000,
     "sslRequired": "external",
     "registrationAllowed": false,
-    "passwordCredentialGrantAllowed": true,
     "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
     "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
     "requiredCredentials": [ "password" ],
diff --git a/testsuite/tomcat6/src/test/java/org/keycloak/testsuite/TomcatTest.java b/testsuite/tomcat6/src/test/java/org/keycloak/testsuite/TomcatTest.java
index 5393b65..e28a2f6 100755
--- a/testsuite/tomcat6/src/test/java/org/keycloak/testsuite/TomcatTest.java
+++ b/testsuite/tomcat6/src/test/java/org/keycloak/testsuite/TomcatTest.java
@@ -60,6 +60,7 @@ public class TomcatTest {
         System.setProperty("my.host.name", "localhost");
         tomcat.deploy("/customer-portal", "customer-portal");
         tomcat.deploy("/customer-db", "customer-db");
+        tomcat.deploy("/customer-db-error-page", "customer-db-error-page");
         tomcat.deploy("/product-portal", "product-portal");
         tomcat.deploy("/secure-portal", "secure-portal");
         tomcat.deploy("/session-portal", "session-portal");
@@ -120,6 +121,15 @@ public class TomcatTest {
     }
 
     /**
+     * KEYCLOAK-1368
+     * @throws Exception
+     */
+    @Test
+    public void testNullBearerTokenCustomErrorPage() throws Exception {
+        testStrategy.testNullBearerTokenCustomErrorPage();
+    }
+
+    /**
      * KEYCLOAK-518
      * @throws Exception
      */
diff --git a/testsuite/tomcat6/src/test/resources/adapter-test/customer-db-error-page/META-INF/context.xml b/testsuite/tomcat6/src/test/resources/adapter-test/customer-db-error-page/META-INF/context.xml
new file mode 100755
index 0000000..5066a55
--- /dev/null
+++ b/testsuite/tomcat6/src/test/resources/adapter-test/customer-db-error-page/META-INF/context.xml
@@ -0,0 +1,3 @@
+<Context path="/customer-db-error-page">
+    <Valve className="org.keycloak.adapters.tomcat.KeycloakAuthenticatorValve"/>
+</Context>
\ No newline at end of file
diff --git a/testsuite/tomcat6/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/keycloak.json b/testsuite/tomcat6/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/keycloak.json
new file mode 100755
index 0000000..38d1179
--- /dev/null
+++ b/testsuite/tomcat6/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/keycloak.json
@@ -0,0 +1,10 @@
+{
+  "realm" : "demo",
+  "resource" : "customer-db",
+  "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+  "auth-server-url": "http://localhost:8081/auth",
+  "ssl-required" : "external",
+  "bearer-only" : true,
+  "enable-cors" : true
+
+}
diff --git a/testsuite/tomcat6/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/web.xml b/testsuite/tomcat6/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/web.xml
new file mode 100755
index 0000000..c2cef86
--- /dev/null
+++ b/testsuite/tomcat6/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/web.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+      version="3.0">
+
+	<module-name>adapter-test</module-name>
+
+    <servlet>
+        <servlet-name>Servlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.adapter.CustomerDatabaseServlet</servlet-class>
+    </servlet>
+    <servlet>
+        <servlet-name>Error Servlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.rule.ErrorServlet</servlet-class>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>Servlet</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Error Servlet</servlet-name>
+        <url-pattern>/error.html</url-pattern>
+    </servlet-mapping>
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Users</web-resource-name>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>user</role-name>
+        </auth-constraint>
+    </security-constraint>
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Errors</web-resource-name>
+            <url-pattern>/error.html</url-pattern>
+        </web-resource-collection>
+    </security-constraint>
+
+    <login-config>
+        <auth-method>BASIC</auth-method>
+        <realm-name>demo</realm-name>
+        <form-login-config>
+            <form-login-page>/error.html</form-login-page>
+            <form-error-page>/error.html</form-error-page>
+        </form-login-config>
+    </login-config>
+
+    <security-role>
+        <role-name>admin</role-name>
+    </security-role>
+    <security-role>
+        <role-name>user</role-name>
+    </security-role>
+</web-app>
diff --git a/testsuite/tomcat6/src/test/resources/adapter-test/demorealm.json b/testsuite/tomcat6/src/test/resources/adapter-test/demorealm.json
index 9db9064..a21838e 100755
--- a/testsuite/tomcat6/src/test/resources/adapter-test/demorealm.json
+++ b/testsuite/tomcat6/src/test/resources/adapter-test/demorealm.json
@@ -7,7 +7,6 @@
     "accessCodeLifespanUserAction": 6000,
     "sslRequired": "external",
     "registrationAllowed": false,
-    "passwordCredentialGrantAllowed": true,
     "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
     "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
     "requiredCredentials": [ "password" ],
diff --git a/testsuite/tomcat7/src/test/java/org/keycloak/testsuite/Tomcat7Test.java b/testsuite/tomcat7/src/test/java/org/keycloak/testsuite/Tomcat7Test.java
index 3f20d16..b67c2fc 100755
--- a/testsuite/tomcat7/src/test/java/org/keycloak/testsuite/Tomcat7Test.java
+++ b/testsuite/tomcat7/src/test/java/org/keycloak/testsuite/Tomcat7Test.java
@@ -65,6 +65,7 @@ public class Tomcat7Test {
         File base = new File(dir.getFile()).getParentFile();
         tomcat.addWebapp("/customer-portal", new File(base, "customer-portal").toString());
         tomcat.addWebapp("/customer-db", new File(base, "customer-db").toString());
+        tomcat.addWebapp("/customer-db-error-page", new File(base, "customer-db-error-page").toString());
         tomcat.addWebapp("/product-portal", new File(base, "product-portal").toString());
         tomcat.addWebapp("/secure-portal", new File(base, "secure-portal").toString());
         tomcat.addWebapp("/session-portal", new File(base, "session-portal").toString());
@@ -125,6 +126,16 @@ public class Tomcat7Test {
     }
 
     /**
+     * KEYCLOAK-1368
+     * @throws Exception
+     */
+    @Test
+    public void testNullBearerTokenCustomErrorPage() throws Exception {
+        testStrategy.testNullBearerTokenCustomErrorPage();
+    }
+
+
+    /**
      * KEYCLOAK-518
      * @throws Exception
      */
diff --git a/testsuite/tomcat7/src/test/resources/adapter-test/customer-db-error-page/META-INF/context.xml b/testsuite/tomcat7/src/test/resources/adapter-test/customer-db-error-page/META-INF/context.xml
new file mode 100755
index 0000000..5066a55
--- /dev/null
+++ b/testsuite/tomcat7/src/test/resources/adapter-test/customer-db-error-page/META-INF/context.xml
@@ -0,0 +1,3 @@
+<Context path="/customer-db-error-page">
+    <Valve className="org.keycloak.adapters.tomcat.KeycloakAuthenticatorValve"/>
+</Context>
\ No newline at end of file
diff --git a/testsuite/tomcat7/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/keycloak.json b/testsuite/tomcat7/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/keycloak.json
new file mode 100755
index 0000000..38d1179
--- /dev/null
+++ b/testsuite/tomcat7/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/keycloak.json
@@ -0,0 +1,10 @@
+{
+  "realm" : "demo",
+  "resource" : "customer-db",
+  "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+  "auth-server-url": "http://localhost:8081/auth",
+  "ssl-required" : "external",
+  "bearer-only" : true,
+  "enable-cors" : true
+
+}
diff --git a/testsuite/tomcat7/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/web.xml b/testsuite/tomcat7/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/web.xml
new file mode 100755
index 0000000..c2cef86
--- /dev/null
+++ b/testsuite/tomcat7/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/web.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+      version="3.0">
+
+	<module-name>adapter-test</module-name>
+
+    <servlet>
+        <servlet-name>Servlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.adapter.CustomerDatabaseServlet</servlet-class>
+    </servlet>
+    <servlet>
+        <servlet-name>Error Servlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.rule.ErrorServlet</servlet-class>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>Servlet</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Error Servlet</servlet-name>
+        <url-pattern>/error.html</url-pattern>
+    </servlet-mapping>
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Users</web-resource-name>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>user</role-name>
+        </auth-constraint>
+    </security-constraint>
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Errors</web-resource-name>
+            <url-pattern>/error.html</url-pattern>
+        </web-resource-collection>
+    </security-constraint>
+
+    <login-config>
+        <auth-method>BASIC</auth-method>
+        <realm-name>demo</realm-name>
+        <form-login-config>
+            <form-login-page>/error.html</form-login-page>
+            <form-error-page>/error.html</form-error-page>
+        </form-login-config>
+    </login-config>
+
+    <security-role>
+        <role-name>admin</role-name>
+    </security-role>
+    <security-role>
+        <role-name>user</role-name>
+    </security-role>
+</web-app>
diff --git a/testsuite/tomcat7/src/test/resources/adapter-test/demorealm.json b/testsuite/tomcat7/src/test/resources/adapter-test/demorealm.json
index 9db9064..a21838e 100755
--- a/testsuite/tomcat7/src/test/resources/adapter-test/demorealm.json
+++ b/testsuite/tomcat7/src/test/resources/adapter-test/demorealm.json
@@ -7,7 +7,6 @@
     "accessCodeLifespanUserAction": 6000,
     "sslRequired": "external",
     "registrationAllowed": false,
-    "passwordCredentialGrantAllowed": true,
     "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
     "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
     "requiredCredentials": [ "password" ],
diff --git a/testsuite/tomcat8/src/test/java/org/keycloak/testsuite/TomcatTest.java b/testsuite/tomcat8/src/test/java/org/keycloak/testsuite/TomcatTest.java
index 8c1372a..0168f04 100755
--- a/testsuite/tomcat8/src/test/java/org/keycloak/testsuite/TomcatTest.java
+++ b/testsuite/tomcat8/src/test/java/org/keycloak/testsuite/TomcatTest.java
@@ -64,6 +64,7 @@ public class TomcatTest {
         File base = new File(dir.getFile()).getParentFile();
         tomcat.addWebapp("/customer-portal", new File(base, "customer-portal").toString());
         tomcat.addWebapp("/customer-db", new File(base, "customer-db").toString());
+        tomcat.addWebapp("/customer-db-error-page", new File(base, "customer-db-error-page").toString());
         tomcat.addWebapp("/product-portal", new File(base, "product-portal").toString());
         tomcat.addWebapp("/secure-portal", new File(base, "secure-portal").toString());
         tomcat.addWebapp("/session-portal", new File(base, "session-portal").toString());
@@ -125,6 +126,15 @@ public class TomcatTest {
     }
 
     /**
+     * KEYCLOAK-1368
+     * @throws Exception
+     */
+    @Test
+    public void testNullBearerTokenCustomErrorPage() throws Exception {
+        testStrategy.testNullBearerTokenCustomErrorPage();
+    }
+
+    /**
      * KEYCLOAK-518
      * @throws Exception
      */
diff --git a/testsuite/tomcat8/src/test/resources/adapter-test/customer-db-error-page/META-INF/context.xml b/testsuite/tomcat8/src/test/resources/adapter-test/customer-db-error-page/META-INF/context.xml
new file mode 100755
index 0000000..5066a55
--- /dev/null
+++ b/testsuite/tomcat8/src/test/resources/adapter-test/customer-db-error-page/META-INF/context.xml
@@ -0,0 +1,3 @@
+<Context path="/customer-db-error-page">
+    <Valve className="org.keycloak.adapters.tomcat.KeycloakAuthenticatorValve"/>
+</Context>
\ No newline at end of file
diff --git a/testsuite/tomcat8/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/keycloak.json b/testsuite/tomcat8/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/keycloak.json
new file mode 100755
index 0000000..38d1179
--- /dev/null
+++ b/testsuite/tomcat8/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/keycloak.json
@@ -0,0 +1,10 @@
+{
+  "realm" : "demo",
+  "resource" : "customer-db",
+  "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+  "auth-server-url": "http://localhost:8081/auth",
+  "ssl-required" : "external",
+  "bearer-only" : true,
+  "enable-cors" : true
+
+}
diff --git a/testsuite/tomcat8/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/web.xml b/testsuite/tomcat8/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/web.xml
new file mode 100755
index 0000000..c2cef86
--- /dev/null
+++ b/testsuite/tomcat8/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/web.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+      version="3.0">
+
+	<module-name>adapter-test</module-name>
+
+    <servlet>
+        <servlet-name>Servlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.adapter.CustomerDatabaseServlet</servlet-class>
+    </servlet>
+    <servlet>
+        <servlet-name>Error Servlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.rule.ErrorServlet</servlet-class>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>Servlet</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Error Servlet</servlet-name>
+        <url-pattern>/error.html</url-pattern>
+    </servlet-mapping>
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Users</web-resource-name>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>user</role-name>
+        </auth-constraint>
+    </security-constraint>
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Errors</web-resource-name>
+            <url-pattern>/error.html</url-pattern>
+        </web-resource-collection>
+    </security-constraint>
+
+    <login-config>
+        <auth-method>BASIC</auth-method>
+        <realm-name>demo</realm-name>
+        <form-login-config>
+            <form-login-page>/error.html</form-login-page>
+            <form-error-page>/error.html</form-error-page>
+        </form-login-config>
+    </login-config>
+
+    <security-role>
+        <role-name>admin</role-name>
+    </security-role>
+    <security-role>
+        <role-name>user</role-name>
+    </security-role>
+</web-app>
diff --git a/testsuite/tomcat8/src/test/resources/adapter-test/demorealm.json b/testsuite/tomcat8/src/test/resources/adapter-test/demorealm.json
index 9db9064..a21838e 100755
--- a/testsuite/tomcat8/src/test/resources/adapter-test/demorealm.json
+++ b/testsuite/tomcat8/src/test/resources/adapter-test/demorealm.json
@@ -7,7 +7,6 @@
     "accessCodeLifespanUserAction": 6000,
     "sslRequired": "external",
     "registrationAllowed": false,
-    "passwordCredentialGrantAllowed": true,
     "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
     "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
     "requiredCredentials": [ "password" ],
diff --git a/testsuite/tomcat8/src/test/resources/tomcat-test/demorealm.json b/testsuite/tomcat8/src/test/resources/tomcat-test/demorealm.json
index ee13db5..0efd923 100755
--- a/testsuite/tomcat8/src/test/resources/tomcat-test/demorealm.json
+++ b/testsuite/tomcat8/src/test/resources/tomcat-test/demorealm.json
@@ -7,7 +7,6 @@
     "accessCodeLifespanUserAction": 6000,
     "sslRequired": "external",
     "registrationAllowed": false,
-    "passwordCredentialGrantAllowed": true,
     "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
     "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
     "requiredCredentials": [ "password" ],
diff --git a/timer/api/src/main/java/org/keycloak/timer/TimerSpi.java b/timer/api/src/main/java/org/keycloak/timer/TimerSpi.java
index ac92339..eb70763 100644
--- a/timer/api/src/main/java/org/keycloak/timer/TimerSpi.java
+++ b/timer/api/src/main/java/org/keycloak/timer/TimerSpi.java
@@ -10,7 +10,7 @@ import org.keycloak.provider.Spi;
 public class TimerSpi implements Spi {
 
     @Override
-    public boolean isPrivate() {
+    public boolean isInternal() {
         return true;
     }