keycloak-aplcache

broker refactor

3/20/2015 7:56:25 PM

Changes

broker/core/src/main/java/org/keycloak/broker/provider/AuthenticationResponse.java 60(+0 -60)

broker/oidc/pom.xml 17(+17 -0)

examples/pom.xml 1(+1 -0)

forms/common-freemarker/src/main/java/org/keycloak/freemarker/beans/TextFormatterBean.java 19(+0 -19)

forms/common-themes/src/main/java/org/keycloak/theme/DefaultKeycloakThemeProvider.java 79(+0 -79)

forms/common-themes/src/main/java/org/keycloak/theme/DefaultKeycloakThemeProviderFactory.java 41(+0 -41)

integration/admin-client/src/main/java/org/keycloak/admin/client/resource/KeycloakAdminFactory.java 27(+0 -27)

project-integrations/aerogear-ups/auth-server/src/main/java/org/aerogear/ups/security/AerogearThemeProviderFactory.java 40(+0 -40)

project-integrations/aerogear-ups/auth-server/src/main/resources/META-INF/services/org.keycloak.freemarker.ThemeProviderFactory 1(+0 -1)

Details

diff --git a/broker/core/src/main/java/org/keycloak/broker/provider/AbstractIdentityProvider.java b/broker/core/src/main/java/org/keycloak/broker/provider/AbstractIdentityProvider.java
index 407c659..1d9b5d1 100755
--- a/broker/core/src/main/java/org/keycloak/broker/provider/AbstractIdentityProvider.java
+++ b/broker/core/src/main/java/org/keycloak/broker/provider/AbstractIdentityProvider.java
@@ -50,12 +50,12 @@ public abstract class AbstractIdentityProvider<C extends IdentityProviderModel> 
     }
 
     @Override
-    public Object callback(RealmModel realm, Callback callback) {
+    public Object callback(RealmModel realm, AuthenticationCallback callback) {
         return null;
     }
 
     @Override
-    public Response logout(UserSessionModel userSession, UriInfo uriInfo, RealmModel realm) {
+    public Response keycloakInitiatedBrowserLogout(UserSessionModel userSession, UriInfo uriInfo, RealmModel realm) {
         return null;
     }
 }
diff --git a/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProvider.java b/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProvider.java
index 14d6b5f..6b5f466 100755
--- a/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProvider.java
+++ b/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProvider.java
@@ -32,16 +32,26 @@ import java.util.Map;
  */
 public interface IdentityProvider<C extends IdentityProviderModel> extends Provider {
 
-    public interface Callback {
+    public interface AuthenticationCallback {
+        /**
+         * This method should be called by provider after the JAXRS callback endpoint has finished authentication
+         * with the remote IDP
+         *
+         * @param userNotes notes to add to the UserSessionModel
+         * @param identityProviderConfig provider config
+         * @param federatedIdentity federated identity
+         * @param code relayState or state parameter used to identity the client session
+         * @return
+         */
         public Response authenticated(Map<String, String> userNotes, IdentityProviderModel identityProviderConfig, FederatedIdentity federatedIdentity, String code);
     }
 
     /**
-     * JAXRS callback endpoint
+     * JAXRS callback endpoint for when the remote IDP wants to callback to keycloak.
      *
      * @return
      */
-    Object callback(RealmModel realm, Callback callback);
+    Object callback(RealmModel realm, AuthenticationCallback callback);
 
     /**
      * <p>Initiates the authentication process by sending an authentication request to an identity provider. This method is called
@@ -57,31 +67,7 @@ public interface IdentityProvider<C extends IdentityProviderModel> extends Provi
  *                    identity provider.
      * @return
      */
-    AuthenticationResponse handleRequest(AuthenticationRequest request);
-
-    /**
-     * <p>Obtains state information sent to the identity provider during the authentication request. Implementations must always
-     * return the same state in order to check the validity of a response from the identity provider.</p>
-     *
-     * <p>This method is invoked on each response from the identity provider.</p>
-     *
-     * @param request The request sent by the identity provider in a response to an authentication request.
-     * @return
-     */
-    String getRelayState(AuthenticationRequest request);
-
-    /**
-     * <p>Handles a response from the identity provider after a successful authentication request is made. Usually, the response will
-     * contain all the necessary information in order to trust the authentication performed by the identity provider and resolve
-     * the identity information for the authenticating user.</p>
-     *
-     * <p>If the response is trusted and proves user's authenticity, this method may return a
-     * {@link FederatedIdentity} in the response. In this case, the authentication flow stops.</p>
-     *
-     * @param request
-     * @return
-     */
-    AuthenticationResponse handleResponse(AuthenticationRequest request);
+    Response handleRequest(AuthenticationRequest request);
 
     /**
      * <p>Returns a {@link javax.ws.rs.core.Response} containing the token previously stored during the authentication process for a
@@ -92,7 +78,16 @@ public interface IdentityProvider<C extends IdentityProviderModel> extends Provi
      */
     Response retrieveToken(FederatedIdentityModel identity);
 
-    Response logout(UserSessionModel userSession, UriInfo uriInfo, RealmModel realm);
+    /**
+     * Called when a Keycloak application initiates a logout through the browser.  This is expected to do a logout
+     * with the IDP
+     *
+     * @param userSession
+     * @param uriInfo
+     * @param realm
+     * @return null if this is not supported by this provider
+     */
+    Response keycloakInitiatedBrowserLogout(UserSessionModel userSession, UriInfo uriInfo, RealmModel realm);
 
     /**
      * Export a representation of the IdentityProvider in a specific format.  For example, a SAML EntityDescriptor

broker/oidc/pom.xml 17(+17 -0)

diff --git a/broker/oidc/pom.xml b/broker/oidc/pom.xml
index 594fc45..478cb47 100755
--- a/broker/oidc/pom.xml
+++ b/broker/oidc/pom.xml
@@ -30,6 +30,23 @@
             <artifactId>jackson-mapper-asl</artifactId>
             <scope>provided</scope>
         </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-events-api</artifactId>
+            <version>${project.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-services</artifactId>
+            <version>${project.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.logging</groupId>
+            <artifactId>jboss-logging</artifactId>
+            <scope>provided</scope>
+        </dependency>
     </dependencies>
 
 </project>
diff --git a/broker/oidc/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java b/broker/oidc/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java
old mode 100644
new mode 100755
index 34075e9..f2245e3
--- a/broker/oidc/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java
+++ b/broker/oidc/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java
@@ -19,20 +19,34 @@ package org.keycloak.broker.oidc;
 
 import org.codehaus.jackson.JsonNode;
 import org.codehaus.jackson.map.ObjectMapper;
+import org.jboss.resteasy.logging.Logger;
+import org.keycloak.ClientConnection;
 import org.keycloak.OAuth2Constants;
 import org.keycloak.broker.oidc.util.SimpleHttp;
 import org.keycloak.broker.provider.AbstractIdentityProvider;
 import org.keycloak.broker.provider.AuthenticationRequest;
-import org.keycloak.broker.provider.AuthenticationResponse;
 import org.keycloak.broker.provider.FederatedIdentity;
 import org.keycloak.broker.provider.IdentityBrokerException;
+import org.keycloak.events.Errors;
+import org.keycloak.events.EventBuilder;
+import org.keycloak.events.EventType;
 import org.keycloak.models.FederatedIdentityModel;
-
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.services.managers.EventsManager;
+import org.keycloak.services.messages.Messages;
+import org.keycloak.services.resources.flows.Flows;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriBuilder;
 import javax.ws.rs.core.UriInfo;
 import java.io.IOException;
 import java.net.URI;
+import java.util.HashMap;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -40,6 +54,7 @@ import java.util.regex.Pattern;
  * @author Pedro Igor
  */
 public abstract class AbstractOAuth2IdentityProvider<C extends OAuth2IdentityProviderConfig> extends AbstractIdentityProvider<C> {
+    protected static final Logger logger = Logger.getLogger(AbstractOAuth2IdentityProvider.class);
 
     public static final String OAUTH2_GRANT_TYPE_AUTHORIZATION_CODE = "authorization_code";
     protected static ObjectMapper mapper = new ObjectMapper();
@@ -54,6 +69,8 @@ public abstract class AbstractOAuth2IdentityProvider<C extends OAuth2IdentityPro
     public static final String OAUTH2_PARAMETER_CLIENT_SECRET = "client_secret";
     public static final String OAUTH2_PARAMETER_GRANT_TYPE = "grant_type";
 
+    protected AuthenticationCallback callback;
+
     public AbstractOAuth2IdentityProvider(C config) {
         super(config);
 
@@ -63,58 +80,19 @@ public abstract class AbstractOAuth2IdentityProvider<C extends OAuth2IdentityPro
     }
 
     @Override
-    public AuthenticationResponse handleRequest(AuthenticationRequest request) {
-        try {
-            URI authorizationUrl = createAuthorizationUrl(request).build();
-
-            return AuthenticationResponse.temporaryRedirect(authorizationUrl);
-        } catch (Exception e) {
-            throw new IdentityBrokerException("Could not create authentication request.", e);
-        }
-    }
-
-    @Override
-    public String getRelayState(AuthenticationRequest request) {
-        UriInfo uriInfo = request.getUriInfo();
-        return uriInfo.getQueryParameters().getFirst(OAUTH2_PARAMETER_STATE);
+    public Object callback(RealmModel realm, AuthenticationCallback callback) {
+        this.callback = callback;
+        return new Endpoint(realm);
     }
 
     @Override
-    public AuthenticationResponse handleResponse(AuthenticationRequest request) {
-        UriInfo uriInfo = request.getUriInfo();
-        String error = uriInfo.getQueryParameters().getFirst(OAuth2Constants.ERROR);
-
-        if (error != null) {
-            if (error.equals("access_denied")) {
-                throw new IdentityBrokerException("Access denied.");
-            } else {
-                throw new IdentityBrokerException(error);
-            }
-        }
-
+    public Response handleRequest(AuthenticationRequest request) {
         try {
-            String authorizationCode = uriInfo.getQueryParameters().getFirst(OAUTH2_PARAMETER_CODE);
-
-            if (authorizationCode != null) {
-                String response = SimpleHttp.doPost(getConfig().getTokenUrl())
-                        .param(OAUTH2_PARAMETER_CODE, authorizationCode)
-                        .param(OAUTH2_PARAMETER_CLIENT_ID, getConfig().getClientId())
-                        .param(OAUTH2_PARAMETER_CLIENT_SECRET, getConfig().getClientSecret())
-                        .param(OAUTH2_PARAMETER_REDIRECT_URI, request.getRedirectUri())
-                        .param(OAUTH2_PARAMETER_GRANT_TYPE, OAUTH2_GRANT_TYPE_AUTHORIZATION_CODE).asString();
-
-                FederatedIdentity federatedIdentity = getFederatedIdentity(response);
-
-                if (getConfig().isStoreToken()) {
-                    federatedIdentity.setToken(response);
-                }
-
-                return AuthenticationResponse.end(federatedIdentity);
-            }
+            URI authorizationUrl = createAuthorizationUrl(request).build();
 
-            throw new IdentityBrokerException("No authorization code from identity provider.");
+            return Response.temporaryRedirect(authorizationUrl).build();
         } catch (Exception e) {
-            throw new IdentityBrokerException("Could not process response from identity provider.", e);
+            throw new IdentityBrokerException("Could not create authentication request.", e);
         }
     }
 
@@ -184,4 +162,63 @@ public abstract class AbstractOAuth2IdentityProvider<C extends OAuth2IdentityPro
     }
 
     protected abstract String getDefaultScopes();
+
+    protected class Endpoint {
+        protected RealmModel realm;
+
+        @Context
+        protected KeycloakSession session;
+
+        @Context
+        protected ClientConnection clientConnection;
+
+        @Context
+        protected HttpHeaders headers;
+
+        @Context
+        protected UriInfo uriInfo;
+
+        public Endpoint(RealmModel realm) {
+            this.realm = realm;
+        }
+
+        @GET
+        public Response authResponse(@QueryParam(AbstractOAuth2IdentityProvider.OAUTH2_PARAMETER_STATE) String state,
+                                     @QueryParam(AbstractOAuth2IdentityProvider.OAUTH2_PARAMETER_CODE) String authorizationCode,
+                                     @QueryParam(OAuth2Constants.ERROR) String error) {
+
+            EventBuilder event = new EventsManager(realm, session, clientConnection).createEventBuilder();
+            if (error != null) {
+                //logger.error("Failed " + getConfig().getAlias() + " broker login: " + error);
+                event.event(EventType.LOGIN);
+                event.error(error);
+                return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.IDENTITY_PROVIDER_UNEXPECTED_ERROR);
+            }
+
+            try {
+
+                if (authorizationCode != null) {
+                    String response = SimpleHttp.doPost(getConfig().getTokenUrl())
+                            .param(OAUTH2_PARAMETER_CODE, authorizationCode)
+                            .param(OAUTH2_PARAMETER_CLIENT_ID, getConfig().getClientId())
+                            .param(OAUTH2_PARAMETER_CLIENT_SECRET, getConfig().getClientSecret())
+                            .param(OAUTH2_PARAMETER_REDIRECT_URI, uriInfo.getAbsolutePath().toString())
+                            .param(OAUTH2_PARAMETER_GRANT_TYPE, OAUTH2_GRANT_TYPE_AUTHORIZATION_CODE).asString();
+
+                    FederatedIdentity federatedIdentity = getFederatedIdentity(response);
+
+                    if (getConfig().isStoreToken()) {
+                        federatedIdentity.setToken(response);
+                    }
+
+                    return callback.authenticated(new HashMap<String, String>(), getConfig(), federatedIdentity, state);
+                }
+            } catch (Exception e) {
+                logger.error("Failed to make identity provider oauth callback", e);
+            }
+            event.event(EventType.LOGIN);
+            event.error(Errors.IDENTITY_PROVIDER_LOGIN_FAILURE);
+            return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.IDENTITY_PROVIDER_UNEXPECTED_ERROR);
+        }
+    }
 }
diff --git a/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLEndpoint.java b/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLEndpoint.java
index 62decc4..849b2b5 100755
--- a/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLEndpoint.java
+++ b/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLEndpoint.java
@@ -4,7 +4,6 @@ import org.jboss.logging.Logger;
 import org.jboss.resteasy.spi.HttpRequest;
 import org.keycloak.ClientConnection;
 import org.keycloak.VerificationException;
-import org.keycloak.broker.provider.AuthenticationResponse;
 import org.keycloak.broker.provider.FederatedIdentity;
 import org.keycloak.broker.provider.IdentityBrokerException;
 import org.keycloak.broker.provider.IdentityProvider;
@@ -12,7 +11,6 @@ import org.keycloak.events.Details;
 import org.keycloak.events.Errors;
 import org.keycloak.events.EventBuilder;
 import org.keycloak.events.EventType;
-import org.keycloak.models.ClientModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserSessionModel;
@@ -40,7 +38,6 @@ import org.picketlink.identity.federation.saml.v2.assertion.AuthnStatementType;
 import org.picketlink.identity.federation.saml.v2.assertion.EncryptedAssertionType;
 import org.picketlink.identity.federation.saml.v2.assertion.NameIDType;
 import org.picketlink.identity.federation.saml.v2.assertion.SubjectType;
-import org.picketlink.identity.federation.saml.v2.profiles.sso.ecp.RequestType;
 import org.picketlink.identity.federation.saml.v2.protocol.ResponseType;
 import org.picketlink.identity.federation.saml.v2.protocol.StatusResponseType;
 import org.w3c.dom.Document;
@@ -74,7 +71,7 @@ public class SAMLEndpoint {
     protected RealmModel realm;
     protected EventBuilder event;
     protected SAMLIdentityProviderConfig config;
-    protected IdentityProvider.Callback callback;
+    protected IdentityProvider.AuthenticationCallback callback;
 
     @Context
     private UriInfo uriInfo;
@@ -92,7 +89,7 @@ public class SAMLEndpoint {
     private HttpHeaders headers;
 
 
-    public SAMLEndpoint(RealmModel realm, SAMLIdentityProviderConfig config, IdentityProvider.Callback callback) {
+    public SAMLEndpoint(RealmModel realm, SAMLIdentityProviderConfig config, IdentityProvider.AuthenticationCallback callback) {
         this.realm = realm;
         this.config = config;
         this.callback = callback;
@@ -265,21 +262,21 @@ public class SAMLEndpoint {
                     logger.error("logout response validation failed", e);
                     event.event(EventType.LOGOUT);
                     event.error(Errors.INVALID_SIGNATURE);
-                    return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.INVALID_REQUESTER);
+                    return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.IDENTITY_PROVIDER_UNEXPECTED_ERROR);
                 }
             }
             if (relayState == null) {
                 logger.error("no valid user session");
                 event.event(EventType.LOGOUT);
                 event.error(Errors.USER_SESSION_NOT_FOUND);
-                return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.SESSION_NOT_ACTIVE);
+                return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.IDENTITY_PROVIDER_UNEXPECTED_ERROR);
             }
             UserSessionModel userSession = session.sessions().getUserSession(realm, relayState);
             if (userSession == null) {
                 logger.error("no valid user session");
                 event.event(EventType.LOGOUT);
                 event.error(Errors.USER_SESSION_NOT_FOUND);
-                return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.SESSION_NOT_ACTIVE);
+                return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.IDENTITY_PROVIDER_UNEXPECTED_ERROR);
             }
             if (userSession.getState() != UserSessionModel.State.LOGGING_OUT) {
                 logger.error("usersession in different state");
diff --git a/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java b/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java
index 7a9bc3b..4ac8177 100755
--- a/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java
+++ b/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java
@@ -17,87 +17,40 @@
  */
 package org.keycloak.broker.saml;
 
-import org.jboss.resteasy.spi.HttpRequest;
 import org.keycloak.broker.provider.AbstractIdentityProvider;
 import org.keycloak.broker.provider.AuthenticationRequest;
-import org.keycloak.broker.provider.AuthenticationResponse;
-import org.keycloak.broker.provider.FederatedIdentity;
 import org.keycloak.broker.provider.IdentityBrokerException;
-import org.keycloak.broker.provider.IdentityProvider;
 import org.keycloak.models.FederatedIdentityModel;
-import org.keycloak.models.IdentityProviderModel;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserSessionModel;
 import org.keycloak.protocol.saml.SAML2AuthnRequestBuilder;
 import org.keycloak.protocol.saml.SAML2LogoutRequestBuilder;
 import org.keycloak.protocol.saml.SAML2NameIDPolicyBuilder;
-import org.keycloak.services.managers.EventsManager;
-import org.picketlink.common.constants.JBossSAMLConstants;
 import org.picketlink.common.constants.JBossSAMLURIConstants;
-import org.picketlink.common.exceptions.ConfigurationException;
-import org.picketlink.common.exceptions.ParsingException;
-import org.picketlink.common.exceptions.ProcessingException;
-import org.picketlink.common.util.DocumentUtil;
-import org.picketlink.common.util.StaxParserUtil;
-import org.picketlink.identity.federation.api.saml.v2.request.SAML2Request;
-import org.picketlink.identity.federation.api.saml.v2.response.SAML2Response;
-import org.picketlink.identity.federation.api.saml.v2.sig.SAML2Signature;
-import org.picketlink.identity.federation.core.parsers.saml.SAMLParser;
-import org.picketlink.identity.federation.core.saml.v2.common.SAMLDocumentHolder;
-import org.picketlink.identity.federation.core.util.JAXPValidationUtil;
-import org.picketlink.identity.federation.core.util.XMLEncryptionUtil;
-import org.picketlink.identity.federation.core.util.XMLSignatureUtil;
-import org.picketlink.identity.federation.saml.v2.assertion.AssertionType;
-import org.picketlink.identity.federation.saml.v2.assertion.EncryptedAssertionType;
-import org.picketlink.identity.federation.saml.v2.assertion.NameIDType;
-import org.picketlink.identity.federation.saml.v2.assertion.SubjectType;
-import org.picketlink.identity.federation.saml.v2.assertion.SubjectType.STSubType;
-import org.picketlink.identity.federation.saml.v2.protocol.ResponseType;
-import org.picketlink.identity.federation.saml.v2.protocol.ResponseType.RTChoiceType;
-import org.picketlink.identity.federation.saml.v2.protocol.StatusCodeType;
-import org.picketlink.identity.federation.saml.v2.protocol.StatusDetailType;
-import org.picketlink.identity.federation.saml.v2.protocol.StatusType;
-import org.picketlink.identity.federation.web.util.PostBindingUtil;
-import org.picketlink.identity.federation.web.util.RedirectBindingUtil;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
 
 import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriBuilder;
 import javax.ws.rs.core.UriInfo;
-import javax.xml.namespace.QName;
-import java.io.IOException;
-import java.net.URLDecoder;
 import java.security.KeyPair;
 import java.security.PrivateKey;
 import java.security.PublicKey;
-import java.security.cert.X509Certificate;
-import java.util.List;
 
 /**
  * @author Pedro Igor
  */
 public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityProviderConfig> {
-
-    private static final String SAML_RESPONSE_PARAMETER = "SAMLResponse";
-    private static final String RELAY_STATE_PARAMETER = "RelayState";
-
-    private SAML2Signature saml2Signature = new SAML2Signature();
-
     public SAMLIdentityProvider(SAMLIdentityProviderConfig config) {
         super(config);
     }
 
     @Override
-    public Object callback(RealmModel realm, Callback callback) {
+    public Object callback(RealmModel realm, AuthenticationCallback callback) {
         return new SAMLEndpoint(realm, getConfig(), callback);
     }
 
     @Override
-    public AuthenticationResponse handleRequest(AuthenticationRequest request) {
+    public Response handleRequest(AuthenticationRequest request) {
         try {
             UriInfo uriInfo = request.getUriInfo();
             RealmModel realm = request.getRealm();
@@ -111,7 +64,7 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
 
             String protocolBinding = JBossSAMLURIConstants.SAML_HTTP_REDIRECT_BINDING.get();
 
-            String assertionConsumerServiceUrl = UriBuilder.fromUri(request.getRedirectUri()).path("endpoint").build().toString();
+            String assertionConsumerServiceUrl = request.getRedirectUri();
 
             if (getConfig().isPostBindingResponse()) {
                 protocolBinding = JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.get();
@@ -145,9 +98,9 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
             }
 
             if (getConfig().isPostBindingAuthnRequest()) {
-                return AuthenticationResponse.fromResponse(authnRequestBuilder.postBinding().request());
+                return authnRequestBuilder.postBinding().request();
             } else {
-                return AuthenticationResponse.fromResponse(authnRequestBuilder.redirectBinding().request());
+                return authnRequestBuilder.redirectBinding().request();
             }
         } catch (Exception e) {
             throw new IdentityBrokerException("Could not create authentication request.", e);
@@ -159,155 +112,12 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
     }
 
     @Override
-    public String getRelayState(AuthenticationRequest request) {
-        return getRequestParameter(request, RELAY_STATE_PARAMETER);
-    }
-
-    @Override
-    public AuthenticationResponse handleResponse(AuthenticationRequest request) {
-        String samlResponse = getRequestParameter(request, SAML_RESPONSE_PARAMETER);
-
-        if (samlResponse == null) {
-            throw new IdentityBrokerException("No response from SAML identity provider.");
-        }
-
-        try {
-            AssertionType assertion = getAssertion(samlResponse, request);
-            SubjectType subject = assertion.getSubject();
-            STSubType subType = subject.getSubType();
-            NameIDType subjectNameID = (NameIDType) subType.getBaseID();
-            FederatedIdentity identity = new FederatedIdentity(subjectNameID.getValue());
-
-            identity.setUsername(subjectNameID.getValue());
-
-            if (subjectNameID.getFormat().toString().equals(JBossSAMLURIConstants.NAMEID_FORMAT_EMAIL.get())) {
-                identity.setEmail(subjectNameID.getValue());
-            }
-
-            if (getConfig().isStoreToken()) {
-                identity.setToken(samlResponse);
-            }
-
-            return AuthenticationResponse.end(identity);
-        } catch (Exception e) {
-            throw new IdentityBrokerException("Could not process response from SAML identity provider.", e);
-        }
-    }
-
-    @Override
     public Response retrieveToken(FederatedIdentityModel identity) {
         return Response.ok(identity.getToken()).build();
     }
 
-    private AssertionType getAssertion(String samlResponse, AuthenticationRequest request) throws Exception {
-        SAML2Request saml2Request = new SAML2Request();
-        ResponseType responseType;
-
-        if (getConfig().isPostBindingResponse()) {
-            responseType = (ResponseType) saml2Request
-                    .getSAML2ObjectFromStream(PostBindingUtil.base64DecodeAsStream(URLDecoder.decode(samlResponse, "UTF-8")));
-        } else {
-            responseType = (ResponseType) saml2Request
-                    .getSAML2ObjectFromStream(RedirectBindingUtil.base64DeflateDecode((samlResponse)));
-        }
-
-        validateStatusResponse(responseType);
-        validateSignature(saml2Request);
-
-        List<RTChoiceType> assertions = responseType.getAssertions();
-
-        if (assertions.isEmpty()) {
-            throw new IdentityBrokerException("No assertion from response.");
-        }
-
-        RTChoiceType rtChoiceType = assertions.get(0);
-        EncryptedAssertionType encryptedAssertion = rtChoiceType.getEncryptedAssertion();
-
-        if (encryptedAssertion != null) {
-            decryptAssertion(responseType, request.getRealm().getPrivateKey());
-
-        }
-
-        return responseType.getAssertions().get(0).getAssertion();
-    }
-
-    private void validateSignature(SAML2Request saml2Request) throws ProcessingException {
-        if (getConfig().isValidateSignature()) {
-            X509Certificate certificate = XMLSignatureUtil.getX509CertificateFromKeyInfoString(getConfig().getSigningCertificate().replaceAll("\\s", ""));
-            SAMLDocumentHolder samlDocumentHolder = saml2Request.getSamlDocumentHolder();
-            Document samlDocument = samlDocumentHolder.getSamlDocument();
-
-            this.saml2Signature.validate(samlDocument, certificate.getPublicKey());
-        }
-    }
-
-    private void validateStatusResponse(ResponseType responseType) {
-        StatusType status = responseType.getStatus();
-        StatusCodeType statusCode = status.getStatusCode();
-
-        if (!JBossSAMLURIConstants.STATUS_SUCCESS.get().equals(statusCode.getValue().toString())) {
-            StatusDetailType statusDetailType = status.getStatusDetail();
-            StringBuilder detailMessage = new StringBuilder();
-
-            if (statusDetailType != null) {
-                for (Object statusDetail : statusDetailType.getAny()) {
-                    detailMessage.append(statusDetail);
-                }
-            } else {
-                detailMessage.append("none");
-            }
-
-            throw new IdentityBrokerException("Authentication failed with code [" + statusCode.getValue() + " and detail [" + detailMessage.toString() + ".");
-        }
-    }
-
-    private ResponseType decryptAssertion(ResponseType responseType, PrivateKey privateKey) throws ProcessingException {
-        SAML2Response saml2Response = new SAML2Response();
-
-        try {
-            Document doc = saml2Response.convert(responseType);
-            Element enc = DocumentUtil.getElement(doc, new QName(JBossSAMLConstants.ENCRYPTED_ASSERTION.get()));
-
-            if (enc == null) {
-                throw new IdentityBrokerException("No encrypted assertion found.");
-            }
-
-            String oldID = enc.getAttribute(JBossSAMLConstants.ID.get());
-            Document newDoc = DocumentUtil.createDocument();
-            Node importedNode = newDoc.importNode(enc, true);
-            newDoc.appendChild(importedNode);
-
-            Element decryptedDocumentElement = XMLEncryptionUtil.decryptElementInDocument(newDoc, privateKey);
-            SAMLParser parser = new SAMLParser();
-
-            JAXPValidationUtil.checkSchemaValidation(decryptedDocumentElement);
-            AssertionType assertion = (AssertionType) parser.parse(StaxParserUtil.getXMLEventReader(DocumentUtil
-                    .getNodeAsStream(decryptedDocumentElement)));
-
-            responseType.replaceAssertion(oldID, new RTChoiceType(assertion));
-
-            return responseType;
-        } catch (Exception e) {
-            throw new IdentityBrokerException("Could not decrypt assertion.", e);
-        }
-    }
-
-    private String getRequestParameter(AuthenticationRequest request, String parameterName) {
-        MultivaluedMap<String, String> requestParameters;
-
-        if (getConfig().isPostBindingResponse()) {
-            HttpRequest httpRequest = request.getHttpRequest();
-            requestParameters = httpRequest.getFormParameters();
-        } else {
-            UriInfo uriInfo = request.getUriInfo();
-            requestParameters = uriInfo.getQueryParameters();
-        }
-
-        return requestParameters.getFirst(parameterName);
-    }
-
     @Override
-    public Response logout(UserSessionModel userSession, UriInfo uriInfo, RealmModel realm) {
+    public Response keycloakInitiatedBrowserLogout(UserSessionModel userSession, UriInfo uriInfo, RealmModel realm) {
         if (getConfig().getSingleLogoutServiceUrl() == null) return null;
 
         SAML2LogoutRequestBuilder logoutBuilder = new SAML2LogoutRequestBuilder()
@@ -351,7 +161,6 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
                 "            protocolSupportEnumeration=\"urn:oasis:names:tc:SAML:2.0:protocol urn:oasis:names:tc:SAML:1.1:protocol http://schemas.xmlsoap.org/ws/2003/07/secext\">\n" +
                 "        <NameIDFormat>" + getConfig().getNameIDPolicyFormat() + "\n" +
                 "        </NameIDFormat>\n" +
-// todo single logout service description
                 "        <SingleLogoutService Binding=\"" + authnBinding + "\" Location=\"" + endpoint + "\"/>\n" +
                 "        <AssertionConsumerService\n" +
                 "                Binding=\"" + authnBinding + "\" Location=\"" + endpoint + "\"\n" +
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 649ad7e..464dcca 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
@@ -10,7 +10,7 @@ import org.keycloak.Config;
 import org.keycloak.connections.mongo.api.MongoStore;
 import org.keycloak.connections.mongo.impl.MongoStoreImpl;
 import org.keycloak.connections.mongo.impl.context.TransactionMongoStoreInvocationContext;
-import org.keycloak.connections.mongo.updater.DefaultMongoUpdaterProvider;
+import org.keycloak.connections.mongo.updater.MongoUpdaterProvider;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.KeycloakSessionFactory;
 
@@ -51,7 +51,7 @@ public class DefaultMongoConnectionFactoryProvider implements MongoConnectionPro
 
     @Override
     public MongoConnectionProvider create(KeycloakSession session) {
-        lazyInit();
+        lazyInit(session);
 
         TransactionMongoStoreInvocationContext invocationContext = new TransactionMongoStoreInvocationContext(mongoStore);
         session.getTransaction().enlist(new MongoKeycloakTransaction(invocationContext));
@@ -69,7 +69,7 @@ public class DefaultMongoConnectionFactoryProvider implements MongoConnectionPro
     }
 
 
-    private void lazyInit() {
+    private void lazyInit(KeycloakSession session) {
         if (client == null) {
             synchronized (this) {
                 if (client == null) {
@@ -94,7 +94,13 @@ public class DefaultMongoConnectionFactoryProvider implements MongoConnectionPro
                         String databaseSchema = config.get("databaseSchema");
                         if (databaseSchema != null) {
                             if (databaseSchema.equals("update")) {
-                                new DefaultMongoUpdaterProvider().update(db);
+                                MongoUpdaterProvider mongoUpdater = session.getProvider(MongoUpdaterProvider.class);
+
+                                if (mongoUpdater == null) {
+                                    throw new RuntimeException("Can't update database: Mongo updater provider not found");
+                                }
+
+                                mongoUpdater.update(session, db);
                             } else {
                                 throw new RuntimeException("Invalid value for databaseSchema: " + databaseSchema);
                             }
diff --git a/connections/mongo/src/main/java/org/keycloak/connections/mongo/impl/types/MapMapper.java b/connections/mongo/src/main/java/org/keycloak/connections/mongo/impl/types/MapMapper.java
index 988ce34..d4f0d29 100644
--- a/connections/mongo/src/main/java/org/keycloak/connections/mongo/impl/types/MapMapper.java
+++ b/connections/mongo/src/main/java/org/keycloak/connections/mongo/impl/types/MapMapper.java
@@ -25,10 +25,13 @@ public class MapMapper<T extends Map> implements Mapper<T, BasicDBObject> {
 
     @Override
     public BasicDBObject convertObject(MapperContext<T, BasicDBObject> context) {
-        T objectToConvert = context.getObjectToConvert();
+        T mapToConvert = context.getObjectToConvert();
+        return convertMap(mapToConvert);
+    }
 
+    public static BasicDBObject convertMap(Map mapToConvert) {
         BasicDBObject dbObject = new BasicDBObject();
-        Set<Map.Entry> entries = objectToConvert.entrySet();
+        Set<Map.Entry> entries = mapToConvert.entrySet();
         for (Map.Entry entry : entries) {
             String key = (String)entry.getKey();
             Object value = entry.getValue();
diff --git a/connections/mongo/src/main/java/org/keycloak/connections/mongo/updater/MongoUpdaterProvider.java b/connections/mongo/src/main/java/org/keycloak/connections/mongo/updater/MongoUpdaterProvider.java
index 7192f1d..3147100 100644
--- a/connections/mongo/src/main/java/org/keycloak/connections/mongo/updater/MongoUpdaterProvider.java
+++ b/connections/mongo/src/main/java/org/keycloak/connections/mongo/updater/MongoUpdaterProvider.java
@@ -1,6 +1,7 @@
 package org.keycloak.connections.mongo.updater;
 
 import com.mongodb.DB;
+import org.keycloak.models.KeycloakSession;
 import org.keycloak.provider.Provider;
 
 /**
@@ -8,6 +9,6 @@ import org.keycloak.provider.Provider;
  */
 public interface MongoUpdaterProvider extends Provider {
 
-    public void update(DB db);
+    public void update(KeycloakSession session, DB db);
 
 }
diff --git a/connections/mongo/src/main/resources/META-INF/services/org.keycloak.provider.Spi b/connections/mongo/src/main/resources/META-INF/services/org.keycloak.provider.Spi
index 90eedc3..fdf7660 100644
--- a/connections/mongo/src/main/resources/META-INF/services/org.keycloak.provider.Spi
+++ b/connections/mongo/src/main/resources/META-INF/services/org.keycloak.provider.Spi
@@ -1 +1,2 @@
-org.keycloak.connections.mongo.MongoConnectionSpi
\ No newline at end of file
+org.keycloak.connections.mongo.MongoConnectionSpi
+org.keycloak.connections.mongo.updater.MongoUpdaterSpi
\ No newline at end of file
diff --git a/connections/mongo-update/pom.xml b/connections/mongo-update/pom.xml
new file mode 100644
index 0000000..658df45
--- /dev/null
+++ b/connections/mongo-update/pom.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <parent>
+        <artifactId>keycloak-parent</artifactId>
+        <groupId>org.keycloak</groupId>
+        <version>1.2.0.Beta1-SNAPSHOT</version>
+        <relativePath>../../pom.xml</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>keycloak-connections-mongo-update</artifactId>
+    <name>Keycloak Connections Mongo Update</name>
+    <description/>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-core</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-model-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-connections-mongo</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-services</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.mongodb</groupId>
+            <artifactId>mongo-java-driver</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.logging</groupId>
+            <artifactId>jboss-logging</artifactId>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/connections/mongo-update/src/main/resources/META-INF/services/org.keycloak.connections.mongo.updater.MongoUpdaterProviderFactory b/connections/mongo-update/src/main/resources/META-INF/services/org.keycloak.connections.mongo.updater.MongoUpdaterProviderFactory
new file mode 100644
index 0000000..6565597
--- /dev/null
+++ b/connections/mongo-update/src/main/resources/META-INF/services/org.keycloak.connections.mongo.updater.MongoUpdaterProviderFactory
@@ -0,0 +1 @@
+org.keycloak.connections.mongo.updater.impl.DefaultMongoUpdaterProviderFactory
\ No newline at end of file
diff --git a/connections/pom.xml b/connections/pom.xml
index 58918f5..d43d861 100755
--- a/connections/pom.xml
+++ b/connections/pom.xml
@@ -18,6 +18,7 @@
         <module>infinispan</module>
         <module>mongo</module>
         <module>file</module>
+        <module>mongo-update</module>
     </modules>
 
     <build>
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 532807e..8a4727b 100755
--- a/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java
@@ -25,6 +25,13 @@ public class RealmRepresentation {
     protected Boolean verifyEmail;
     protected Boolean resetPasswordAllowed;
 
+    @Deprecated
+    protected Boolean social;
+    @Deprecated
+    protected Boolean updateProfileOnInitialSocialLogin;
+    @Deprecated
+    protected Map<String, String> socialProviders;
+
     protected Boolean userCacheEnabled;
     protected Boolean realmCacheEnabled;
 
@@ -313,6 +320,22 @@ public class RealmRepresentation {
         this.resetPasswordAllowed = resetPassword;
     }
 
+    public Boolean isSocial() {
+        return social;
+    }
+
+    public void setSocial(Boolean social) {
+        this.social = social;
+    }
+
+    public Boolean isUpdateProfileOnInitialSocialLogin() {
+        return updateProfileOnInitialSocialLogin;
+    }
+
+    public void setUpdateProfileOnInitialSocialLogin(Boolean updateProfileOnInitialSocialLogin) {
+        this.updateProfileOnInitialSocialLogin = updateProfileOnInitialSocialLogin;
+    }
+
     public Map<String, String> getBrowserSecurityHeaders() {
         return browserSecurityHeaders;
     }
@@ -321,6 +344,14 @@ public class RealmRepresentation {
         this.browserSecurityHeaders = browserSecurityHeaders;
     }
 
+    public Map<String, String> getSocialProviders() {
+        return socialProviders;
+    }
+
+    public void setSocialProviders(Map<String, String> socialProviders) {
+        this.socialProviders = socialProviders;
+    }
+
     public Map<String, String> getSmtpServer() {
         return smtpServer;
     }
@@ -482,10 +513,6 @@ public class RealmRepresentation {
     }
 
     public List<IdentityProviderRepresentation> getIdentityProviders() {
-        if (this.identityProviders == null) {
-            this.identityProviders = new ArrayList<IdentityProviderRepresentation>();
-        }
-
         return identityProviders;
     }
 
@@ -494,11 +521,12 @@ public class RealmRepresentation {
     }
 
     public void addIdentityProvider(IdentityProviderRepresentation identityProviderRepresentation) {
-        getIdentityProviders().add(identityProviderRepresentation);
+        if (identityProviders == null) identityProviders = new LinkedList<>();
+        identityProviders.add(identityProviderRepresentation);
     }
 
     public boolean isIdentityFederationEnabled() {
-        return !getIdentityProviders().isEmpty();
+        return identityProviders != null && !identityProviders.isEmpty();
     }
 
     public List<ProtocolMapperRepresentation> getProtocolMappers() {
diff --git a/core/src/main/java/org/keycloak/representations/idm/SocialLinkRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/SocialLinkRepresentation.java
new file mode 100644
index 0000000..8203261
--- /dev/null
+++ b/core/src/main/java/org/keycloak/representations/idm/SocialLinkRepresentation.java
@@ -0,0 +1,35 @@
+package org.keycloak.representations.idm;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class SocialLinkRepresentation {
+
+    protected String socialProvider;
+    protected String socialUserId;
+    protected String socialUsername;
+
+    public String getSocialProvider() {
+        return socialProvider;
+    }
+
+    public void setSocialProvider(String socialProvider) {
+        this.socialProvider = socialProvider;
+    }
+
+    public String getSocialUserId() {
+        return socialUserId;
+    }
+
+    public void setSocialUserId(String socialUserId) {
+        this.socialUserId = socialUserId;
+    }
+
+    public String getSocialUsername() {
+        return socialUsername;
+    }
+
+    public void setSocialUsername(String socialUsername) {
+        this.socialUsername = socialUsername;
+    }
+}
diff --git a/core/src/main/java/org/keycloak/representations/idm/UserRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/UserRepresentation.java
index 8fa1d6a..d2907d5 100755
--- a/core/src/main/java/org/keycloak/representations/idm/UserRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/UserRepresentation.java
@@ -25,6 +25,8 @@ public class UserRepresentation {
     protected List<CredentialRepresentation> credentials;
     protected List<String> requiredActions;
     protected List<FederatedIdentityRepresentation> federatedIdentities;
+    @Deprecated
+    protected List<SocialLinkRepresentation> socialLinks;
     protected List<String> realmRoles;
     protected Map<String, List<String>> applicationRoles;
 
@@ -147,6 +149,14 @@ public class UserRepresentation {
         this.federatedIdentities = federatedIdentities;
     }
 
+    public List<SocialLinkRepresentation> getSocialLinks() {
+        return socialLinks;
+    }
+
+    public void setSocialLinks(List<SocialLinkRepresentation> socialLinks) {
+        this.socialLinks = socialLinks;
+    }
+
     public List<String> getRealmRoles() {
         return realmRoles;
     }
diff --git a/dependencies/server-all/pom.xml b/dependencies/server-all/pom.xml
index 25b33d0..fe6d5cc 100755
--- a/dependencies/server-all/pom.xml
+++ b/dependencies/server-all/pom.xml
@@ -182,6 +182,11 @@
         </dependency>
         <dependency>
             <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-connections-mongo-update</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
             <artifactId>keycloak-model-mongo</artifactId>
             <version>${project.version}</version>
         </dependency>
diff --git a/distribution/modules/build.xml b/distribution/modules/build.xml
index 52b97ef..9199165 100755
--- a/distribution/modules/build.xml
+++ b/distribution/modules/build.xml
@@ -269,6 +269,10 @@
             <maven-resource group="org.keycloak" artifact="keycloak-connections-mongo"/>
         </module-def>
 
+        <module-def name="org.keycloak.keycloak-connections-mongo-update">
+            <maven-resource group="org.keycloak" artifact="keycloak-connections-mongo-update"/>
+        </module-def>
+
         <module-def name="org.keycloak.keycloak-model-mongo">
             <maven-resource group="org.keycloak" artifact="keycloak-model-mongo"/>
         </module-def>
diff --git a/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-connections-mongo-update/main/module.xml b/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-connections-mongo-update/main/module.xml
new file mode 100644
index 0000000..efc0102
--- /dev/null
+++ b/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-connections-mongo-update/main/module.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-connections-mongo-update">
+    <resources>
+        <!-- Insert resources here -->
+    </resources>
+    <dependencies>
+        <module name="org.keycloak.keycloak-core"/>
+        <module name="org.keycloak.keycloak-model-api"/>
+        <module name="org.keycloak.keycloak-connections-mongo"/>
+        <module name="org.keycloak.keycloak-services"/>
+        <module name="org.mongodb.mongo-java-driver"/>
+        <module name="org.jboss.logging"/>
+        <module name="javax.api"/>
+    </dependencies>
+
+</module>
\ No newline at end of file
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 2772582..c757599 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
@@ -16,6 +16,7 @@
         <module name="org.keycloak.keycloak-connections-jpa" services="import"/>
         <module name="org.keycloak.keycloak-connections-jpa-liquibase" services="import"/>
         <module name="org.keycloak.keycloak-connections-mongo" services="import"/>
+        <module name="org.keycloak.keycloak-connections-mongo-update" services="import"/>
         <module name="org.keycloak.keycloak-connections-file" services="import"/>
         <module name="org.keycloak.keycloak-core" services="import"/>
         <module name="org.keycloak.keycloak-core-jaxrs" services="import"/>
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 341e44b..bafc53f 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
@@ -16,6 +16,7 @@
         <module name="org.keycloak.keycloak-connections-jpa" services="import"/>
         <module name="org.keycloak.keycloak-connections-jpa-liquibase" services="import"/>
         <module name="org.keycloak.keycloak-connections-mongo" services="import"/>
+        <module name="org.keycloak.keycloak-connections-mongo-update" services="import"/>
         <module name="org.keycloak.keycloak-connections-file" services="import"/>
         <module name="org.keycloak.keycloak-core" services="import"/>
         <module name="org.keycloak.keycloak-core-jaxrs" services="import"/>
diff --git a/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-wildfly-extensions/main/module.xml b/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-wildfly-extensions/main/module.xml
index 9ccc11e..01af076 100755
--- a/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-wildfly-extensions/main/module.xml
+++ b/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-wildfly-extensions/main/module.xml
@@ -8,6 +8,8 @@
         <module name="org.keycloak.keycloak-core"/>
         <module name="org.keycloak.keycloak-model-api"/>
         <module name="org.keycloak.keycloak-services"/>
+        <module name="org.keycloak.keycloak-forms-common-freemarker"/>
+        <module name="org.keycloak.keycloak-forms-common-themes"/>
         <module name="org.jboss.modules"/>
     </dependencies>
 </module>
diff --git a/distribution/subsystem-war/src/main/webapp/WEB-INF/jboss-deployment-structure.xml b/distribution/subsystem-war/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
index 1da88be..29de32e 100755
--- a/distribution/subsystem-war/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
+++ b/distribution/subsystem-war/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
@@ -7,6 +7,7 @@
             <module name="org.keycloak.keycloak-connections-jpa" services="import" meta-inf="import"/>
             <module name="org.keycloak.keycloak-connections-jpa-liquibase" services="import"/>
             <module name="org.keycloak.keycloak-connections-mongo" services="import"/>
+            <module name="org.keycloak.keycloak-connections-mongo-update" services="import"/>
             <module name="org.keycloak.keycloak-connections-file" services="import"/>
             <module name="org.keycloak.keycloak-core" services="import"/>
             <module name="org.keycloak.keycloak-core-jaxrs" services="import"/>
diff --git a/docbook/reference/en/en-US/modules/providers.xml b/docbook/reference/en/en-US/modules/providers.xml
index e88bc34..a1e9184 100755
--- a/docbook/reference/en/en-US/modules/providers.xml
+++ b/docbook/reference/en/en-US/modules/providers.xml
@@ -44,7 +44,7 @@ public class MyEventListenerProviderFactory implements EventListenerProviderFact
 
 }
 }]]></programlisting>
-            The example uses a MaxList which has a maximum size and is concurrency safe. When the maximum size is reached
+            The example uses an imagined MaxList which has a maximum size and is concurrency safe. When the maximum size is reached
             and new entries are added the oldest entry is removed. Keycloak creates a single instance of
             EventListenerProviderFactory which makes it possible to store state for multiple requests. EventListenerProvider
             instances are created by calling create on the factory for each requests so these should be light-weight.
@@ -116,10 +116,10 @@ public class MyEventListenerProvider implements EventListenerProvider {
                 Next you need to register this module with Keycloak. This is done by editing keycloak-server.json and adding
                 it to the providers:
 <programlisting><![CDATA[{
-"providers": [
-    ...
-    "module:org.keycloak.examples.event-sysout"
-]
+    "providers": [
+        ...
+        "module:org.keycloak.examples.event-sysout"
+    ]
 }]]></programlisting>
             </para>
         </section>
@@ -150,6 +150,21 @@ public class MyEventListenerProvider implements EventListenerProvider {
 }]]></programlisting>
             </para>
         </section>
+
+        <section>
+            <title>Configuring a provider</title>
+            <para>
+                You can pass configuration options to your provider by setting them in <literal>keycloak-server.json</literal>.
+                For example to set the max value for <literal>my-event-listener</literal> add:
+<programlisting><![CDATA[{
+    "eventsListener": {
+        "my-event-listener": {
+            "max": 100
+        }
+    }
+}]]></programlisting>
+            </para>
+        </section>
     </section>
 
     <section>
diff --git a/docbook/reference/en/en-US/modules/server-installation.xml b/docbook/reference/en/en-US/modules/server-installation.xml
index 1d9bc6b..84d7796 100755
--- a/docbook/reference/en/en-US/modules/server-installation.xml
+++ b/docbook/reference/en/en-US/modules/server-installation.xml
@@ -449,17 +449,16 @@ keycloak-war-dist-all-&project.version;/
 },
 ]]></programlisting>
 
-You can also change the location of the data file by specifying parameters on the realm:<programlisting><![CDATA[
-    "realm": {
-        "provider": "file",
-        "file" : {
-            "directory" : "/mydirectory",
-            "fileName" : "myfilename.json"
-        }
-    },
+You can also change the location of the data file by adding a connectionsFile snippet:<programlisting><![CDATA[
+"connectionsFile": {
+   "default" : {
+        "directory": "/mydirectory",
+        "fileName": "myfilename.json"
+    }
+}
 ]]></programlisting>
 
-                All configuration options are optional. Default value for directory is ${jboss.server.data.dir}. Default file name
+All configuration options are optional. Default value for directory is <literal>${jboss.server.data.dir}</literal>. Default file name
                 is <literal>keycloak-model.json</literal>.
             </para>
         </section>
diff --git a/events/api/src/main/java/org/keycloak/events/Errors.java b/events/api/src/main/java/org/keycloak/events/Errors.java
index a02dd9c..41b501d 100755
--- a/events/api/src/main/java/org/keycloak/events/Errors.java
+++ b/events/api/src/main/java/org/keycloak/events/Errors.java
@@ -42,7 +42,6 @@ public interface Errors {
     String NOT_ALLOWED = "not_allowed";
 
     String FEDERATED_IDENTITY_EMAIL_EXISTS = "federated_identity_email_exists";
-    String FEDERATED_IDENTITY_REGISTRATION_EMAIL_MISSING = "federated_identity_registration_email_missing";
     String FEDERATED_IDENTITY_USERNAME_EXISTS = "federated_identity_username_exists";
     String SSL_REQUIRED = "ssl_required";
 
@@ -50,4 +49,5 @@ public interface Errors {
 
     String EMAIL_SEND_FAILED = "email_send_failed";
     String INVALID_EMAIL = "invalid_email";
+    String IDENTITY_PROVIDER_LOGIN_FAILURE = "identity_provider_login_failure";
 }

examples/pom.xml 1(+1 -0)

diff --git a/examples/pom.xml b/examples/pom.xml
index eb68e33..1e81647 100755
--- a/examples/pom.xml
+++ b/examples/pom.xml
@@ -34,5 +34,6 @@
         <module>basic-auth</module>
         <module>fuse</module>
         <module>kerberos</module>
+        <module>themes</module>
     </modules>
 </project>
diff --git a/examples/providers/event-listener-sysout/README.md b/examples/providers/event-listener-sysout/README.md
index 3325add..e3cef35 100644
--- a/examples/providers/event-listener-sysout/README.md
+++ b/examples/providers/event-listener-sysout/README.md
@@ -5,3 +5,13 @@ To deploy copy target/event-listener-sysout-example.jar to standalone/configurat
 Then start (or restart) the server. Once started open the admin console, select your realm, then click on Events, 
 followed by config. Click on Listeners select box, then pick sysout from the dropdown. After this try to logout and 
 login again to see events printed to System.out.
+
+The example event listener can be configured to exclude certain events, for example to exclude REFRESH_TOKEN and
+CODE_TO_TOKEN events add the following to keycloak-server.json:
+
+    ...
+    "eventsListener": {
+        "sysout" {
+            "exclude": [ "REFRESH_TOKEN", "CODE_TO_TOKEN" ]
+        }
+    }
diff --git a/examples/providers/event-listener-sysout/src/main/java/org/keycloak/examples/providers/events/SysoutEventListenerProviderFactory.java b/examples/providers/event-listener-sysout/src/main/java/org/keycloak/examples/providers/events/SysoutEventListenerProviderFactory.java
index ab2b403..3f87d81 100755
--- a/examples/providers/event-listener-sysout/src/main/java/org/keycloak/examples/providers/events/SysoutEventListenerProviderFactory.java
+++ b/examples/providers/event-listener-sysout/src/main/java/org/keycloak/examples/providers/events/SysoutEventListenerProviderFactory.java
@@ -24,10 +24,10 @@ public class SysoutEventListenerProviderFactory implements EventListenerProvider
 
     @Override
     public void init(Config.Scope config) {
-        String excludes = config.get("excludes");
+        String[] excludes = config.getArray("excludes");
         if (excludes != null) {
-            excludedEvents = new HashSet<EventType>();
-            for (String e : excludes.split(",")) {
+            excludedEvents = new HashSet<>();
+            for (String e : excludes) {
                 excludedEvents.add(EventType.valueOf(e));
             }
         }
diff --git a/examples/themes/pom.xml b/examples/themes/pom.xml
new file mode 100755
index 0000000..842c117
--- /dev/null
+++ b/examples/themes/pom.xml
@@ -0,0 +1,30 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <parent>
+        <artifactId>keycloak-parent</artifactId>
+        <groupId>org.keycloak</groupId>
+        <version>1.2.0.Beta1-SNAPSHOT</version>
+        <relativePath>../../pom.xml</relativePath>
+    </parent>
+    <name>Themes Examples</name>
+    <description/>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>keycloak-example-themes</artifactId>
+    <packaging>jar</packaging>
+
+    <build>
+        <finalName>keycloak-example-themes</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-deploy-plugin</artifactId>
+                <configuration>
+                    <skip>true</skip>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+    <modules>
+    </modules>
+</project>
diff --git a/examples/themes/README.md b/examples/themes/README.md
index fccb847..75ec61a 100644
--- a/examples/themes/README.md
+++ b/examples/themes/README.md
@@ -6,7 +6,24 @@ Sunrise Login Theme
 
 Example login theme that changes the look of the login forms.
 
-To use the theme copy `login/sunrise` to `standalone/configuration/themes/login/`. Open the admin console, select your realm, click on `Theme`. In the dropdown for `Login Theme` select `sunrise`. Click `Save` and login to the realm to see the new theme in action.
+To use the theme you can either deploy it as a module or copy it to the Keycloaks themes folder.
+
+To deploy as a module run:
+
+    mvn clean install
+    $KEYCLOAK_HOME/bin/jboss-cli.sh --command="module add --name=org.keycloak.example.sunrisetheme --resources=target/keycloak-example-themes.jar"
+
+Then open $KEYCLOAK_HOME/standalone/configuration/keycloak-server.json and register the theme module by adding:
+    
+    "theme": {
+        "module": {
+            "modules": [ "org.keycloak.example.sunrisetheme" ]
+        }
+    }
+
+Alternatively you can copy `src/main/resources/theme/login` to `standalone/configuration/themes/login/`. 
+
+Once you've added the theme open the admin console, select your realm, click on `Theme`. In the dropdown for `Login Theme` select `sunrise`. Click `Save` and login to the realm to see the new theme in action.
 
 
 Change Logo Theme
@@ -14,14 +31,30 @@ Change Logo Theme
 
 Example themes for login forms, account management, admin console and welcome pages that changes the Keycloak logo.
 
-To use the themes copy:
+To use the themes you can either deploy it as a module or copy it to the Keycloaks themes folder.
+
+To deploy as a module run:
+
+   mvn clean install
+   $KEYCLOAK_HOME/bin/jboss-cli.sh --command="module add --name=org.keycloak.example.logotheme --resources=target/keycloak-example-themes.jar"
+
+Then open $KEYCLOAK_HOME/standalone/configuration/keycloak-server.json and register the theme module by adding:
+    
+    "theme": {
+        "module": {
+            "modules": [ "org.keycloak.example.logotheme" ]
+        }
+    }
+
+Alternatively you can copy:
 
 * `account/logo-example` to `standalone/configuration/themes/account/`
 * `login/logo-example` to `standalone/configuration/themes/login/`
 * `admin/logo-example` to `standalone/configuration/themes/admin/`
 * `welcome/logo-example` to `standalone/configuration/themes/welcome/`
 
-Open the admin console, select your realm, click on `Theme`. In the dropdowns for `Login Theme`, `Account Theme` and `Admin Console Theme` select `logo-example`. Click `Save` and login to the realm to see the new theme in action.
+
+Once you've added the theme open the admin console, select your realm, click on `Theme`. In the dropdowns for `Login Theme`, `Account Theme` and `Admin Console Theme` select `logo-example`. Click `Save` and login to the realm to see the new theme in action.
 
 To change the theme for the welcome pages open `standalone/configuration/keycloak-server.json` find the config for `theme` and add 'welcomeTheme':
 
diff --git a/examples/themes/src/main/resources/META-INF/keycloak-themes.json b/examples/themes/src/main/resources/META-INF/keycloak-themes.json
new file mode 100644
index 0000000..12ee694
--- /dev/null
+++ b/examples/themes/src/main/resources/META-INF/keycloak-themes.json
@@ -0,0 +1,9 @@
+{
+    "themes": [{
+        "name" : "logo-example",
+        "types": [ "admin", "account", "login", "welcome" ]
+    }, {
+        "name" : "sunrise",
+        "types": [ "login" ]
+    }]
+}
diff --git a/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/FreeMarkerAccountProvider.java b/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/FreeMarkerAccountProvider.java
index 881606f..8497fc6 100755
--- a/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/FreeMarkerAccountProvider.java
+++ b/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/FreeMarkerAccountProvider.java
@@ -6,7 +6,7 @@ import org.keycloak.account.AccountProvider;
 import org.keycloak.account.freemarker.model.*;
 import org.keycloak.events.Event;
 import org.keycloak.freemarker.*;
-import org.keycloak.freemarker.beans.TextFormatterBean;
+import org.keycloak.freemarker.beans.MessageFormatterMethod;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserModel;
@@ -18,6 +18,7 @@ import java.io.IOException;
 import java.net.URI;
 import java.text.MessageFormat;
 import java.util.*;
+import org.keycloak.freemarker.beans.LocaleBean;
 
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -86,14 +87,10 @@ public class FreeMarkerAccountProvider implements AccountProvider {
         }
 
         Locale locale = LocaleHelper.getLocale(realm, user, uriInfo, headers);
-        if(locale != null){
-            attributes.put("locale", locale);
-            attributes.put("formatter", new TextFormatterBean(locale));
-        }
         Properties messages;
         try {
             messages = theme.getMessages(locale);
-            attributes.put("rb", messages);
+            attributes.put("msg", new MessageFormatterMethod(locale, messages));
         } catch (IOException e) {
             logger.warn("Failed to load messages", e);
             messages = new Properties();
@@ -113,7 +110,7 @@ public class FreeMarkerAccountProvider implements AccountProvider {
         if (message != null) {
             String formattedMessage;
             if(messages.containsKey(message)){
-                formattedMessage = new MessageFormat(messages.getProperty(message).replace("'","''"),locale).format(parameters);
+                formattedMessage = new MessageFormat(messages.getProperty(message),locale).format(parameters);
             }else{
                 formattedMessage = message;
             }
@@ -130,6 +127,16 @@ public class FreeMarkerAccountProvider implements AccountProvider {
 
         attributes.put("url", new UrlBean(realm, theme, baseUri, baseQueryUri, uriInfo.getRequestUri(), stateChecker));
 
+        if (realm.isInternationalizationEnabled()) {
+            UriBuilder b;
+            switch (page) {
+                default:
+                    b = UriBuilder.fromUri(baseQueryUri).path(uriInfo.getPath());
+                    break;
+            }
+            attributes.put("locale", new LocaleBean(realm, locale, b, messages));
+        }
+
         attributes.put("features", new FeaturesBean(identityProviderEnabled, eventsEnabled, passwordUpdateSupported));
 
         switch (page) {
diff --git a/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/model/UrlBean.java b/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/model/UrlBean.java
index a357aad..de7e432 100755
--- a/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/model/UrlBean.java
+++ b/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/model/UrlBean.java
@@ -59,10 +59,6 @@ public class UrlBean {
         return Urls.accountSessionsLogoutPage(baseQueryURI, realm, stateChecker).toString();
     }
 
-    public String getLocaleCookiePath(){
-        return Urls.localeCookiePath(baseURI, realm);
-    }
-
     public String getTotpRemoveUrl() {
         return Urls.accountTotpRemove(baseQueryURI, realm, stateChecker).toString();
     }
diff --git a/forms/common-freemarker/src/main/java/org/keycloak/freemarker/beans/LocaleBean.java b/forms/common-freemarker/src/main/java/org/keycloak/freemarker/beans/LocaleBean.java
new file mode 100644
index 0000000..91ae108
--- /dev/null
+++ b/forms/common-freemarker/src/main/java/org/keycloak/freemarker/beans/LocaleBean.java
@@ -0,0 +1,58 @@
+package org.keycloak.freemarker.beans;
+
+import org.keycloak.freemarker.LocaleHelper;
+import org.keycloak.models.RealmModel;
+
+import javax.ws.rs.core.UriBuilder;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class LocaleBean {
+
+    private String current;
+    private List<Locale> supported;
+
+    public LocaleBean(RealmModel realm, java.util.Locale current, UriBuilder uriBuilder, Properties messages) {
+        this.current = messages.getProperty("locale_" + current.toLanguageTag(), current.toLanguageTag());
+
+        supported = new LinkedList<>();
+        for (String l : realm.getSupportedLocales()) {
+            String label = messages.getProperty("locale_" + l, l);
+            String url = uriBuilder.replaceQueryParam(LocaleHelper.KC_LOCALE_PARAM, l).build().toString();
+            supported.add(new Locale(label, url));
+        }
+    }
+
+    public String getCurrent() {
+        return current;
+    }
+
+    public List<Locale> getSupported() {
+        return supported;
+    }
+
+    public static class Locale {
+
+        private String label;
+        private String url;
+
+        public Locale(String label, String url) {
+            this.label = label;
+            this.url = url;
+        }
+
+        public String getUrl() {
+            return url;
+        }
+
+        public String getLabel() {
+            return label;
+        }
+
+    }
+
+}
diff --git a/forms/common-freemarker/src/main/java/org/keycloak/freemarker/beans/MessageFormatterMethod.java b/forms/common-freemarker/src/main/java/org/keycloak/freemarker/beans/MessageFormatterMethod.java
new file mode 100644
index 0000000..37bfc56
--- /dev/null
+++ b/forms/common-freemarker/src/main/java/org/keycloak/freemarker/beans/MessageFormatterMethod.java
@@ -0,0 +1,32 @@
+package org.keycloak.freemarker.beans;
+
+import freemarker.template.TemplateMethodModelEx;
+import freemarker.template.TemplateModelException;
+
+import java.text.MessageFormat;
+import java.util.List;
+import java.util.Locale;
+import java.util.Properties;
+
+/**
+ * @author <a href="mailto:gerbermichi@me.com">Michael Gerber</a>
+ */
+public class MessageFormatterMethod implements TemplateMethodModelEx {
+    private final Properties messages;
+    private final Locale locale;
+
+    public MessageFormatterMethod(Locale locale, Properties messages) {
+        this.locale = locale;
+        this.messages = messages;
+    }
+
+    @Override
+    public Object exec(List list) throws TemplateModelException {
+        String key = list.get(0).toString();
+        if (list.size() >= 1) {
+            return new MessageFormat(messages.getProperty(key,key),locale).format(list.subList(1, list.size()).toArray());
+        } else {
+            return null;
+        }
+    }
+}
diff --git a/forms/common-freemarker/src/main/java/org/keycloak/freemarker/LocaleHelper.java b/forms/common-freemarker/src/main/java/org/keycloak/freemarker/LocaleHelper.java
index e153fcf..0029dfd 100644
--- a/forms/common-freemarker/src/main/java/org/keycloak/freemarker/LocaleHelper.java
+++ b/forms/common-freemarker/src/main/java/org/keycloak/freemarker/LocaleHelper.java
@@ -15,7 +15,8 @@ import java.util.*;
  */
 public class LocaleHelper {
     public final static String LOCALE_COOKIE = "KEYCLOAK_LOCALE";
-    public static final String LOCALE_PARAM = "ui_locale";
+    public static final String UI_LOCALES_PARAM = "ui_locales";
+    public static final String KC_LOCALE_PARAM = "kc_locale";
 
     private final static Logger LOGGER = Logger.getLogger(LocaleHelper.class);
 
@@ -28,12 +29,26 @@ public class LocaleHelper {
             return Locale.ENGLISH;
         }
 
+        //0. kc_locale query parameter
+         if(uriInfo != null && uriInfo.getQueryParameters().containsKey(KC_LOCALE_PARAM)){
+            String localeString = uriInfo.getQueryParameters().getFirst(KC_LOCALE_PARAM);
+            Locale locale =  findLocale(realm.getSupportedLocales(), localeString);
+            if(locale != null){
+                if(user != null){
+                    user.setAttribute(UserModel.LOCALE, locale.toLanguageTag());
+                }
+                return locale;
+            }else{
+                LOGGER.infof("Locale %s is not supported.", localeString);
+            }
+        }
+         
         //1. Locale cookie
         if(httpHeaders != null && httpHeaders.getCookies().containsKey(LOCALE_COOKIE)){
             String localeString = httpHeaders.getCookies().get(LOCALE_COOKIE).getValue();
-            Locale locale =  findLocale(localeString, realm.getSupportedLocales());
+            Locale locale =  findLocale(realm.getSupportedLocales(), localeString);
             if(locale != null){
-                if(user != null){
+                if(user != null && user.getAttribute(UserModel.LOCALE) == null){
                     user.setAttribute(UserModel.LOCALE, locale.toLanguageTag());
                 }
                 return locale;
@@ -45,7 +60,7 @@ public class LocaleHelper {
         //2. User profile
         if(user != null && user.getAttributes().containsKey(UserModel.LOCALE)){
             String localeString = user.getAttribute(UserModel.LOCALE);
-            Locale locale =  findLocale(localeString, realm.getSupportedLocales());
+            Locale locale =  findLocale(realm.getSupportedLocales(), localeString);
             if(locale != null){
 
                 return locale;
@@ -55,9 +70,9 @@ public class LocaleHelper {
         }
 
         //3. ui_locales query parameter
-        if(uriInfo != null && uriInfo.getQueryParameters().containsKey(LOCALE_PARAM)){
-            String localeString = uriInfo.getQueryParameters().getFirst(LOCALE_PARAM);
-            Locale locale =  findLocale(localeString, realm.getSupportedLocales());
+        if(uriInfo != null && uriInfo.getQueryParameters().containsKey(UI_LOCALES_PARAM)){
+            String localeString = uriInfo.getQueryParameters().getFirst(UI_LOCALES_PARAM);
+            Locale locale =  findLocale(realm.getSupportedLocales(), localeString.split(" "));
             if(locale != null){
                 return locale;
             }else{
@@ -69,7 +84,7 @@ public class LocaleHelper {
         if(httpHeaders !=null && httpHeaders.getAcceptableLanguages() != null && !httpHeaders.getAcceptableLanguages().isEmpty()){
             for(Locale l : httpHeaders.getAcceptableLanguages()){
                 String localeString = l.toLanguageTag();
-                Locale locale =  findLocale(localeString, realm.getSupportedLocales());
+                Locale locale =  findLocale(realm.getSupportedLocales(), localeString);
                 if(locale != null){
                     return locale;
                 }else{
@@ -94,20 +109,27 @@ public class LocaleHelper {
         builder.cookie(new NewCookie(LocaleHelper.LOCALE_COOKIE, locale.toLanguageTag(), path, null, null, 31536000, secure));
     }
 
-    public static Locale findLocale(String localeString, Set<String> supportedLocales) {
-        Locale result = null;
-        Locale search = Locale.forLanguageTag(localeString);
-        for(String languageTag : supportedLocales) {
-            Locale locale = Locale.forLanguageTag(languageTag);
-            if(locale.getLanguage().equals(search.getLanguage())){
-                if(locale.getCountry().equals("") && result == null){
-                    result = locale;
-                }
-                if(locale.getCountry().equals(search.getCountry())){
-                    return locale;
+
+
+    public static Locale findLocale(Set<String> supportedLocales, String ... localeStrings) {
+        for(String localeString : localeStrings){
+            Locale result = null;
+            Locale search = Locale.forLanguageTag(localeString);
+            for(String languageTag : supportedLocales) {
+                Locale locale = Locale.forLanguageTag(languageTag);
+                if(locale.getLanguage().equals(search.getLanguage())){
+                    if(locale.getCountry().equals("") && result == null){
+                        result = locale;
+                    }
+                    if(locale.getCountry().equals(search.getCountry())){
+                        return locale;
+                    }
                 }
             }
+            if(result != null){
+                return result;
+            }
         }
-        return result;
+        return null;
     }
 }
diff --git a/forms/common-freemarker/src/test/java/org/keycloak/freemarke/LocaleHelperTest.java b/forms/common-freemarker/src/test/java/org/keycloak/freemarke/LocaleHelperTest.java
index 01bb998..47fa9e4 100644
--- a/forms/common-freemarker/src/test/java/org/keycloak/freemarke/LocaleHelperTest.java
+++ b/forms/common-freemarker/src/test/java/org/keycloak/freemarke/LocaleHelperTest.java
@@ -13,12 +13,23 @@ import java.util.HashSet;
 public class LocaleHelperTest {
     @Test
     public void findLocaleTest(){
-        Assert.assertEquals("de", LocaleHelper.findLocale("de", new HashSet<>(Arrays.asList("de","en"))).toLanguageTag());
-        Assert.assertEquals("en", LocaleHelper.findLocale("en", new HashSet<>(Arrays.asList("de","en"))).toLanguageTag());
-        Assert.assertEquals("de", LocaleHelper.findLocale("de-CH", new HashSet<>(Arrays.asList("de","en"))).toLanguageTag());
-        Assert.assertEquals("de-CH", LocaleHelper.findLocale("de-CH", new HashSet<>(Arrays.asList("de","de-CH","de-DE"))).toLanguageTag());
-        Assert.assertEquals("de-DE", LocaleHelper.findLocale("de-DE", new HashSet<>(Arrays.asList("de","de-CH","de-DE"))).toLanguageTag());
-        Assert.assertEquals("de", LocaleHelper.findLocale("de", new HashSet<>(Arrays.asList("de","de-CH","de-DE"))).toLanguageTag());
-        Assert.assertNull(LocaleHelper.findLocale("de", new HashSet<>(Arrays.asList("de-CH","de-DE"))));
+        Assert.assertEquals("de", LocaleHelper.findLocale(new HashSet<>(Arrays.asList("de","en")), "de").toLanguageTag());
+        Assert.assertEquals("en", LocaleHelper.findLocale(new HashSet<>(Arrays.asList("de","en")), "en").toLanguageTag());
+        Assert.assertEquals("de", LocaleHelper.findLocale(new HashSet<>(Arrays.asList("de","en")), "de-CH").toLanguageTag());
+        Assert.assertEquals("de-CH", LocaleHelper.findLocale(new HashSet<>(Arrays.asList("de","de-CH","de-DE")), "de-CH").toLanguageTag());
+        Assert.assertEquals("de-DE", LocaleHelper.findLocale(new HashSet<>(Arrays.asList("de","de-CH","de-DE")), "de-DE").toLanguageTag());
+        Assert.assertEquals("de", LocaleHelper.findLocale(new HashSet<>(Arrays.asList("de","de-CH","de-DE")), "de").toLanguageTag());
+        Assert.assertNull(LocaleHelper.findLocale(new HashSet<>(Arrays.asList("de-CH","de-DE")), "de"));
+    }
+
+    @Test
+    public void findLocalesTest(){
+        Assert.assertEquals("de", LocaleHelper.findLocale(new HashSet<>(Arrays.asList("de","en")), "de en".split(" ")).toLanguageTag());
+        Assert.assertEquals("en", LocaleHelper.findLocale(new HashSet<>(Arrays.asList("de","en")), "en de".split(" ")).toLanguageTag());
+        Assert.assertEquals("de", LocaleHelper.findLocale(new HashSet<>(Arrays.asList("de","en")), "de-CH en".split(" ")).toLanguageTag());
+        Assert.assertEquals("de-CH", LocaleHelper.findLocale(new HashSet<>(Arrays.asList("de","de-CH","de-DE")), "de-CH de".split(" ")).toLanguageTag());
+        Assert.assertEquals("de-DE", LocaleHelper.findLocale(new HashSet<>(Arrays.asList("de","de-CH","de-DE")), "de-DE de-CH de".split(" ")).toLanguageTag());
+        Assert.assertEquals("de", LocaleHelper.findLocale(new HashSet<>(Arrays.asList("de","de-CH","de-DE")), "en fr de".split(" ")).toLanguageTag());
+        Assert.assertNull(LocaleHelper.findLocale(new HashSet<>(Arrays.asList("de-CH","de-DE")), "de en fr".split(" ")));
     }
 }
diff --git a/forms/common-themes/pom.xml b/forms/common-themes/pom.xml
index 04ea6bc..70b057b 100755
--- a/forms/common-themes/pom.xml
+++ b/forms/common-themes/pom.xml
@@ -47,6 +47,11 @@
             <artifactId>jboss-logging</artifactId>
             <scope>provided</scope>
         </dependency>
+        <dependency>
+            <groupId>org.codehaus.jackson</groupId>
+            <artifactId>jackson-core-asl</artifactId>
+            <scope>provided</scope>
+        </dependency>
 	</dependencies>
 
 	<build>
diff --git a/forms/common-themes/src/main/java/org/keycloak/theme/JarThemeProviderFactory.java b/forms/common-themes/src/main/java/org/keycloak/theme/JarThemeProviderFactory.java
new file mode 100644
index 0000000..bcd0316
--- /dev/null
+++ b/forms/common-themes/src/main/java/org/keycloak/theme/JarThemeProviderFactory.java
@@ -0,0 +1,110 @@
+package org.keycloak.theme;
+
+import org.keycloak.Config;
+import org.keycloak.freemarker.Theme;
+import org.keycloak.freemarker.ThemeProvider;
+import org.keycloak.freemarker.ThemeProviderFactory;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.util.JsonSerialization;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class JarThemeProviderFactory implements ThemeProviderFactory {
+
+    protected static final String KEYCLOAK_THEMES_JSON = "META-INF/keycloak-themes.json";
+    protected static Map<Theme.Type, Map<String, ClassLoaderTheme>> themes = new HashMap<>();
+
+    public static class ThemeRepresentation {
+        private String name;
+        private String[] types;
+
+        public String getName() {
+            return name;
+        }
+
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        public String[] getTypes() {
+            return types;
+        }
+
+        public void setTypes(String[] types) {
+            this.types = types;
+        }
+    }
+
+    public static class ThemesRepresentation {
+        private ThemeRepresentation[] themes;
+
+        public ThemeRepresentation[] getThemes() {
+            return themes;
+        }
+
+        public void setThemes(ThemeRepresentation[] themes) {
+            this.themes = themes;
+        }
+    }
+
+    @Override
+    public ThemeProvider create(KeycloakSession session) {
+        return new JarThemeProvider(themes);
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+        try {
+            ClassLoader classLoader = getClass().getClassLoader();
+            Enumeration<URL> resources = classLoader.getResources(KEYCLOAK_THEMES_JSON);
+            while (resources.hasMoreElements()) {
+                loadThemes(classLoader, resources.nextElement().openStream());
+            }
+        } catch (IOException e) {
+            throw new RuntimeException("Failed to load themes", e);
+        }
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+    }
+
+    @Override
+    public void close() {
+    }
+
+    @Override
+    public String getId() {
+        return "jar";
+    }
+
+    protected void loadThemes(ClassLoader classLoader, InputStream themesInputStream) {
+        try {
+            ThemesRepresentation themesRep = JsonSerialization.readValue(themesInputStream, ThemesRepresentation.class);
+
+            for (ThemeRepresentation themeRep : themesRep.getThemes()) {
+                for (String t : themeRep.getTypes()) {
+                    Theme.Type type = Theme.Type.valueOf(t.toUpperCase());
+                    if (!themes.containsKey(type)) {
+                        themes.put(type, new HashMap<String, ClassLoaderTheme>());
+                    }
+                    themes.get(type).put(themeRep.getName(), new ClassLoaderTheme(themeRep.getName(), type, classLoader));
+                }
+            }
+        } catch (Exception e) {
+            throw new RuntimeException("Failed to load themes", e);
+        }
+    }
+
+}
diff --git a/forms/common-themes/src/main/resources/META-INF/keycloak-themes.json b/forms/common-themes/src/main/resources/META-INF/keycloak-themes.json
new file mode 100644
index 0000000..d9f09bd
--- /dev/null
+++ b/forms/common-themes/src/main/resources/META-INF/keycloak-themes.json
@@ -0,0 +1,12 @@
+{
+    "themes": [{
+        "name" : "base",
+        "types": [ "admin", "account", "login" ]
+    }, {
+        "name" : "patternfly",
+        "types": [ "admin", "account", "login" ]
+    }, {
+        "name" : "keycloak",
+        "types": [ "admin", "account", "login", "common", "email", "welcome" ]
+    }]
+}
\ No newline at end of file
diff --git a/forms/common-themes/src/main/resources/META-INF/services/org.keycloak.freemarker.ThemeProviderFactory b/forms/common-themes/src/main/resources/META-INF/services/org.keycloak.freemarker.ThemeProviderFactory
index c1b32dc..ae680da 100644
--- a/forms/common-themes/src/main/resources/META-INF/services/org.keycloak.freemarker.ThemeProviderFactory
+++ b/forms/common-themes/src/main/resources/META-INF/services/org.keycloak.freemarker.ThemeProviderFactory
@@ -1,2 +1,2 @@
-org.keycloak.theme.DefaultKeycloakThemeProviderFactory
+org.keycloak.theme.JarThemeProviderFactory
 org.keycloak.theme.FolderThemeProviderFactory
\ No newline at end of file
diff --git a/forms/common-themes/src/main/resources/theme/account/base/account.ftl b/forms/common-themes/src/main/resources/theme/account/base/account.ftl
index 89e73b8..34487d7 100755
--- a/forms/common-themes/src/main/resources/theme/account/base/account.ftl
+++ b/forms/common-themes/src/main/resources/theme/account/base/account.ftl
@@ -16,7 +16,7 @@
 
         <div class="form-group">
             <div class="col-sm-2 col-md-2">
-                <label for="username" class="control-label">${rb.username}</label>
+                <label for="username" class="control-label">${msg("username")}</label>
             </div>
 
             <div class="col-sm-10 col-md-10">
@@ -26,7 +26,7 @@
 
         <div class="form-group">
             <div class="col-sm-2 col-md-2">
-                <label for="email" class="control-label">${rb.email}</label> <span class="required">*</span>
+            <label for="email" class="control-label">${msg("email")}</label> <span class="required">*</span>
             </div>
 
             <div class="col-sm-10 col-md-10">
@@ -37,7 +37,7 @@
 
         <div class="form-group">
             <div class="col-sm-2 col-md-2">
-                <label for="lastName" class="control-label">${rb.lastName}</label> <span class="required">*</span>
+                <label for="lastName" class="control-label">${msg("lastName")}</label> <span class="required">*</span>
             </div>
 
             <div class="col-sm-10 col-md-10">
@@ -47,7 +47,7 @@
 
         <div class="form-group">
             <div class="col-sm-2 col-md-2">
-                <label for="firstName" class="control-label">${rb.firstName}</label> <span class="required">*</span>
+                <label for="firstName" class="control-label">${msg("firstName")}</label> <span class="required">*</span>
             </div>
 
             <div class="col-sm-10 col-md-10">
@@ -57,7 +57,7 @@
 
         <div class="form-group">
             <div class="col-sm-2 col-md-2">
-                <label for="user.attributes.street" class="control-label">${rb.street}</label>
+                <label for="user.attributes.street" class="control-label">${msg("street")}</label>
             </div>
 
             <div class="col-sm-10 col-md-10">
@@ -66,7 +66,7 @@
         </div>
         <div class="form-group">
             <div class="col-sm-2 col-md-2">
-                <label for="user.attributes.locality" class="control-label">${rb.locality}</label>
+                <label for="user.attributes.locality" class="control-label">${msg("locality")}</label>
             </div>
 
             <div class="col-sm-10 col-md-10">
@@ -75,7 +75,7 @@
         </div>
         <div class="form-group">
             <div class="col-sm-2 col-md-2">
-                <label for="user.attributes.region" class="control-label">${rb.region}</label>
+                <label for="user.attributes.region" class="control-label">${msg("region")}</label>
             </div>
 
             <div class="col-sm-10 col-md-10">
@@ -84,7 +84,7 @@
         </div>
         <div class="form-group">
             <div class="col-sm-2 col-md-2">
-                <label for="user.attributes.postal_code" class="control-label">${rb.postal_code}</label>
+                <label for="user.attributes.postal_code" class="control-label">${msg("postal_code")}</label>
             </div>
 
             <div class="col-sm-10 col-md-10">
@@ -93,7 +93,7 @@
         </div>
         <div class="form-group">
             <div class="col-sm-2 col-md-2">
-                <label for="user.attributes.country" class="control-label">${rb.country}</label>
+                <label for="user.attributes.country" class="control-label">${msg("country")}</label>
             </div>
 
             <div class="col-sm-10 col-md-10">
diff --git a/forms/common-themes/src/main/resources/theme/account/base/messages/messages_en.properties b/forms/common-themes/src/main/resources/theme/account/base/messages/messages_en.properties
index 41072c8..7cf27a4 100755
--- a/forms/common-themes/src/main/resources/theme/account/base/messages/messages_en.properties
+++ b/forms/common-themes/src/main/resources/theme/account/base/messages/messages_en.properties
@@ -17,15 +17,15 @@ invalidEmailMessage=Invalid email address.
 missingLastNameMessage=Please specify last name.
 missingEmailMessage=Please specify email.
 missingPasswordMessage=Please specify password.
-notMatchPasswordMessage=Passwords don't match.
+notMatchPasswordMessage=Passwords don''t match.
 
 missingTotpMessage=Please specify authenticator code
 invalidPasswordExistingMessage=Invalid existing password
-invalidPasswordConfirmMessage=Password confirmation doesn't match
+invalidPasswordConfirmMessage=Password confirmation doesn''t match
 invalidTotpMessage=Invalid authenticator code
 
-readOnlyUserMessage=You can't update your account as it is read only
-readOnlyPasswordMessage=You can't update your password as your account is read only
+readOnlyUserMessage=You can''t update your account as it is read only
+readOnlyPasswordMessage=You can''t update your password as your account is read only
 
 successTotpMessage=Mobile authenticator configured.
 successTotpRemovedMessage=Mobile authenticator removed.
@@ -37,7 +37,7 @@ missingIdentityProviderMessage=Identity provider not specified
 invalidFederatedIdentityActionMessage=Invalid or missing action
 identityProviderNotFoundMessage=Specified identity provider not found
 federatedIdentityLinkNotActiveMessage=This identity is not active anymore
-federatedIdentityRemovingLastProviderMessage=You can't remove last federated identity as you don't have password
+federatedIdentityRemovingLastProviderMessage=You can''t remove last federated identity as you don''t have password
 identityProviderRedirectErrorMessage=Failed to redirect to identity provider
 identityProviderRemovedMessage=Identity provider removed successfully
 
diff --git a/forms/common-themes/src/main/resources/theme/account/base/password.ftl b/forms/common-themes/src/main/resources/theme/account/base/password.ftl
index af68d3b..b0a3813 100755
--- a/forms/common-themes/src/main/resources/theme/account/base/password.ftl
+++ b/forms/common-themes/src/main/resources/theme/account/base/password.ftl
@@ -14,7 +14,7 @@
         <#if password.passwordSet>
             <div class="form-group">
                 <div class="col-sm-2 col-md-2">
-                    <label for="password" class="control-label">${rb.password}</label>
+                    <label for="password" class="control-label">${msg("password")}</label>
                 </div>
 
                 <div class="col-sm-10 col-md-10">
@@ -27,7 +27,7 @@
 
         <div class="form-group">
             <div class="col-sm-2 col-md-2">
-                <label for="password-new" class="control-label">${rb.passwordNew}</label>
+                <label for="password-new" class="control-label">${msg("passwordNew")}</label>
             </div>
 
             <div class="col-sm-10 col-md-10">
@@ -37,7 +37,7 @@
 
         <div class="form-group">
             <div class="col-sm-2 col-md-2">
-                <label for="password-confirm" class="control-label" class="two-lines">${rb.passwordConfirm}</label>
+                <label for="password-confirm" class="control-label" class="two-lines">${msg("passwordConfirm")}</label>
             </div>
 
             <div class="col-sm-10 col-md-10">
diff --git a/forms/common-themes/src/main/resources/theme/account/base/sessions.ftl b/forms/common-themes/src/main/resources/theme/account/base/sessions.ftl
index 435f188..3010743 100755
--- a/forms/common-themes/src/main/resources/theme/account/base/sessions.ftl
+++ b/forms/common-themes/src/main/resources/theme/account/base/sessions.ftl
@@ -42,6 +42,6 @@
 
     </table>
 
-    <a id="logout-all-sessions" href="${url.sessionsLogoutUrl}">${rb.doLogOutAllSessions}</a>
+    <a id="logout-all-sessions" href="${url.sessionsLogoutUrl}">${msg("doLogOutAllSessions")}</a>
 
 </@layout.mainLayout>
diff --git a/forms/common-themes/src/main/resources/theme/account/base/template.ftl b/forms/common-themes/src/main/resources/theme/account/base/template.ftl
index 0d862c3..adfd52c 100644
--- a/forms/common-themes/src/main/resources/theme/account/base/template.ftl
+++ b/forms/common-themes/src/main/resources/theme/account/base/template.ftl
@@ -15,19 +15,6 @@
             <script type="text/javascript" src="${url.resourcesPath}/${script}"></script>
         </#list>
     </#if>
-    <#if realm.internationalizationEnabled>
-        <script type="text/javascript">
-            window.onload = function () {
-                var select = document.querySelector(".kc-locale-select");
-                select.onchange = function (event) {
-                    document.cookie = "KEYCLOAK_LOCALE=" + select.value+"; path=${url.localeCookiePath}";
-                    setTimeout(function () {
-                        window.location.reload();
-                    }, 0);
-                }
-            }
-        </script>
-    </#if>
 </head>
 <body class="admin-console user ${bodyClass}">
 
@@ -43,11 +30,14 @@
                     <ul class="nav navbar-nav navbar-utility">
                         <#if realm.internationalizationEnabled>
                             <li>
-                                <select class="kc-locale-select">
-                                    <#list realm.supportedLocales as l>
-                                        <option value="${l}" <#if locale.toLanguageTag()==l>selected="selected"</#if>>${rb["locale_" + l]}</option>
-                                    </#list>
-                                </select>
+                                <div class="kc-dropdown">
+                                    <a href="#">${locale.current}</a>
+                                    <ul>
+                                        <#list locale.supported as l>
+                                            <li class="kc-dropdown-item"><a href="${l.url}">${l.label}</a></li>
+                                        </#list>
+                                    </ul>
+                                </div>
                             <li>
                         </#if>
                         <#if referrer?has_content && referrer.url?has_content><li><a href="${referrer.url}" id="referrer">Back to ${referrer.name}</a></li></#if>
diff --git a/forms/common-themes/src/main/resources/theme/account/base/totp.ftl b/forms/common-themes/src/main/resources/theme/account/base/totp.ftl
index d480337..45e7829 100755
--- a/forms/common-themes/src/main/resources/theme/account/base/totp.ftl
+++ b/forms/common-themes/src/main/resources/theme/account/base/totp.ftl
@@ -46,7 +46,7 @@
             <input type="hidden" id="stateChecker" name="stateChecker" value="${stateChecker}">
             <div class="form-group">
                 <div class="col-sm-2 col-md-2">
-                    <label for="totp" class="control-label">${rb.authenticatorCode}</label>
+                    <label for="totp" class="control-label">${msg("authenticatorCode")}</label>
                 </div>
 
                 <div class="col-sm-10 col-md-10">
diff --git a/forms/common-themes/src/main/resources/theme/account/patternfly/resources/css/account.css b/forms/common-themes/src/main/resources/theme/account/patternfly/resources/css/account.css
index 07762b0..a18d0f2 100644
--- a/forms/common-themes/src/main/resources/theme/account/patternfly/resources/css/account.css
+++ b/forms/common-themes/src/main/resources/theme/account/patternfly/resources/css/account.css
@@ -220,4 +220,55 @@ ol li span {
 hr + .form-horizontal {
     border: none;
     padding-top: 0;
+}
+
+.kc-dropdown{
+    position: relative;
+}
+.kc-dropdown > a{
+    display:block;
+    padding: 11px 10px 12px;
+    line-height: 12px;
+    font-size: 12px;
+    color: #fff !important;
+    text-decoration: none;
+}
+.kc-dropdown > a::after{
+    content: "\2c5";
+    margin-left: 4px;
+}
+.kc-dropdown:hover > a{
+    background-color: rgba(0,0,0,0.2);
+}
+.kc-dropdown ul li a{
+    padding: 1px 11px;
+    font-size: 12px;
+    color: #000 !important;
+    border: 1px solid #fff;
+    text-decoration: none;
+    display:block;
+    line-height: 20px;
+}
+.kc-dropdown ul li a:hover{
+    color: #4d5258;
+    background-color: #d4edfa;
+    border-color: #b3d3e7;
+}
+.kc-dropdown ul{
+    position: absolute;
+    z-index: 2000;
+    list-style:none;
+    display:none;
+    padding: 5px 0px;
+    margin: 0px;
+    background-color: #fff !important;
+    border: 1px solid #b6b6b6;
+    border-radius: 1px;
+    -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
+    box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
+    background-clip: padding-box;
+    min-width: 100px;
+}
+.kc-dropdown:hover ul{
+    display:block;
 }
\ No newline at end of file
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/applications.js b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/applications.js
index a70b4a6..307f805 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/applications.js
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/applications.js
@@ -1181,11 +1181,11 @@ module.controller('ApplicationProtocolMapperCtrl', function($scope, realm, serve
     }
     $scope.protocol = application.protocol;
     $scope.mapper = angular.copy(mapper);
-    var oldCopy = angular.copy($scope.realm);
     $scope.changed = false;
+    $scope.boolval = true;
+    $scope.boolvalId = 'boolval';
 
-    console.log('protocol: ' + protocol);
-    var protocolMappers = serverInfo.protocolMapperTypes[$scope.protocol];
+    var protocolMappers = serverInfo.protocolMapperTypes[application.protocol];
     for (var i = 0; i < protocolMappers.length; i++) {
         if (protocolMappers[i].id == mapper.protocolMapper) {
             $scope.mapperType = protocolMappers[i];
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/loaders.js b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/loaders.js
index 6fcfeb0..da6873d 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/loaders.js
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/loaders.js
@@ -234,8 +234,6 @@ module.factory('ApplicationRoleListLoader', function(Loader, ApplicationRole, $r
 
 module.factory('ApplicationLoader', function(Loader, Application, $route, $q) {
     return Loader.get(Application, function() {
-        console.log('application loader****');
-        console.log($route.current.params.application);
         return {
             realm : $route.current.params.realm,
             application : $route.current.params.application
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-identity-provider.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-identity-provider.html
index 651f351..4d81c65 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-identity-provider.html
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-identity-provider.html
@@ -35,7 +35,7 @@
                                 <a href="#/realms/{{realm.realm}}/identity-provider-settings/provider/{{identityProvider.providerId}}/{{identityProvider.alias}}">{{identityProvider.alias}}</a>
                             </td>
                             <td>
-                                {{callbackUrl}}{{identityProvider.alias}}
+                                {{callbackUrl}}{{identityProvider.alias}}/endpoint
                             </td>
                         </tr>
                         </tbody>
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-theme-settings.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-theme-settings.html
index 5d5a927..741b787 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-theme-settings.html
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-theme-settings.html
@@ -65,14 +65,14 @@
                             <input ng-model="realm.internationalizationEnabled" name="internationalizationEnabled" id="internationalizationEnabled" onoffswitch />
                         </div>
                     </div>
-                    <div class="form-group">
+                    <div class="form-group" data-ng-show="realm.internationalizationEnabled">
                         <label class="col-sm-2 control-label" for="supportedLocales" class="control-label two-lines">Supported Locales</label>
 
                         <div class="col-sm-4">
                             <input id="supportedLocales" type="text" ui-select2="supportedLocalesOptions" ng-model="realm.supportedLocales" placeholder="Type a locale and enter" ng-required="realm.internationalizationEnabled" ng-disabled="!realm.internationalizationEnabled">
                         </div>
                     </div>
-                    <div class="form-group">
+                    <div class="form-group" data-ng-show="realm.internationalizationEnabled">
                         <label class="col-sm-2 control-label" for="defaultLocale">Default Locale</label>
                         <div class="col-sm-4">
                             <div class="select-kc">
diff --git a/forms/common-themes/src/main/resources/theme/email/keycloak/email-verification.ftl b/forms/common-themes/src/main/resources/theme/email/keycloak/email-verification.ftl
index 301212f..5f2490b 100644
--- a/forms/common-themes/src/main/resources/theme/email/keycloak/email-verification.ftl
+++ b/forms/common-themes/src/main/resources/theme/email/keycloak/email-verification.ftl
@@ -1 +1 @@
-${formatter.format(rb.emailVerificationBody,link, linkExpiration)}
\ No newline at end of file
+${msg("emailVerificationBody",link, linkExpiration)}
\ No newline at end of file
diff --git a/forms/common-themes/src/main/resources/theme/email/keycloak/event-login_error.ftl b/forms/common-themes/src/main/resources/theme/email/keycloak/event-login_error.ftl
index cd9d247..7835c91 100644
--- a/forms/common-themes/src/main/resources/theme/email/keycloak/event-login_error.ftl
+++ b/forms/common-themes/src/main/resources/theme/email/keycloak/event-login_error.ftl
@@ -1 +1 @@
-${formatter.format(rb.eventLoginErrorBody,event.date,event.ipAddress)}
\ No newline at end of file
+${msg("eventLoginErrorBody",event.date,event.ipAddress)}
\ No newline at end of file
diff --git a/forms/common-themes/src/main/resources/theme/email/keycloak/event-remove_totp.ftl b/forms/common-themes/src/main/resources/theme/email/keycloak/event-remove_totp.ftl
index 37ae2f7..8930b64 100644
--- a/forms/common-themes/src/main/resources/theme/email/keycloak/event-remove_totp.ftl
+++ b/forms/common-themes/src/main/resources/theme/email/keycloak/event-remove_totp.ftl
@@ -1 +1 @@
-${formatter.format(rb.eventRemoveTotpBody,event.date, event.ipAddress)}
\ No newline at end of file
+${msg("eventRemoveTotpBody",event.date, event.ipAddress)}
\ No newline at end of file
diff --git a/forms/common-themes/src/main/resources/theme/email/keycloak/event-update_password.ftl b/forms/common-themes/src/main/resources/theme/email/keycloak/event-update_password.ftl
index 2c88214..754daac 100644
--- a/forms/common-themes/src/main/resources/theme/email/keycloak/event-update_password.ftl
+++ b/forms/common-themes/src/main/resources/theme/email/keycloak/event-update_password.ftl
@@ -1 +1 @@
-${formatter.format(rb.eventUpdatePasswordBody,event.date, event.ipAddress)}
\ No newline at end of file
+${msg("eventUpdatePasswordBody",event.date, event.ipAddress)}
\ No newline at end of file
diff --git a/forms/common-themes/src/main/resources/theme/email/keycloak/event-update_totp.ftl b/forms/common-themes/src/main/resources/theme/email/keycloak/event-update_totp.ftl
index b34a898..3a7b0f7 100644
--- a/forms/common-themes/src/main/resources/theme/email/keycloak/event-update_totp.ftl
+++ b/forms/common-themes/src/main/resources/theme/email/keycloak/event-update_totp.ftl
@@ -1 +1 @@
-${formatter.format(rb.eventUpdateTotpBody,event.date, event.ipAddress)}
\ No newline at end of file
+${msg("eventUpdateTotpBody",event.date, event.ipAddress)}
\ No newline at end of file
diff --git a/forms/common-themes/src/main/resources/theme/email/keycloak/messages/messages_en.properties b/forms/common-themes/src/main/resources/theme/email/keycloak/messages/messages_en.properties
index e64a00f..c23daf6 100755
--- a/forms/common-themes/src/main/resources/theme/email/keycloak/messages/messages_en.properties
+++ b/forms/common-themes/src/main/resources/theme/email/keycloak/messages/messages_en.properties
@@ -1,7 +1,7 @@
 emailVerificationSubject=Verify email
-emailVerificationBody=Someone has created a Keycloak 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.
+emailVerificationBody=Someone has created a Keycloak 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.
 passwordResetSubject=Reset password
-passwordResetBody=Someone just requested to change your Keycloak 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.
+passwordResetBody=Someone just requested to change your Keycloak 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.
 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.
 eventRemoveTotpSubject=Remove TOTP
diff --git a/forms/common-themes/src/main/resources/theme/email/keycloak/password-reset.ftl b/forms/common-themes/src/main/resources/theme/email/keycloak/password-reset.ftl
index 55f0138..d7150d6 100644
--- a/forms/common-themes/src/main/resources/theme/email/keycloak/password-reset.ftl
+++ b/forms/common-themes/src/main/resources/theme/email/keycloak/password-reset.ftl
@@ -1 +1 @@
-${formatter.format(rb.passwordResetBody,link, linkExpiration)}
\ No newline at end of file
+${msg("passwordResetBody",link, linkExpiration)}
\ No newline at end of file
diff --git a/forms/common-themes/src/main/resources/theme/login/base/error.ftl b/forms/common-themes/src/main/resources/theme/login/base/error.ftl
index 3854ae2..2c8c153 100755
--- a/forms/common-themes/src/main/resources/theme/login/base/error.ftl
+++ b/forms/common-themes/src/main/resources/theme/login/base/error.ftl
@@ -1,9 +1,9 @@
 <#import "template.ftl" as layout>
 <@layout.registrationLayout displayMessage=false; section>
     <#if section = "title">
-        ${rb.errorTitle}
+        ${msg("errorTitle")}
     <#elseif section = "header">
-        ${rb.errorTitleHtml}
+        ${msg("errorTitleHtml")}
     <#elseif section = "form">
         <div id="kc-error-message">
             <p class="instruction">${message.summary}</p>
diff --git a/forms/common-themes/src/main/resources/theme/login/base/info.ftl b/forms/common-themes/src/main/resources/theme/login/base/info.ftl
index d303e5b..f4de855 100755
--- a/forms/common-themes/src/main/resources/theme/login/base/info.ftl
+++ b/forms/common-themes/src/main/resources/theme/login/base/info.ftl
@@ -8,7 +8,7 @@
     <div id="kc-info-message">
         <p class="instruction">${message.summary}</p>
         <#if client.baseUrl??>
-        <p><a href="${client.baseUrl}">${rb.backToApplication}</a></p>
+        <p><a href="${client.baseUrl}">${msg("backToApplication")}</a></p>
         </#if>
     </div>
     </#if>
diff --git a/forms/common-themes/src/main/resources/theme/login/base/login.ftl b/forms/common-themes/src/main/resources/theme/login/base/login.ftl
index 71c34cd..505e185 100755
--- a/forms/common-themes/src/main/resources/theme/login/base/login.ftl
+++ b/forms/common-themes/src/main/resources/theme/login/base/login.ftl
@@ -2,22 +2,22 @@
 <@layout.registrationLayout displayInfo=social.displayInfo; section>
     <#if section = "title">
         <#if client.application>
-            ${formatter.format(rb.loginTitle,(realm.name!''))}
+            ${msg("loginTitle",(realm.name!''))}
         <#elseif client.oauthClient>
-            ${formatter.format(rb.loginOauthTitle,(realm.name!''))}
+            ${msg("loginOauthTitle",(realm.name!''))}
         </#if>
     <#elseif section = "header">
         <#if client.application>
-            ${formatter.format(rb.loginTitleHtml,(realm.name!''))}
+            ${msg("loginTitleHtml",(realm.name!''))}
         <#elseif client.oauthClient>
-            ${formatter.format(rb.loginOauthTitleHtml,(realm.name!''), (client.clientId!''))}
+            ${msg("loginOauthTitleHtml",(realm.name!''), (client.clientId!''))}
         </#if>
     <#elseif section = "form">
         <#if realm.password>
             <form id="kc-form-login" class="${properties.kcFormClass!}" action="${url.loginAction}" method="post">
                 <div class="${properties.kcFormGroupClass!}">
                     <div class="${properties.kcLabelWrapperClass!}">
-                        <label for="username" class="${properties.kcLabelClass!}"><#if !realm.registrationEmailAsUsername>${rb.usernameOrEmail}<#else>${rb.email}</#if></label>
+                        <label for="username" class="${properties.kcLabelClass!}"><#if !realm.registrationEmailAsUsername>${msg("usernameOrEmail")}<#else>${msg("email")}</#if></label>
                     </div>
 
                     <div class="${properties.kcInputWrapperClass!}">
@@ -27,7 +27,7 @@
 
                 <div class="${properties.kcFormGroupClass!}">
                     <div class="${properties.kcLabelWrapperClass!}">
-                        <label for="password" class="${properties.kcLabelClass!}">${rb.password}</label>
+                        <label for="password" class="${properties.kcLabelClass!}">${msg("password")}</label>
                     </div>
 
                     <div class="${properties.kcInputWrapperClass!}">
@@ -41,24 +41,24 @@
                             <div class="checkbox">
                                 <label>
                                     <#if login.rememberMe??>
-                                        <input id="rememberMe" name="rememberMe" type="checkbox" tabindex="3" checked> ${rb.rememberMe}
+                                        <input id="rememberMe" name="rememberMe" type="checkbox" tabindex="3" checked> ${msg("rememberMe")}
                                     <#else>
-                                        <input id="rememberMe" name="rememberMe" type="checkbox" tabindex="3"> ${rb.rememberMe}
+                                        <input id="rememberMe" name="rememberMe" type="checkbox" tabindex="3"> ${msg("rememberMe")}
                                     </#if>
                                 </label>
                             </div>
                         </#if>
                         <div class="${properties.kcFormOptionsWrapperClass!}">
                             <#if realm.resetPasswordAllowed>
-                                <span><a href="${url.loginPasswordResetUrl}">${rb.doForgotPassword}</a></span>
+                                <span><a href="${url.loginPasswordResetUrl}">${msg("doForgotPassword")}</a></span>
                             </#if>
                         </div>
                     </div>
 
                     <div id="kc-form-buttons" class="${properties.kcFormButtonsClass!}">
                         <div class="${properties.kcFormButtonsWrapperClass!}">
-                            <input class="btn btn-primary btn-lg" name="login" id="kc-login" type="submit" value="${rb.doLogIn}"/>
-                            <input class="btn btn-default btn-lg" name="cancel" id="kc-cancel" type="submit" value="${rb.doCancel}"/>
+                            <input class="btn btn-primary btn-lg" name="login" id="kc-login" type="submit" value="${msg("doLogIn")}"/>
+                            <input class="btn btn-default btn-lg" name="cancel" id="kc-cancel" type="submit" value="${msg("doCancel")}"/>
                         </div>
                      </div>
                 </div>
@@ -67,7 +67,7 @@
     <#elseif section = "info" >
         <#if realm.password && realm.registrationAllowed>
             <div id="kc-registration">
-                <span>${rb.noAccount} <a href="${url.registrationUrl}">${rb.doRegister}</a></span>
+                <span>${msg("noAccount")} <a href="${url.registrationUrl}">${msg("doRegister")}</a></span>
             </div>
         </#if>
 
diff --git a/forms/common-themes/src/main/resources/theme/login/base/login-config-totp.ftl b/forms/common-themes/src/main/resources/theme/login/base/login-config-totp.ftl
index c884ad4..94f264a 100755
--- a/forms/common-themes/src/main/resources/theme/login/base/login-config-totp.ftl
+++ b/forms/common-themes/src/main/resources/theme/login/base/login-config-totp.ftl
@@ -1,14 +1,14 @@
 <#import "template.ftl" as layout>
 <@layout.registrationLayout displayInfo=true; section>
     <#if section = "title">
-        ${rb.loginTotpTitle}
+        ${msg("loginTotpTitle")}
     <#elseif section = "header">
-        ${rb.loginTotpTitle}
+        ${msg("loginTotpTitle")}
     <#elseif section = "form">
         <form action="${url.loginUpdateTotpUrl}" class="${properties.kcFormClass!}" id="kc-totp-settings-form" method="post">
             <div class="${properties.kcFormGroupClass!}">
                 <div class="${properties.kcLabelWrapperClass!}">
-                    <label for="otp" class="${properties.kcLabelClass!}">${rb.loginTotpOneTime}</label>
+                    <label for="otp" class="${properties.kcLabelClass!}">${msg("loginTotpOneTime")}</label>
                 </div>
                 <div class="${properties.kcInputWrapperClass!}">
                     <input type="text" id="totp" name="totp" class="${properties.kcInputClass!}" />
@@ -23,22 +23,22 @@
                 </div>
 
                 <div id="kc-form-buttons" class="${properties.kcFormButtonsClass!}">
-                    <input class="btn btn-primary btn-lg" type="submit" value="${rb.doSubmit}"/>
+                    <input class="btn btn-primary btn-lg" type="submit" value="${msg("doSubmit")}"/>
                 </div>
             </div>
         </form>
     <#elseif section = "info" >
         <ol id="kc-totp-settings">
             <li>
-                <p>${rb.loginTotpStep1}</p>
+                <p>${msg("loginTotpStep1")}</p>
             </li>
             <li>
-                <p>${rb.loginTotpStep2}</p>
+                <p>${msg("loginTotpStep2")}</p>
                 <img src="${totp.totpSecretQrCodeUrl}" alt="Figure: Barcode"><br/>
                 <span class="code">${totp.totpSecretEncoded}</span>
             </li>
             <li>
-                <p>${rb.loginTotpStep3}</p>
+                <p>${msg("loginTotpStep3")}</p>
             </li>
         </ol>
     </#if>
diff --git a/forms/common-themes/src/main/resources/theme/login/base/login-oauth-grant.ftl b/forms/common-themes/src/main/resources/theme/login/base/login-oauth-grant.ftl
index 797b62d..757a715 100755
--- a/forms/common-themes/src/main/resources/theme/login/base/login-oauth-grant.ftl
+++ b/forms/common-themes/src/main/resources/theme/login/base/login-oauth-grant.ftl
@@ -2,12 +2,12 @@
 <#import "template.ftl" as layout>
 <@layout.registrationLayout bodyClass="oauth"; section>
     <#if section = "title">
-        ${rb.oauthGrantTitle}
+        ${msg("oauthGrantTitle")}
     <#elseif section = "header">
-        ${formatter.format(rb.oauthGrantTitleHtml,(realm.name!''), (client.clientId!''))}
+        ${msg("oauthGrantTitleHtml",(realm.name!''), (client.clientId!''))}
     <#elseif section = "form">
         <div id="kc-oauth" class="content-area">
-            <h3>${rb.oauthGrantRequest}</h3>
+            <h3>${msg("oauthGrantRequest")}</h3>
             <ul>
                 <#if oauth.claimsRequested??>
                     <li>
@@ -55,8 +55,8 @@
 
                     <div id="kc-form-buttons" class="${properties.kcFormButtonsClass!}">
                         <div class="${properties.kcFormButtonsWrapperClass!}">
-                            <input class="btn btn-primary btn-lg" name="accept" id="kc-login" type="submit" value="${rb.doYes}"/>
-                            <input class="btn btn-default btn-lg" name="cancel" id="kc-cancel" type="submit" value="${rb.doNo}"/>
+                            <input class="btn btn-primary btn-lg" name="accept" id="kc-login" type="submit" value="${msg("doYes")}"/>
+                            <input class="btn btn-default btn-lg" name="cancel" id="kc-cancel" type="submit" value="${msg("doNo")}"/>
                         </div>
                     </div>
                 </div>
diff --git a/forms/common-themes/src/main/resources/theme/login/base/login-reset-password.ftl b/forms/common-themes/src/main/resources/theme/login/base/login-reset-password.ftl
index 9fe7a15..ec327c2 100755
--- a/forms/common-themes/src/main/resources/theme/login/base/login-reset-password.ftl
+++ b/forms/common-themes/src/main/resources/theme/login/base/login-reset-password.ftl
@@ -1,14 +1,14 @@
 <#import "template.ftl" as layout>
 <@layout.registrationLayout displayInfo=true; section>
     <#if section = "title">
-        ${rb.emailForgotTitle}
+        ${msg("emailForgotTitle")}
     <#elseif section = "header">
-        ${rb.emailForgotTitle}
+        ${msg("emailForgotTitle")}
     <#elseif section = "form">
         <form id="kc-reset-password-form" class="${properties.kcFormClass!}" action="${url.loginPasswordResetUrl}" method="post">
             <div class="${properties.kcFormGroupClass!}">
                 <div class="${properties.kcLabelWrapperClass!}">
-                    <label for="username" class="${properties.kcLabelClass!}">${rb.usernameOrEmail}</label>
+                    <label for="username" class="${properties.kcLabelClass!}">${msg("usernameOrEmail")}</label>
                 </div>
                 <div class="${properties.kcInputWrapperClass!}">
                     <input type="text" id="username" name="username" class="${properties.kcInputClass!}" />
@@ -18,16 +18,16 @@
             <div class="${properties.kcFormGroupClass!}">
                 <div id="kc-form-options" class="${properties.kcFormOptionsClass!}">
                     <div class="${properties.kcFormOptionsWrapperClass!}">
-                        <span><a href="${url.loginUrl}">${rb.backToLogin}</a></span>
+                        <span><a href="${url.loginUrl}">${msg("backToLogin")}</a></span>
                     </div>
                 </div>
 
                 <div id="kc-form-buttons" class="${properties.kcFormButtonsClass!}">
-                    <input class="btn btn-primary btn-lg" type="submit" value="${rb.doSubmit}"/>
+                    <input class="btn btn-primary btn-lg" type="submit" value="${msg("doSubmit")}"/>
                 </div>
             </div>
         </form>
     <#elseif section = "info" >
-        ${rb.emailInstruction}
+        ${msg("emailInstruction")}
     </#if>
 </@layout.registrationLayout>
\ No newline at end of file
diff --git a/forms/common-themes/src/main/resources/theme/login/base/login-totp.ftl b/forms/common-themes/src/main/resources/theme/login/base/login-totp.ftl
index 8661fa0..ec07935 100755
--- a/forms/common-themes/src/main/resources/theme/login/base/login-totp.ftl
+++ b/forms/common-themes/src/main/resources/theme/login/base/login-totp.ftl
@@ -1,9 +1,9 @@
 <#import "template.ftl" as layout>
 <@layout.registrationLayout; section>
     <#if section = "title">
-        ${formatter.format(rb.loginTitle,realm.name)}
+        ${msg("loginTitle",realm.name)}
     <#elseif section = "header">
-        ${formatter.format(rb.loginTitleHtml,realm.name)}
+        ${msg("loginTitleHtml",realm.name)}
     <#elseif section = "form">
         <form id="kc-totp-login-form" class="${properties.kcFormClass!}" action="${url.loginAction}" method="post">
             <input id="username" name="username" value="${login.username!''}" type="hidden" />
@@ -11,7 +11,7 @@
 
             <div class="${properties.kcFormGroupClass!}">
                 <div class="${properties.kcLabelWrapperClass!}">
-                    <label for="totp" class="${properties.kcLabelClass!}">${rb.authenticatorCode}</label>
+                    <label for="totp" class="${properties.kcLabelClass!}">${msg("doLogIn")}</label>
                 </div>
 
                 <div class="${properties.kcInputWrapperClass!}">
@@ -27,8 +27,8 @@
 
                 <div id="kc-form-buttons" class="${properties.kcFormButtonsClass!}">
                     <div class="${properties.kcFormButtonsWrapperClass!}">
-                        <input class="btn btn-primary btn-lg" name="login" id="kc-login" type="submit" value="${rb.doLogIn}"/>
-                        <input class="btn btn-default btn-lg" name="cancel" id="kc-cancel" type="submit" value="${rb.doCancel}"/>
+                        <input class="btn btn-primary btn-lg" name="login" id="kc-login" type="submit" value="${msg("doLogIn")}"/>
+                        <input class="btn btn-default btn-lg" name="cancel" id="kc-cancel" type="submit" value="${msg("doCancel")}"/>
                     </div>
                 </div>
             </div>
diff --git a/forms/common-themes/src/main/resources/theme/login/base/login-update-password.ftl b/forms/common-themes/src/main/resources/theme/login/base/login-update-password.ftl
index bbc69a2..d201616 100755
--- a/forms/common-themes/src/main/resources/theme/login/base/login-update-password.ftl
+++ b/forms/common-themes/src/main/resources/theme/login/base/login-update-password.ftl
@@ -1,14 +1,14 @@
 <#import "template.ftl" as layout>
 <@layout.registrationLayout displayInfo=true; section>
     <#if section = "title">
-        ${rb.updatePasswordTitle}
+        ${msg("updatePasswordTitle")}
     <#elseif section = "header">
-        ${rb.updatePasswordTitle}
+        ${msg("updatePasswordTitle")}
     <#elseif section = "form">
         <form id="kc-passwd-update-form" class="${properties.kcFormClass!}" action="${url.loginUpdatePasswordUrl}" method="post">
             <div class="${properties.kcFormGroupClass!}">
                 <div class="${properties.kcLabelWrapperClass!}">
-                    <label for="password-new" class="${properties.kcLabelClass!}">${rb.passwordNew}</label>
+                    <label for="password-new" class="${properties.kcLabelClass!}">${msg("passwordNew")}</label>
                 </div>
                 <div class="${properties.kcInputWrapperClass!}">
                     <input type="password" id="password-new" name="password-new" class="${properties.kcInputClass!}" autofocus />
@@ -17,7 +17,7 @@
 
             <div class="${properties.kcFormGroupClass!}">
                 <div class="${properties.kcLabelWrapperClass!}">
-                    <label for="password-confirm" class="${properties.kcLabelClass!}">${rb.passwordConfirm}</label>
+                    <label for="password-confirm" class="${properties.kcLabelClass!}">${msg("passwordConfirm")}</label>
                 </div>
                 <div class="${properties.kcInputWrapperClass!}">
                     <input type="password" id="password-confirm" name="password-confirm" class="${properties.kcInputClass!}" />
@@ -31,7 +31,7 @@
                 </div>
 
                 <div id="kc-form-buttons" class="${properties.kcFormButtonsClass!}">
-                    <input class="btn btn-primary btn-lg" type="submit" value="${rb.doSubmit}"/>
+                    <input class="btn btn-primary btn-lg" type="submit" value="${msg("doSubmit")}"/>
                 </div>
             </div>
         </form>
diff --git a/forms/common-themes/src/main/resources/theme/login/base/login-update-profile.ftl b/forms/common-themes/src/main/resources/theme/login/base/login-update-profile.ftl
index c3e1d9b..56b5cbe 100755
--- a/forms/common-themes/src/main/resources/theme/login/base/login-update-profile.ftl
+++ b/forms/common-themes/src/main/resources/theme/login/base/login-update-profile.ftl
@@ -1,14 +1,14 @@
 <#import "template.ftl" as layout>
 <@layout.registrationLayout; section>
     <#if section = "title">
-        ${rb.loginProfileTitle}
+        ${msg("loginProfileTitle")}
     <#elseif section = "header">
-        ${rb.loginProfileTitle}
+        ${msg("loginProfileTitle")}
     <#elseif section = "form">
         <form id="kc-update-profile-form" class="${properties.kcFormClass!}" action="${url.loginUpdateProfileUrl}" method="post">
             <div class="${properties.kcFormGroupClass!}">
                 <div class="${properties.kcLabelWrapperClass!}">
-                    <label for="email" class="${properties.kcLabelClass!}">${rb.email}</label>
+                    <label for="email" class="${properties.kcLabelClass!}">${msg("email")}</label>
                 </div>
                 <div class="${properties.kcInputWrapperClass!}">
                     <input type="text" id="email" name="email" value="${(user.email!'')?html}" class="${properties.kcInputClass!}" />
@@ -17,7 +17,7 @@
 
             <div class="${properties.kcFormGroupClass!}">
                 <div class="${properties.kcLabelWrapperClass!}">
-                    <label for="firstName" class="${properties.kcLabelClass!}">${rb.firstName}</label>
+                    <label for="firstName" class="${properties.kcLabelClass!}">${msg("firstName")}</label>
                 </div>
                 <div class="${properties.kcInputWrapperClass!}">
                     <input type="text" id="firstName" name="firstName" value="${(user.firstName!'')?html}" class="${properties.kcInputClass!}" />
@@ -26,7 +26,7 @@
 
             <div class="${properties.kcFormGroupClass!}">
                 <div class="${properties.kcLabelWrapperClass!}">
-                    <label for="lastName" class="${properties.kcLabelClass!}">${rb.lastName}</label>
+                    <label for="lastName" class="${properties.kcLabelClass!}">${msg("lastName")}</label>
                 </div>
                 <div class="${properties.kcInputWrapperClass!}">
                     <input type="text" id="lastName" name="lastName" value="${(user.lastName!'')?html}" class="${properties.kcInputClass!}" />
@@ -40,7 +40,7 @@
                 </div>
 
                 <div id="kc-form-buttons" class="${properties.kcFormButtonsClass!}">
-                    <input class="btn btn-primary btn-lg" type="submit" value="${rb.doSubmit}" />
+                    <input class="btn btn-primary btn-lg" type="submit" value="${msg("doSubmit")}" />
                 </div>
             </div>
         </form>
diff --git a/forms/common-themes/src/main/resources/theme/login/base/login-verify-email.ftl b/forms/common-themes/src/main/resources/theme/login/base/login-verify-email.ftl
index ac48f95..1396351 100755
--- a/forms/common-themes/src/main/resources/theme/login/base/login-verify-email.ftl
+++ b/forms/common-themes/src/main/resources/theme/login/base/login-verify-email.ftl
@@ -1,15 +1,15 @@
 <#import "template.ftl" as layout>
 <@layout.registrationLayout; section>
     <#if section = "title">
-        ${rb.emailVerifyTitle}
+        ${msg("emailVerifyTitle")}
     <#elseif section = "header">
-        ${rb.emailVerifyTitle}
+        ${msg("emailVerifyTitle")}
     <#elseif section = "form">
         <p class="instruction">
-            ${rb.emailVerifyInstruction1}
+            ${msg("emailVerifyInstruction1")}
         </p>
         <p class="instruction">
-            ${rb.emailVerifyInstruction2} <a href="${url.loginEmailVerificationUrl}">${rb.doClickHere}</a> ${rb.emailVerifyInstruction3}
+            ${msg("emailVerifyInstruction2")} <a href="${url.loginEmailVerificationUrl}">${msg("doClickHere")}</a> ${msg("emailVerifyInstruction3")}
         </p>
     </#if>
 </@layout.registrationLayout>
\ No newline at end of file
diff --git a/forms/common-themes/src/main/resources/theme/login/base/messages/messages_de.properties b/forms/common-themes/src/main/resources/theme/login/base/messages/messages_de.properties
index 70d8aba..c4c2bef 100644
--- a/forms/common-themes/src/main/resources/theme/login/base/messages/messages_de.properties
+++ b/forms/common-themes/src/main/resources/theme/login/base/messages/messages_de.properties
@@ -79,7 +79,6 @@ invalidTotpMessage=Ung�ltiger One-time Code.
 usernameExistsMessage=Benutzermane exisitert bereits.
 emailExistsMessage=E-Mail existiert bereits.
 
-federatedIdentityRegistrationEmailMissingMessage=Die E-Mail Adresse ist nicht vorhanden. Bitte verwenden Sie einen anderen Provider um das Benutzerkonto zu erstellen.
 federatedIdentityEmailExistsMessage=Es exisitert bereits ein Benutzer mit dieser E-Mail Adresse. Bitte melden Sie sich bei der Benutzerverwaltung an um das Benutzerkonto zu verkn�pfen.
 federatedIdentityUsernameExistsMessage=Es exisitert bereits ein Benutzer mit diesem Benutzernamen. Bitte melden Sie sich bei der Benutzerverwaltung an um das Benutzerkonto zu verkn�pfen.
 
diff --git a/forms/common-themes/src/main/resources/theme/login/base/messages/messages_en.properties b/forms/common-themes/src/main/resources/theme/login/base/messages/messages_en.properties
index 6f48c59..afbe584 100755
--- a/forms/common-themes/src/main/resources/theme/login/base/messages/messages_en.properties
+++ b/forms/common-themes/src/main/resources/theme/login/base/messages/messages_en.properties
@@ -17,8 +17,8 @@ loginTotpTitle=Mobile Authenticator Setup
 loginProfileTitle=Update Account Information
 oauthGrantTitle=OAuth Grant
 oauthGrantTitleHtml=Temporary access for <strong>{0}</strong> requested by <strong>{1}</strong>.
-errorTitle=We're sorry...
-errorTitleHtml=We're <strong>sorry</strong> ...
+errorTitle=We''re sorry...
+errorTitleHtml=We''re <strong>sorry</strong> ...
 emailVerifyTitle=Email verification
 emailForgotTitle=Forgot Your Password?
 updatePasswordTitle=Update password
@@ -50,7 +50,7 @@ loginTotpOneTime=One-time code
 oauthGrantRequest=Do you grant these access privileges?
 
 emailVerifyInstruction1=An email with instructions to verify your email address has been sent to you.
-emailVerifyInstruction2=Haven't received a verification code in your email?
+emailVerifyInstruction2=Haven''t received a verification code in your email?
 emailVerifyInstruction3=to re-send the email.
 
 backToLogin=&laquo; Back to Login
@@ -69,10 +69,10 @@ missingEmailMessage=Please specify email.
 missingUsernameMessage=Please specify username.
 missingPasswordMessage=Please specify password.
 missingTotpMessage=Please specify authenticator code.
-notMatchPasswordMessage=Passwords don't match.
+notMatchPasswordMessage=Passwords don''t match.
 
 invalidPasswordExistingMessage=Invalid existing password.
-invalidPasswordConfirmMessage=Password confirmation doesn't match.
+invalidPasswordConfirmMessage=Password confirmation doesn''t match.
 invalidTotpMessage=Invalid authenticator code.
 
 usernameExistsMessage=Username already exists.
@@ -143,4 +143,3 @@ backToApplication=&laquo; Back to Application
 missingParameterMessage=Missing parameters\: {0}
 clientNotFoundMessage=Client not found.
 invalidParameterMessage=Invalid parameter\: {0}
-federatedIdentityRegistrationEmailMissingMessage=Email is not provided. Use another provider to create account please.
diff --git a/forms/common-themes/src/main/resources/theme/login/base/register.ftl b/forms/common-themes/src/main/resources/theme/login/base/register.ftl
index 8dcdcea..930a07d 100755
--- a/forms/common-themes/src/main/resources/theme/login/base/register.ftl
+++ b/forms/common-themes/src/main/resources/theme/login/base/register.ftl
@@ -1,15 +1,15 @@
 <#import "template.ftl" as layout>
 <@layout.registrationLayout; section>
     <#if section = "title">
-        ${formatter.format(rb.registerWithTitle,(realm.name!''))}
+        ${msg("registerWithTitle",(realm.name!''))}
     <#elseif section = "header">
-         ${formatter.format(rb.registerWithTitleHtml,(realm.name!''))}
+         ${msg("registerWithTitleHtml",(realm.name!''))}
     <#elseif section = "form">
         <form id="kc-register-form" class="${properties.kcFormClass!}" action="${url.registrationAction}" method="post">
           <#if !realm.registrationEmailAsUsername>
             <div class="${properties.kcFormGroupClass!}">
                 <div class="${properties.kcLabelWrapperClass!}">
-                    <label for="username" class="${properties.kcLabelClass!}">${rb.username}</label>
+                    <label for="username" class="${properties.kcLabelClass!}">${msg("username")}</label>
                 </div>
                 <div class="${properties.kcInputWrapperClass!}">
                     <input type="text" id="username" class="${properties.kcInputClass!}" name="username" value="${(register.formData.username!'')?html}" />
@@ -18,7 +18,7 @@
           </#if>
             <div class="${properties.kcFormGroupClass!}">
                 <div class="${properties.kcLabelWrapperClass!}">
-                    <label for="firstName" class="${properties.kcLabelClass!}">${rb.firstName}</label>
+                    <label for="firstName" class="${properties.kcLabelClass!}">${msg("firstName")}</label>
                 </div>
                 <div class="${properties.kcInputWrapperClass!}">
                     <input type="text" id="firstName" class="${properties.kcInputClass!}" name="firstName" value="${(register.formData.firstName!'')?html}" />
@@ -27,7 +27,7 @@
 
             <div class="${properties.kcFormGroupClass!}">
                 <div class="${properties.kcLabelWrapperClass!}">
-                    <label for="lastName" class="${properties.kcLabelClass!}">${rb.lastName}</label>
+                    <label for="lastName" class="${properties.kcLabelClass!}">${msg("lastName")}</label>
                 </div>
                 <div class="${properties.kcInputWrapperClass!}">
                     <input type="text" id="lastName" class="${properties.kcInputClass!}" name="lastName" value="${(register.formData.lastName!'')?html}" />
@@ -36,7 +36,7 @@
 
             <div class="${properties.kcFormGroupClass!}">
                 <div class="${properties.kcLabelWrapperClass!}">
-                    <label for="email" class="${properties.kcLabelClass!}">${rb.email}</label>
+                    <label for="email" class="${properties.kcLabelClass!}">${msg("email")}</label>
                 </div>
                 <div class="${properties.kcInputWrapperClass!}">
                     <input type="text" id="email" class="${properties.kcInputClass!}" name="email" value="${(register.formData.email!'')?html}" />
@@ -45,7 +45,7 @@
 
             <div class="${properties.kcFormGroupClass!}">
                 <div class="${properties.kcLabelWrapperClass!}">
-                    <label for="password" class="${properties.kcLabelClass!}">${rb.password}</label>
+                    <label for="password" class="${properties.kcLabelClass!}">${msg("password")}</label>
                 </div>
                 <div class="${properties.kcInputWrapperClass!}">
                     <input type="password" id="password" class="${properties.kcInputClass!}" name="password" />
@@ -54,7 +54,7 @@
 
             <div class="${properties.kcFormGroupClass!}">
                 <div class="${properties.kcLabelWrapperClass!}">
-                    <label for="password-confirm" class="${properties.kcLabelClass!}">${rb.passwordConfirm}</label>
+                    <label for="password-confirm" class="${properties.kcLabelClass!}">${msg("passwordConfirm")}</label>
                 </div>
                 <div class="${properties.kcInputWrapperClass!}">
                     <input type="password" id="password-confirm" class="${properties.kcInputClass!}" name="password-confirm" />
@@ -63,7 +63,7 @@
 
             <div class="form-group">
                 <div class="${properties.kcLabelWrapperClass!}">
-                    <label for="user.attributes.street" class="${properties.kcLabelClass!}">${rb.street}</label>
+                    <label for="user.attributes.street" class="${properties.kcLabelClass!}">${msg("street")}</label>
                 </div>
 
                 <div class="${properties.kcInputWrapperClass!}">
@@ -72,7 +72,7 @@
             </div>
             <div class="form-group">
                 <div class="${properties.kcLabelWrapperClass!}">
-                    <label for="user.attributes.locality" class="${properties.kcLabelClass!}">${rb.locality}</label>
+                    <label for="user.attributes.locality" class="${properties.kcLabelClass!}">${msg("locality")}</label>
                 </div>
 
                 <div class="${properties.kcInputWrapperClass!}">
@@ -81,7 +81,7 @@
             </div>
             <div class="form-group">
                 <div class="${properties.kcLabelWrapperClass!}">
-                    <label for="user.attributes.region" class="${properties.kcLabelClass!}">${rb.region}</label>
+                    <label for="user.attributes.region" class="${properties.kcLabelClass!}">${msg("region")}</label>
                 </div>
 
                 <div class="${properties.kcInputWrapperClass!}">
@@ -90,7 +90,7 @@
             </div>
             <div class="form-group">
                 <div class="${properties.kcLabelWrapperClass!}">
-                    <label for="user.attributes.postal_code" class="${properties.kcLabelClass!}">${rb.postal_code}</label>
+                    <label for="user.attributes.postal_code" class="${properties.kcLabelClass!}">${msg("postal_code")}</label>
                 </div>
 
                 <div class="${properties.kcInputWrapperClass!}">
@@ -99,7 +99,7 @@
             </div>
             <div class="form-group">
                 <div class="${properties.kcLabelWrapperClass!}">
-                    <label for="user.attributes.country" class="${properties.kcLabelClass!}">${rb.country}</label>
+                    <label for="user.attributes.country" class="${properties.kcLabelClass!}">${msg("country")}</label>
                 </div>
 
                 <div class="${properties.kcInputWrapperClass!}">
@@ -111,12 +111,12 @@
             <div class="${properties.kcFormGroupClass!}">
                 <div id="kc-form-options" class="${properties.kcFormOptionsClass!}">
                     <div class="${properties.kcFormOptionsWrapperClass!}">
-                        <span><a href="${url.loginUrl}">${rb.backToLogin}</a></span>
+                        <span><a href="${url.loginUrl}">${msg("backToLogin")}</a></span>
                     </div>
                 </div>
 
                 <div id="kc-form-buttons" class="${properties.kcFormButtonsClass!}">
-                    <input class="btn btn-primary btn-lg" type="submit" value="${rb.doRegister}"/>
+                    <input class="btn btn-primary btn-lg" type="submit" value="${msg("doRegister")}"/>
                 </div>
             </div>
         </form>
diff --git a/forms/common-themes/src/main/resources/theme/login/base/template.ftl b/forms/common-themes/src/main/resources/theme/login/base/template.ftl
index c09271d..907cfd5 100644
--- a/forms/common-themes/src/main/resources/theme/login/base/template.ftl
+++ b/forms/common-themes/src/main/resources/theme/login/base/template.ftl
@@ -21,19 +21,6 @@
             <script src="${url.resourcesPath}/${script}" type="text/javascript"></script>
         </#list>
     </#if>
-    <#if realm.internationalizationEnabled>
-        <script type="text/javascript">
-            window.onload = function () {
-                var select = document.querySelector(".kc-locale-select");
-                select.onchange = function (event) {
-                    document.cookie = "KEYCLOAK_LOCALE=" + select.value+"; path=${url.localeCookiePath}";
-                    setTimeout(function () {
-                        window.location.reload();
-                    }, 0);
-                }
-            }
-        </script>
-    </#if>
 </head>
 
 <body class="${properties.kcBodyClass!}">
@@ -44,15 +31,6 @@
 
             <div id="kc-header" class="${properties.kcHeaderClass!}">
                 <div id="kc-header-wrapper" class="${properties.kcHeaderWrapperClass!}"><#nested "header"></div>
-                <#if realm.internationalizationEnabled>
-                    <div id="kc-locale-wrapper" class="${properties.kcLocaleWrapperClass!}">
-                        <select class="kc-locale-select">
-                            <#list realm.supportedLocales as l>
-                                <option value="${l}" <#if locale.toLanguageTag()==l>selected="selected"</#if>>${rb["locale_" + l]}</option>
-                            </#list>
-                        </select>
-                    </div>
-                </#if>
             </div>
 
             <#if displayMessage && message?has_content>
@@ -61,6 +39,25 @@
                         <span class="kc-feedback-text">${message.summary}</span>
                     </div>
                 </div>
+            <#else>
+                <div id="kc-feedback-placeholder" class="${properties.kcFeedBackPlaceholderClass!}">
+                    <div id="kc-feedback-placeholder-wrapper"></div>
+                </div>
+            </#if>
+
+            <#if realm.internationalizationEnabled>
+                <div id="kc-locale" class="${properties.kcLocaleClass!}">
+                    <div id="kc-locale-wrapper" class="${properties.kcLocaleWrapperClass!}">
+                        <div class="kc-dropdown">
+                            <a href="#">${locale.current}</a>
+                            <ul>
+                                <#list locale.supported as l>
+                                    <li class="kc-dropdown-item"><a href="${l.url}">${l.label}</a></li>
+                                </#list>
+                            </ul>
+                        </div>
+                    </div>
+                </div>
             </#if>
 
             <div id="kc-content" class="${properties.kcContentClass!}">
@@ -85,7 +82,7 @@
 
     <!--
         <p class="powered">
-            <a href="http://www.keycloak.org">${rb.poweredByKeycloak}</a>
+            <a href="http://www.keycloak.org">${msg("poweredByKeycloak")}</a>
         </p>
     </div>
     -->
diff --git a/forms/common-themes/src/main/resources/theme/login/patternfly/resources/css/login.css b/forms/common-themes/src/main/resources/theme/login/patternfly/resources/css/login.css
index a3fc592..345f594 100644
--- a/forms/common-themes/src/main/resources/theme/login/patternfly/resources/css/login.css
+++ b/forms/common-themes/src/main/resources/theme/login/patternfly/resources/css/login.css
@@ -1,3 +1,58 @@
+.kc-dropdown{
+    position: relative;
+}
+.kc-dropdown > a{
+    position: absolute;
+    right: 0px;
+    display:block;
+    padding: 11px 10px 12px;
+    line-height: 12px;
+    font-size: 12px;
+    color: #fff !important;
+    text-decoration: none;
+}
+.kc-dropdown > a::after{
+    content: "\2c5";
+    margin-left: 4px;
+}
+.kc-dropdown:hover > a{
+    background-color: rgba(0,0,0,0.2);
+}
+.kc-dropdown ul li a{
+    padding: 1px 11px;
+    font-size: 12px;
+    color: #000 !important;
+    border: 1px solid #fff;
+    text-decoration: none;
+    display:block;
+    line-height: 20px;
+}
+.kc-dropdown ul li a:hover{
+    color: #4d5258;
+    background-color: #d4edfa;
+    border-color: #b3d3e7;
+}
+.kc-dropdown ul{
+    position: absolute;
+    right: 0px;
+    top: 35px;
+    z-index: 2000;
+    list-style:none;
+    display:none;
+    padding: 5px 0px;
+    margin: 0px;
+    background-color: #fff !important;
+    border: 1px solid #b6b6b6;
+    border-radius: 1px;
+    -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
+    box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
+    background-clip: padding-box;
+    min-width: 100px;
+}
+.kc-dropdown:hover ul{
+    display:block;
+}
+
 .login-pf .container {
     padding-top: 40px;
 }
@@ -237,8 +292,6 @@ ol#kc-totp-settings li:first-of-type {
     }
 
     #kc-form {
-        padding-left: 15px;
-        padding-right: 15px;
         float: none;
     }
 
diff --git a/forms/common-themes/src/main/resources/theme/login/patternfly/theme.properties b/forms/common-themes/src/main/resources/theme/login/patternfly/theme.properties
index 4b85665..25427a7 100644
--- a/forms/common-themes/src/main/resources/theme/login/patternfly/theme.properties
+++ b/forms/common-themes/src/main/resources/theme/login/patternfly/theme.properties
@@ -10,8 +10,9 @@ kcContentClass=col-sm-12 col-md-12 col-lg-12 container
 kcContentWrapperClass=row
 
 kcHeaderClass=col-xs-12 col-sm-7 col-md-6 col-lg-5
-
-kcFeedBackClass=col-xs-12 col-sm-5 col-md-6 col-lg-7
+kcFeedBackClass=col-xs-12 col-sm-4 col-md-5 col-lg-6
+kcFeedBackPlaceholderClass=col-xs-12 col-sm-4 col-md-5 col-lg-6
+kcLocaleClass=col-xs-12 col-sm-1
 
 kcFormAreaClass=col-xs-12 col-sm-8 col-md-8 col-lg-6 login
 
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 21972b2..505a416 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
@@ -10,7 +10,7 @@ import org.keycloak.freemarker.FreeMarkerUtil;
 import org.keycloak.freemarker.LocaleHelper;
 import org.keycloak.freemarker.Theme;
 import org.keycloak.freemarker.ThemeProvider;
-import org.keycloak.freemarker.beans.TextFormatterBean;
+import org.keycloak.freemarker.beans.MessageFormatterMethod;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserModel;
@@ -20,6 +20,7 @@ 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.*;
 
 /**
@@ -84,9 +85,8 @@ public class FreeMarkerEmailProvider implements EmailProvider {
             Locale locale = LocaleHelper.getLocale(realm, user);
             attributes.put("locale", locale);
             Properties rb = theme.getMessages(locale);
-            attributes.put("rb", rb);
-            attributes.put("formatter", new TextFormatterBean(locale));
-            String subject =  rb.getProperty(subjectKey);
+            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);
 
             send(subject, body);
diff --git a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/FreeMarkerLoginFormsProvider.java b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/FreeMarkerLoginFormsProvider.java
index 14579b9..44c8bad 100755
--- a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/FreeMarkerLoginFormsProvider.java
+++ b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/FreeMarkerLoginFormsProvider.java
@@ -6,11 +6,12 @@ import org.keycloak.OAuth2Constants;
 import org.keycloak.email.EmailException;
 import org.keycloak.email.EmailProvider;
 import org.keycloak.freemarker.*;
-import org.keycloak.freemarker.beans.TextFormatterBean;
+import org.keycloak.freemarker.beans.MessageFormatterMethod;
 import org.keycloak.login.LoginFormsPages;
 import org.keycloak.login.LoginFormsProvider;
 import org.keycloak.login.freemarker.model.ClientBean;
 import org.keycloak.login.freemarker.model.CodeBean;
+import org.keycloak.freemarker.beans.LocaleBean;
 import org.keycloak.login.freemarker.model.LoginBean;
 import org.keycloak.login.freemarker.model.MessageBean;
 import org.keycloak.login.freemarker.model.OAuthGrantBean;
@@ -27,7 +28,6 @@ import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.services.messages.Messages;
-import org.keycloak.services.resources.LoginActionsService;
 import org.keycloak.services.resources.flows.Urls;
 
 import javax.ws.rs.core.*;
@@ -176,13 +176,9 @@ import java.util.concurrent.TimeUnit;
 
         Properties messages;
         Locale locale = LocaleHelper.getLocale(realm, user, uriInfo, httpHeaders);
-        if(locale != null){
-            attributes.put("locale", locale);
-            attributes.put("formatter", new TextFormatterBean(locale));
-        }
         try {
             messages = theme.getMessages(locale);
-            attributes.put("rb", messages);
+            attributes.put("msg", new MessageFormatterMethod(locale, messages));
         } catch (IOException e) {
             logger.warn("Failed to load messages", e);
             messages = new Properties();
@@ -191,7 +187,7 @@ import java.util.concurrent.TimeUnit;
         if (message != null) {
             String formattedMessage;
             if(messages.containsKey(message)){
-                formattedMessage = new MessageFormat(messages.getProperty(message).replace("'","''"),locale).format(parameters);
+                formattedMessage = new MessageFormat(messages.getProperty(message),locale).format(parameters);
             }else{
                 formattedMessage = message;
             }
@@ -207,6 +203,22 @@ import java.util.concurrent.TimeUnit;
             attributes.put("realm", new RealmBean(realm));
             attributes.put("social", new IdentityProviderBean(realm, baseUri, this.uriInfo));
             attributes.put("url", new UrlBean(realm, theme, baseUri, this.actionUri));
+
+            if (realm.isInternationalizationEnabled()) {
+                UriBuilder b;
+                switch (page) {
+                    case LOGIN:
+                        b = UriBuilder.fromUri(Urls.realmLoginPage(baseUri, realm.getName()));
+                        break;
+                    case REGISTER:
+                        b = UriBuilder.fromUri(Urls.realmRegisterPage(baseUri, realm.getName()));
+                        break;
+                    default:
+                        b = UriBuilder.fromUri(baseUri).path(uriInfo.getPath());
+                        break;
+                }
+                attributes.put("locale", new LocaleBean(realm, locale, b, messages));
+            }
         }
 
         if (client != null) {
diff --git a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/RealmBean.java b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/RealmBean.java
index 3e36d08..b161ad2 100755
--- a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/RealmBean.java
+++ b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/RealmBean.java
@@ -66,10 +66,6 @@ public class RealmBean {
         return realm.isInternationalizationEnabled();
     }
 
-    public Set<String> getSupportedLocales(){
-        return realm.getSupportedLocales();
-    }
-
     public boolean isPassword() {
         for (RequiredCredentialModel r : realm.getRequiredCredentials()) {
             if (r.getType().equals(CredentialRepresentation.PASSWORD)) {
diff --git a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/UrlBean.java b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/UrlBean.java
index 259b098..eb9a40b 100755
--- a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/UrlBean.java
+++ b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/UrlBean.java
@@ -34,9 +34,7 @@ public class UrlBean {
 
     private final URI actionuri;
     private URI baseURI;
-
     private Theme theme;
-
     private String realm;
 
     public UrlBean(RealmModel realm, Theme theme, URI baseURI, URI actionUri) {
@@ -86,10 +84,6 @@ public class UrlBean {
         return Urls.loginActionEmailVerification(baseURI, realm).toString();
     }
 
-    public String getLocaleCookiePath(){
-        return Urls.localeCookiePath(baseURI, realm);
-    }
-
     public String getOauthAction() {
         if (this.actionuri != null) {
             return this.actionuri.getPath();
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/RolesResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/RolesResource.java
index f7a0af1..bebff63 100755
--- a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/RolesResource.java
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/RolesResource.java
@@ -3,6 +3,7 @@ package org.keycloak.admin.client.resource;
 import org.keycloak.representations.idm.RoleRepresentation;
 
 import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
 import javax.ws.rs.Path;
@@ -27,5 +28,8 @@ public interface RolesResource {
     @Path("{roleName}")
     public RoleResource get(@PathParam("roleName") String roleName);
 
+    @Path("{role-name}")
+    @DELETE
+    public void deleteRole(final @PathParam("role-name") String roleName);
 
 }
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/token/TokenManager.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/token/TokenManager.java
index f5a796d..e38da50 100644
--- a/integration/admin-client/src/main/java/org/keycloak/admin/client/token/TokenManager.java
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/token/TokenManager.java
@@ -43,6 +43,7 @@ public class TokenManager {
         ResteasyWebTarget target = client.target(config.getServerUrl());
 
         Form form = new Form()
+                .param("grant_type", "password")
                 .param("username", config.getUsername())
                 .param("password", config.getPassword());
 
@@ -64,6 +65,7 @@ public class TokenManager {
         ResteasyWebTarget target = client.target(config.getServerUrl());
 
         Form form = new Form()
+                .param("grant_type", "refresh_token")
                 .param("username", config.getUsername())
                 .param("password", config.getPassword());
 
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/token/TokenService.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/token/TokenService.java
index 376e5f0..4711b26 100755
--- a/integration/admin-client/src/main/java/org/keycloak/admin/client/token/TokenService.java
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/token/TokenService.java
@@ -18,11 +18,11 @@ import javax.ws.rs.core.MultivaluedMap;
 public interface TokenService {
 
     @POST
-    @Path("/realms/{realm}/protocol/openid-connect/grants/access")
+    @Path("/realms/{realm}/protocol/openid-connect/token")
     public AccessTokenResponse grantToken(@PathParam("realm") String realm, MultivaluedMap<String, String> map);
 
     @POST
-    @Path("/realms/{realm}/protocol/openid-connect/refresh")
+    @Path("/realms/{realm}/protocol/openid-connect/token")
     public AccessTokenResponse refreshToken(@PathParam("realm") String realm, MultivaluedMap<String, String> map);
 
 }
diff --git a/integration/keycloak-as7-subsystem/src/main/java/org/keycloak/subsystem/extension/SecureDeploymentDefinition.java b/integration/keycloak-as7-subsystem/src/main/java/org/keycloak/subsystem/extension/SecureDeploymentDefinition.java
index c2cb88d..60c65fb 100755
--- a/integration/keycloak-as7-subsystem/src/main/java/org/keycloak/subsystem/extension/SecureDeploymentDefinition.java
+++ b/integration/keycloak-as7-subsystem/src/main/java/org/keycloak/subsystem/extension/SecureDeploymentDefinition.java
@@ -68,6 +68,12 @@ public class SecureDeploymentDefinition extends SimpleResourceDefinition {
                     .setAllowExpression(true)
                     .setDefaultValue(new ModelNode(false))
                     .build();
+    protected static final SimpleAttributeDefinition ENABLE_BASIC_AUTH =
+            new SimpleAttributeDefinitionBuilder("enable-basic-auth", ModelType.BOOLEAN, true)
+                    .setXmlName("enable-basic-auth")
+                    .setAllowExpression(true)
+                    .setDefaultValue(new ModelNode(false))
+                    .build();
     protected static final SimpleAttributeDefinition PUBLIC_CLIENT =
             new SimpleAttributeDefinitionBuilder("public-client", ModelType.BOOLEAN, true)
                     .setXmlName("public-client")
@@ -81,6 +87,7 @@ public class SecureDeploymentDefinition extends SimpleResourceDefinition {
         DEPLOYMENT_ONLY_ATTRIBUTES.add(RESOURCE);
         DEPLOYMENT_ONLY_ATTRIBUTES.add(USE_RESOURCE_ROLE_MAPPINGS);
         DEPLOYMENT_ONLY_ATTRIBUTES.add(BEARER_ONLY);
+        DEPLOYMENT_ONLY_ATTRIBUTES.add(ENABLE_BASIC_AUTH);
         DEPLOYMENT_ONLY_ATTRIBUTES.add(PUBLIC_CLIENT);
     }
 
diff --git a/integration/keycloak-as7-subsystem/src/main/resources/schema/keycloak_1_0.xsd b/integration/keycloak-as7-subsystem/src/main/resources/schema/keycloak_1_0.xsd
index 6afc3f1..10257d4 100755
--- a/integration/keycloak-as7-subsystem/src/main/resources/schema/keycloak_1_0.xsd
+++ b/integration/keycloak-as7-subsystem/src/main/resources/schema/keycloak_1_0.xsd
@@ -46,6 +46,7 @@
                 <xs:element name="use-resource-role-mappings" type="xs:boolean" minOccurs="0" maxOccurs="1" />
                 <xs:element name="bearer-only" type="xs:boolean" minOccurs="0" maxOccurs="1" />
                 <xs:element name="credential" maxOccurs="unbounded" minOccurs="0" type="xs:credential-type"/>
+                <xs:element name="enable-basic-auth" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
             </xs:extension>
         </xs:complexContent>
     </xs:complexType>
diff --git a/integration/wildfly-extensions/pom.xml b/integration/wildfly-extensions/pom.xml
index e627d32..4e19872 100755
--- a/integration/wildfly-extensions/pom.xml
+++ b/integration/wildfly-extensions/pom.xml
@@ -43,6 +43,18 @@
         </dependency>
         <dependency>
             <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-forms-common-freemarker</artifactId>
+            <version>${project.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-forms-common-themes</artifactId>
+            <version>${project.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
             <artifactId>keycloak-services</artifactId>
             <version>${project.version}</version>
             <scope>provided</scope>
diff --git a/integration/wildfly-extensions/src/main/java/org/keycloak/provider/wildfly/ModuleThemeProviderFactory.java b/integration/wildfly-extensions/src/main/java/org/keycloak/provider/wildfly/ModuleThemeProviderFactory.java
new file mode 100644
index 0000000..231ff07
--- /dev/null
+++ b/integration/wildfly-extensions/src/main/java/org/keycloak/provider/wildfly/ModuleThemeProviderFactory.java
@@ -0,0 +1,35 @@
+package org.keycloak.provider.wildfly;
+
+import org.jboss.modules.Module;
+import org.jboss.modules.ModuleClassLoader;
+import org.jboss.modules.ModuleIdentifier;
+import org.keycloak.Config;
+import org.keycloak.theme.JarThemeProviderFactory;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class ModuleThemeProviderFactory extends JarThemeProviderFactory {
+
+    @Override
+    public void init(Config.Scope config) {
+        String[] modules = config.getArray("modules");
+        if (modules != null) {
+            try {
+                for (String moduleSpec : modules) {
+                    Module module = Module.getContextModuleLoader().loadModule(ModuleIdentifier.fromString(moduleSpec));
+                    ModuleClassLoader classLoader = module.getClassLoader();
+                    loadThemes(classLoader, classLoader.getResourceAsStream(KEYCLOAK_THEMES_JSON));
+                }
+            } catch (Exception e) {
+                throw new RuntimeException("Failed to load themes", e);
+            }
+        }
+    }
+
+    @Override
+    public String getId() {
+        return "module";
+    }
+
+}
diff --git a/integration/wildfly-extensions/src/main/resources/META-INF/services/org.keycloak.freemarker.ThemeProviderFactory b/integration/wildfly-extensions/src/main/resources/META-INF/services/org.keycloak.freemarker.ThemeProviderFactory
new file mode 100644
index 0000000..c5515a6
--- /dev/null
+++ b/integration/wildfly-extensions/src/main/resources/META-INF/services/org.keycloak.freemarker.ThemeProviderFactory
@@ -0,0 +1 @@
+org.keycloak.provider.wildfly.ModuleThemeProviderFactory
\ No newline at end of file
diff --git a/model/api/src/main/java/org/keycloak/models/ClaimMask.java b/model/api/src/main/java/org/keycloak/models/ClaimMask.java
index 3a65034..da8063f 100755
--- a/model/api/src/main/java/org/keycloak/models/ClaimMask.java
+++ b/model/api/src/main/java/org/keycloak/models/ClaimMask.java
@@ -49,4 +49,6 @@ public class ClaimMask {
         return (mask & PHONE) > 0;
     }
 
+
+
 }
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 8313c32..7e88c9a 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
@@ -108,6 +108,15 @@ public class ModelToRepresentation {
         rep.setQuickLoginCheckMilliSeconds(realm.getQuickLoginCheckMilliSeconds());
         rep.setMaxDeltaTimeSeconds(realm.getMaxDeltaTimeSeconds());
         rep.setFailureFactor(realm.getFailureFactor());
+
+        rep.setEventsEnabled(realm.isEventsEnabled());
+        if (realm.getEventsExpiration() != 0) {
+            rep.setEventsExpiration(realm.getEventsExpiration());
+        }
+        if (realm.getEventsListeners() != null) {
+            rep.setEventsListeners(new LinkedList<String>(realm.getEventsListeners()));
+        }
+
         rep.setVerifyEmail(realm.isVerifyEmail());
         rep.setResetPasswordAllowed(realm.isResetPasswordAllowed());
         rep.setAccessTokenLifespan(realm.getAccessTokenLifespan());
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 aa90067..b23a367 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
@@ -31,6 +31,7 @@ import org.keycloak.representations.idm.ProtocolMapperRepresentation;
 import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.representations.idm.RoleRepresentation;
 import org.keycloak.representations.idm.ScopeMappingRepresentation;
+import org.keycloak.representations.idm.SocialLinkRepresentation;
 import org.keycloak.representations.idm.UserFederationProviderRepresentation;
 import org.keycloak.representations.idm.UserRepresentation;
 
@@ -39,6 +40,7 @@ import java.net.URI;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -48,6 +50,8 @@ public class RepresentationToModel {
     private static Logger logger = Logger.getLogger(RepresentationToModel.class);
 
     public static void importRealm(KeycloakSession session, RealmRepresentation rep, RealmModel newRealm) {
+        convertDeprecatedSocialProviders(rep);
+
         newRealm.setName(rep.getRealm());
         if (rep.isEnabled() != null) newRealm.setEnabled(rep.isEnabled());
         if (rep.isBruteForceProtected() != null) newRealm.setBruteForceProtected(rep.isBruteForceProtected());
@@ -255,6 +259,56 @@ public class RepresentationToModel {
         }
     }
 
+    private static void convertDeprecatedSocialProviders(RealmRepresentation rep) {
+        if (rep.isSocial() != null && rep.isSocial() && rep.getSocialProviders() != null && !rep.getSocialProviders().isEmpty() && rep.getIdentityProviders() == null) {
+            Boolean updateProfileFirstLogin = rep.isUpdateProfileOnInitialSocialLogin() != null && rep.isUpdateProfileOnInitialSocialLogin();
+            if (rep.getSocialProviders() != null) {
+
+                List<IdentityProviderRepresentation> identityProviders = new LinkedList<>();
+                for (String k : rep.getSocialProviders().keySet()) {
+                    if (k.endsWith(".key")) {
+                        String providerId = k.split("\\.")[0];
+                        String key = rep.getSocialProviders().get(k);
+                        String secret = rep.getSocialProviders().get(k.replace(".key", ".secret"));
+
+                        IdentityProviderRepresentation identityProvider = new IdentityProviderRepresentation();
+                        identityProvider.setAlias(providerId);
+                        identityProvider.setProviderId(providerId);
+                        identityProvider.setEnabled(true);
+                        identityProvider.setUpdateProfileFirstLogin(updateProfileFirstLogin);
+
+                        Map<String, String> config = new HashMap<>();
+                        config.put("clientId", key);
+                        config.put("clientSecret", secret);
+                        identityProvider.setConfig(config);
+
+                        identityProviders.add(identityProvider);
+                    }
+                }
+                rep.setIdentityProviders(identityProviders);
+            }
+        }
+
+        rep.setSocial(null);
+        rep.setSocialProviders(null);
+        rep.setUpdateProfileOnInitialSocialLogin(false);
+    }
+
+    private static void convertDeprecatedSocialProviders(UserRepresentation user) {
+        if (user.getSocialLinks() != null && !user.getSocialLinks().isEmpty() && user.getFederatedIdentities() == null) {
+            List<FederatedIdentityRepresentation> federatedIdentities = new LinkedList<>();
+            for (SocialLinkRepresentation social : user.getSocialLinks()) {
+                FederatedIdentityRepresentation federatedIdentity = new FederatedIdentityRepresentation();
+                federatedIdentity.setIdentityProvider(social.getSocialProvider());
+                federatedIdentity.setUserId(social.getSocialUserId());
+                federatedIdentity.setUserName(social.getSocialUsername());
+            }
+            user.setFederatedIdentities(federatedIdentities);
+        }
+
+        user.setSocialLinks(null);
+    }
+
     public static void updateRealm(RealmRepresentation rep, RealmModel realm) {
         if (rep.getRealm() != null) {
             realm.setName(rep.getRealm());
@@ -688,6 +742,8 @@ public class RepresentationToModel {
     // Users
 
     public static UserModel createUser(KeycloakSession session, RealmModel newRealm, UserRepresentation userRep, Map<String, ApplicationModel> appMap) {
+        convertDeprecatedSocialProviders(userRep);
+
         // Import users just to user storage. Don't federate
         UserModel user = session.userStorage().addUser(newRealm, userRep.getId(), userRep.getUsername(), false);
         user.setEnabled(userRep.isEnabled());
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 10f128f..132b949 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
@@ -1000,8 +1000,8 @@ public class RealmAdapter implements RealmModel {
         if (!role.getContainer().equals(this)) return false;
         session.users().preRemove(this, role);
         RoleEntity roleEntity = RoleAdapter.toRoleEntity(role, em);
-        realm.getRoles().remove(role);
-        realm.getDefaultRoles().remove(role);
+        realm.getRoles().remove(roleEntity);
+        realm.getDefaultRoles().remove(roleEntity);
 
         em.createNativeQuery("delete from COMPOSITE_ROLE where CHILD_ROLE = :role").setParameter("role", roleEntity).executeUpdate();
         em.createNamedQuery("deleteScopeMappingByRole").setParameter("role", roleEntity).executeUpdate();
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 df13023..ba0c8d7 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
@@ -1101,9 +1101,9 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
     @Override
     public void setSupportedLocales(Set<String> locales) {
         if (locales != null) {
-            realm.setEventsListeners(new ArrayList<String>(locales));
+            realm.setSupportedLocales(new ArrayList<String>(locales));
         } else {
-            realm.setEventsListeners(Collections.EMPTY_LIST);
+            realm.setSupportedLocales(Collections.EMPTY_LIST);
         }
         updateRealm();
     }
diff --git a/project-integrations/aerogear-ups/auth-server/src/main/resources/META-INF/keycloak-themes.json b/project-integrations/aerogear-ups/auth-server/src/main/resources/META-INF/keycloak-themes.json
new file mode 100644
index 0000000..09db937
--- /dev/null
+++ b/project-integrations/aerogear-ups/auth-server/src/main/resources/META-INF/keycloak-themes.json
@@ -0,0 +1,6 @@
+{
+    "themes": [{
+        "name" : "aerogear",
+        "types": [ "admin", "account", "login" ]
+    }]
+}
\ No newline at end of file
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java
index 5a55996..2ec8ec6 100755
--- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java
@@ -6,14 +6,11 @@ import org.jboss.resteasy.client.ClientResponse;
 import org.jboss.resteasy.client.core.executors.ApacheHttpClient4Executor;
 import org.keycloak.events.EventBuilder;
 import org.keycloak.models.ApplicationModel;
-import org.keycloak.models.ClaimMask;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.ClientSessionModel;
 import org.keycloak.models.KeycloakSession;
-import org.keycloak.models.KeycloakSessionFactory;
 import org.keycloak.models.ProtocolMapperModel;
 import org.keycloak.models.RealmModel;
-import org.keycloak.models.RoleModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.UserSessionModel;
 import org.keycloak.protocol.LoginProtocol;
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocolFactory.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocolFactory.java
index 8ef3c80..83afe93 100755
--- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocolFactory.java
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocolFactory.java
@@ -51,6 +51,11 @@ public class SamlProtocolFactory extends AbstractLoginProtocolFactory {
         return builtins;
     }
 
+    @Override
+    public List<ProtocolMapperModel> getDefaultBuiltinMappers() {
+        return defaultBuiltins;
+    }
+
     static List<ProtocolMapperModel> builtins = new ArrayList<>();
     static List<ProtocolMapperModel> defaultBuiltins = new ArrayList<>();
 
diff --git a/services/src/main/java/org/keycloak/protocol/LoginProtocolFactory.java b/services/src/main/java/org/keycloak/protocol/LoginProtocolFactory.java
index f634161..5e5bf0b 100755
--- a/services/src/main/java/org/keycloak/protocol/LoginProtocolFactory.java
+++ b/services/src/main/java/org/keycloak/protocol/LoginProtocolFactory.java
@@ -19,5 +19,12 @@ public interface LoginProtocolFactory extends ProviderFactory<LoginProtocol> {
      * @return
      */
     List<ProtocolMapperModel> getBuiltinMappers();
+
+    /**
+     * List of mappers, which are added to new clients by default
+     * @return
+     */
+    List<ProtocolMapperModel> getDefaultBuiltinMappers();
+
     Object createProtocolEndpoint(RealmModel realm, EventBuilder event, AuthenticationManager authManager);
 }
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolFactory.java b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolFactory.java
index 120446f..c039929 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolFactory.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolFactory.java
@@ -25,6 +25,14 @@ import java.util.Map;
  * @version $Revision: 1 $
  */
 public class OIDCLoginProtocolFactory extends AbstractLoginProtocolFactory {
+
+    public static final String USERNAME = "username";
+    public static final String EMAIL = "email";
+    public static final String EMAIL_VERIFIED = "email verified";
+    public static final String GIVEN_NAME = "given name";
+    public static final String FAMILY_NAME = "family name";
+    public static final String FULL_NAME = "full name";
+
     @Override
     public LoginProtocol create(KeycloakSession session) {
         return new OIDCLoginProtocol().setSession(session);
@@ -35,41 +43,46 @@ public class OIDCLoginProtocolFactory extends AbstractLoginProtocolFactory {
         return builtins;
     }
 
+    @Override
+    public List<ProtocolMapperModel> getDefaultBuiltinMappers() {
+        return defaultBuiltins;
+    }
+
     static List<ProtocolMapperModel> builtins = new ArrayList<>();
     static List<ProtocolMapperModel> defaultBuiltins = new ArrayList<>();
 
     static {
 
         ProtocolMapperModel model;
-        model = UserPropertyMapper.createClaimMapper("username",
+        model = UserPropertyMapper.createClaimMapper(USERNAME,
                 "username",
                 "preferred_username", "String",
-                true, "username",
+                true, USERNAME,
                 true, true);
         builtins.add(model);
         defaultBuiltins.add(model);
-        model = UserPropertyMapper.createClaimMapper("email",
+        model = UserPropertyMapper.createClaimMapper(EMAIL,
                 "email",
                 "email", "String",
-                true, "email",
+                true, EMAIL,
                 true, true);
         builtins.add(model);
         defaultBuiltins.add(model);
-        model = UserPropertyMapper.createClaimMapper("given name",
+        model = UserPropertyMapper.createClaimMapper(GIVEN_NAME,
                 "firstName",
                 "given_name", "String",
-                true, "given name",
+                true, GIVEN_NAME,
                 true, true);
         builtins.add(model);
         defaultBuiltins.add(model);
-        model = UserPropertyMapper.createClaimMapper("family name",
+        model = UserPropertyMapper.createClaimMapper(FAMILY_NAME,
                 "lastName",
                 "family_name", "String",
-                true, "family name",
+                true, FAMILY_NAME,
                 true, true);
         builtins.add(model);
         defaultBuiltins.add(model);
-        model = UserPropertyMapper.createClaimMapper("email verified",
+        model = UserPropertyMapper.createClaimMapper(EMAIL_VERIFIED,
                 "emailVerified",
                 "email_verified", "boolean",
                 false, null,
@@ -77,11 +90,11 @@ public class OIDCLoginProtocolFactory extends AbstractLoginProtocolFactory {
         builtins.add(model);
 
         ProtocolMapperModel fullName = new ProtocolMapperModel();
-        fullName.setName("full name");
+        fullName.setName(FULL_NAME);
         fullName.setProtocolMapper(FullNameMapper.PROVIDER_ID);
         fullName.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
         fullName.setConsentRequired(true);
-        fullName.setConsentText("full name");
+        fullName.setConsentText(FULL_NAME);
         Map<String, String> config = new HashMap<String, String>();
         config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN, "true");
         config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN, "true");
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolService.java b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolService.java
index b4b0de5..6bdae4e 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolService.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolService.java
@@ -133,7 +133,7 @@ public class OIDCLoginProtocolService {
     public Object registerPage() {
         AuthorizationEndpoint endpoint = new AuthorizationEndpoint(authManager, realm, event);
         ResteasyProviderFactory.getInstance().injectProperties(endpoint);
-        return endpoint.register().init();
+        return endpoint.init().register();
     }
 
     /**
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 252a081..96d97e3 100755
--- a/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java
+++ b/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java
@@ -54,6 +54,7 @@ public class ApplianceBootstrap {
         realm.setSsoSessionMaxLifespan(36000);
         realm.setAccessCodeLifespan(60);
         realm.setAccessCodeLifespanUserAction(300);
+        realm.setAccessCodeLifespanLogin(1800);
         realm.setSslRequired(SslRequired.EXTERNAL);
         realm.setRegistrationAllowed(false);
         realm.setRegistrationEmailAsUsername(false);
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 c540baa..383f5e3 100755
--- a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
@@ -21,6 +21,7 @@ import org.keycloak.models.RequiredCredentialModel;
 import org.keycloak.models.RoleModel;
 import org.keycloak.models.UserCredentialModel;
 import org.keycloak.models.UserModel;
+import org.keycloak.models.UserModel.RequiredAction;
 import org.keycloak.models.UserSessionModel;
 import org.keycloak.models.utils.KeycloakModelUtils;
 import org.keycloak.protocol.LoginProtocol;
@@ -32,6 +33,7 @@ import org.keycloak.services.resources.LoginActionsService;
 import org.keycloak.services.resources.RealmsResource;
 import org.keycloak.services.resources.flows.Flows;
 import org.keycloak.services.util.CookieHelper;
+import org.keycloak.services.validation.Validation;
 import org.keycloak.util.Time;
 
 import javax.ws.rs.core.Cookie;
@@ -45,6 +47,7 @@ import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Set;
+import java.util.Iterator;
 
 /**
  * Stateless object that manages authentication
@@ -166,7 +169,7 @@ public class AuthenticationManager {
         String brokerId = userSession.getNote(IdentityBrokerService.BROKER_PROVIDER_ID);
         if (brokerId != null) {
             IdentityProvider identityProvider = IdentityBrokerService.getIdentityProvider(session, realm, brokerId);
-            Response response = identityProvider.logout(userSession, uriInfo, realm);
+            Response response = identityProvider.keycloakInitiatedBrowserLogout(userSession, uriInfo, realm);
             if (response != null) return response;
         }
         return finishBrowserLogout(session, realm, userSession, uriInfo, connection, headers);
@@ -373,17 +376,28 @@ public class AuthenticationManager {
 
         Set<UserModel.RequiredAction> requiredActions = user.getRequiredActions();
         if (!requiredActions.isEmpty()) {
-            UserModel.RequiredAction action = user.getRequiredActions().iterator().next();
-            accessCode.setRequiredAction(action);
-
-            LoginFormsProvider loginFormsProvider = Flows.forms(session, realm, client, uriInfo, request.getHttpHeaders()).setClientSessionCode(accessCode.getCode()).setUser(user);
-            if (action.equals(UserModel.RequiredAction.VERIFY_EMAIL)) {
-                event.clone().event(EventType.SEND_VERIFY_EMAIL).detail(Details.EMAIL, user.getEmail()).success();
-                LoginActionsService.createActionCookie(realm, uriInfo, clientConnection, userSession.getId());
+            Iterator<RequiredAction> i = user.getRequiredActions().iterator();
+            UserModel.RequiredAction action = i.next();
+            
+            if (action.equals(UserModel.RequiredAction.VERIFY_EMAIL) && Validation.isEmpty(user.getEmail())) {
+                if (i.hasNext())
+                    action = i.next();
+                else
+                    action = null;
             }
 
-            return loginFormsProvider
-                    .createResponse(action);
+            if (action != null) {
+                accessCode.setRequiredAction(action);
+
+                LoginFormsProvider loginFormsProvider = Flows.forms(session, realm, client, uriInfo, request.getHttpHeaders()).setClientSessionCode(accessCode.getCode())
+                        .setUser(user);
+                if (action.equals(UserModel.RequiredAction.VERIFY_EMAIL)) {
+                    event.clone().event(EventType.SEND_VERIFY_EMAIL).detail(Details.EMAIL, user.getEmail()).success();
+                    LoginActionsService.createActionCookie(realm, uriInfo, clientConnection, userSession.getId());
+                }
+
+                return loginFormsProvider.createResponse(action);
+            }
         }
 
         if (!isResource) {
diff --git a/services/src/main/java/org/keycloak/services/messages/Messages.java b/services/src/main/java/org/keycloak/services/messages/Messages.java
index a1cc072..0c219da 100755
--- a/services/src/main/java/org/keycloak/services/messages/Messages.java
+++ b/services/src/main/java/org/keycloak/services/messages/Messages.java
@@ -172,5 +172,5 @@ public class Messages {
 
     public static final String INVALID_PARAMETER = "invalidParameterMessage";
 
-    public static final String FEDERATED_IDENTITY_REGISTRATION_EMAIL_MISSING = "federatedIdentityRegistrationEmailMissingMessage";
+    public static final String IDENTITY_PROVIDER_LOGIN_FAILURE = "identityProviderLoginFailure";
 }
diff --git a/services/src/main/java/org/keycloak/services/resources/flows/Urls.java b/services/src/main/java/org/keycloak/services/resources/flows/Urls.java
index ab56f4d..a214f62 100755
--- a/services/src/main/java/org/keycloak/services/resources/flows/Urls.java
+++ b/services/src/main/java/org/keycloak/services/resources/flows/Urls.java
@@ -69,7 +69,7 @@ public class Urls {
 
     public static URI identityProviderAuthnResponse(URI baseUri, String providerId, String realmName) {
         return realmBase(baseUri).path(RealmsResource.class, "getBrokerService")
-                .path(IdentityBrokerService.class, "handleResponseGet")
+                .path(IdentityBrokerService.class, "getEndpoint")
                 .build(realmName, providerId);
     }
 
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 6eb5707..a835b66 100755
--- a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
+++ b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
@@ -22,7 +22,6 @@ import org.jboss.resteasy.spi.HttpRequest;
 import org.jboss.resteasy.spi.ResteasyProviderFactory;
 import org.keycloak.ClientConnection;
 import org.keycloak.broker.provider.AuthenticationRequest;
-import org.keycloak.broker.provider.AuthenticationResponse;
 import org.keycloak.broker.provider.FederatedIdentity;
 import org.keycloak.broker.provider.IdentityBrokerException;
 import org.keycloak.broker.provider.IdentityProvider;
@@ -50,6 +49,7 @@ import org.keycloak.services.managers.EventsManager;
 import org.keycloak.services.messages.Messages;
 import org.keycloak.services.resources.flows.Flows;
 import org.keycloak.services.resources.flows.Urls;
+import org.keycloak.services.validation.Validation;
 import org.keycloak.social.SocialIdentityProvider;
 
 import javax.ws.rs.Consumes;
@@ -77,7 +77,7 @@ import static org.keycloak.models.UserModel.RequiredAction.UPDATE_PROFILE;
  * @author Pedro Igor
  */
 @Path("/broker")
-public class IdentityBrokerService implements IdentityProvider.Callback {
+public class IdentityBrokerService implements IdentityProvider.AuthenticationCallback {
 
     private static final Logger LOGGER = Logger.getLogger(IdentityBrokerService.class);
     public static final String BROKER_PROVIDER_ID = "BROKER_PROVIDER_ID";
@@ -125,9 +125,7 @@ public class IdentityBrokerService implements IdentityProvider.Callback {
         try {
             ClientSessionCode clientSessionCode = parseClientSessionCode(code);
             IdentityProvider identityProvider = getIdentityProvider(session, realmModel, providerId);
-            AuthenticationResponse authenticationResponse = identityProvider.handleRequest(createAuthenticationRequest(providerId, clientSessionCode));
-
-            Response response = authenticationResponse.getResponse();
+            Response response = identityProvider.handleRequest(createAuthenticationRequest(providerId, clientSessionCode));
 
             if (response != null) {
                 this.event.success();
@@ -145,18 +143,6 @@ public class IdentityBrokerService implements IdentityProvider.Callback {
         return redirectToErrorPage(Messages.COULD_NOT_PROCEED_WITH_AUTHENTICATION_REQUEST);
     }
 
-    @GET
-    @Path("{provider_id}")
-    public Response handleResponseGet(@PathParam("provider_id") String providerId) {
-        return handleResponse(providerId);
-    }
-
-    @POST
-    @Path("{provider_id}")
-    public Response handleResponsePost(@PathParam("provider_id") String providerId) {
-        return handleResponse(providerId);
-    }
-
     @Path("{provider_id}/endpoint")
     public Object getEndpoint(@PathParam("provider_id") String providerId) {
         IdentityProvider identityProvider = getIdentityProvider(session, realmModel, providerId);
@@ -319,117 +305,6 @@ public class IdentityBrokerService implements IdentityProvider.Callback {
                 this.uriInfo, event);
     }
 
-    private Response handleResponse(String providerId) {
-        if (isDebugEnabled()) {
-            LOGGER.debugf("Handling authentication response from identity provider [%s].", providerId);
-        }
-        this.event.event(EventType.IDENTITY_PROVIDER_RESPONSE);
-        this.event.detail(Details.IDENTITY_PROVIDER, providerId);
-        IdentityProviderModel identityProviderConfig = getIdentityProviderConfig(providerId);
-
-        try {
-            IdentityProvider identityProvider = getIdentityProvider(session, realmModel, providerId);
-            String relayState = identityProvider.getRelayState(createAuthenticationRequest(providerId, null));
-
-            if (relayState == null) {
-                return redirectToErrorPage(Messages.NO_RELAY_STATE_IN_RESPONSE, providerId);
-            }
-
-            if (isDebugEnabled()) {
-                LOGGER.debugf("Relay state is valid: [%s].", relayState);
-            }
-
-            ClientSessionCode clientSessionCode = parseClientSessionCode(relayState);
-            AuthenticationResponse authenticationResponse = identityProvider.handleResponse(createAuthenticationRequest(providerId, clientSessionCode));
-            Response response = authenticationResponse.getResponse();
-
-            if (response != null) {
-                if (isDebugEnabled()) {
-                    LOGGER.debugf("Identity provider [%s] is going to send a response [%s].", identityProvider, response);
-                }
-                return response;
-            }
-
-            FederatedIdentity identity = authenticationResponse.getUser();
-
-            if (isDebugEnabled()) {
-                LOGGER.debugf("Identity provider [%s] returned with identity [%s].", providerId, identity);
-            }
-
-            if (!identityProviderConfig.isStoreToken()) {
-                if (isDebugEnabled()) {
-                    LOGGER.debugf("Token will not be stored for identity provider [%s].", providerId);
-                }
-                identity.setToken(null);
-            }
-
-            identity.setIdentityProviderId(providerId);
-
-            return performLocalAuthentication(identity, clientSessionCode);
-        } catch (IdentityBrokerException e) {
-            rollback();
-            return redirectToErrorPage(Messages.IDENTITY_PROVIDER_AUTHENTICATION_FAILED, e, providerId);
-        } catch (Exception e) {
-            rollback();
-            return redirectToErrorPage(Messages.UNEXPECTED_ERROR_HANDLING_RESPONSE, e, providerId);
-        } finally {
-            if (this.session.getTransaction().isActive()) {
-                this.session.getTransaction().commit();
-            }
-        }
-    }
-
-    private Response performLocalAuthentication(FederatedIdentity updatedIdentity, ClientSessionCode clientCode) {
-        ClientSessionModel clientSession = clientCode.getClientSession();
-        IdentityProviderModel identityProviderConfig = getIdentityProviderConfig(updatedIdentity.getIdentityProviderId());
-        String providerId = identityProviderConfig.getAlias();
-        FederatedIdentityModel federatedIdentityModel = new FederatedIdentityModel(providerId, updatedIdentity.getId(),
-                updatedIdentity.getUsername(), updatedIdentity.getToken());
-
-        this.event.event(EventType.IDENTITY_PROVIDER_LOGIN)
-                .detail(Details.REDIRECT_URI, clientSession.getRedirectUri())
-                .detail(Details.IDENTITY_PROVIDER_IDENTITY, updatedIdentity.getUsername());
-
-        UserModel federatedUser = this.session.users().getUserByFederatedIdentity(federatedIdentityModel, this.realmModel);
-
-        // Check if federatedUser is already authenticated (this means linking social into existing federatedUser account)
-        if (clientSession.getUserSession() != null) {
-            return performAccountLinking(clientSession, providerId, federatedIdentityModel, federatedUser);
-        }
-
-        if (federatedUser == null) {
-            try {
-                federatedUser = createUser(updatedIdentity);
-
-                if (identityProviderConfig.isUpdateProfileFirstLogin()) {
-                    if (isDebugEnabled()) {
-                        LOGGER.debugf("Identity provider requires update profile action.", federatedUser);
-                    }
-                    federatedUser.addRequiredAction(UPDATE_PROFILE);
-                }
-            } catch (Exception e) {
-                return redirectToLoginPage(e, clientCode);
-            }
-        }
-
-        updateFederatedIdentity(updatedIdentity, federatedUser);
-
-        UserSessionModel userSession = this.session.sessions()
-                .createUserSession(this.realmModel, federatedUser, federatedUser.getUsername(), this.clientConnection.getRemoteAddr(), "broker", false);
-
-        this.event.user(federatedUser);
-        this.event.session(userSession);
-
-        TokenManager.attachClientSession(userSession, clientSession);
-
-        if (isDebugEnabled()) {
-            LOGGER.debugf("Performing local authentication for user [%s].", federatedUser);
-        }
-
-        return AuthenticationManager.nextActionAfterAuthentication(this.session, userSession, clientSession, this.clientConnection, this.request,
-                this.uriInfo, event);
-    }
-
     private Response performAccountLinking(ClientSessionModel clientSession, String providerId, FederatedIdentityModel federatedIdentityModel, UserModel federatedUser) {
         this.event.event(EventType.IDENTITY_PROVIDER_ACCCOUNT_LINKING);
 
@@ -607,15 +482,10 @@ public class IdentityBrokerService implements IdentityProvider.Callback {
         }
 
         String username = updatedIdentity.getUsername();
-        if (this.realmModel.isRegistrationEmailAsUsername()) {
+        if (this.realmModel.isRegistrationEmailAsUsername() && !Validation.isEmpty(updatedIdentity.getEmail())) {
             username = updatedIdentity.getEmail();
-            if (username == null || username.trim().length() == 0) {
-                fireErrorEvent(Errors.FEDERATED_IDENTITY_REGISTRATION_EMAIL_MISSING);
-                throw new IdentityBrokerException(Messages.FEDERATED_IDENTITY_REGISTRATION_EMAIL_MISSING);
-                // TODO KEYCLOAK-1053 (ask user to enter email address) should be implemented instead of plain exception as better solution for this case
-            }
-            username = username.trim();
-        } else if (username != null) {
+        } 
+        if (username != null) {
             username = username.trim();
         }
 
diff --git a/services/src/main/java/org/keycloak/services/util/MigrationUtils.java b/services/src/main/java/org/keycloak/services/util/MigrationUtils.java
new file mode 100644
index 0000000..f2a1676
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/util/MigrationUtils.java
@@ -0,0 +1,70 @@
+package org.keycloak.services.util;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.keycloak.models.ClaimMask;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.ProtocolMapperModel;
+import org.keycloak.protocol.LoginProtocol;
+import org.keycloak.protocol.LoginProtocolFactory;
+import org.keycloak.protocol.oidc.OIDCLoginProtocolFactory;
+import org.keycloak.provider.ProviderFactory;
+
+/**
+ * Various common utils needed for migration from older version to newer
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class MigrationUtils {
+
+    private MigrationUtils() {}
+
+    /**
+     *
+     * @param session
+     * @param claimMask mask used on ClientModel in 1.1.0
+     * @return set of 1.2.0.Beta1 protocol mappers corresponding to given claimMask
+     */
+    public static Collection<ProtocolMapperModel> getMappersForClaimMask(KeycloakSession session, Long claimMask) {
+        Map<String, ProtocolMapperModel> allMappers = getAllDefaultMappers(session);
+
+        if (claimMask == null) {
+            return allMappers.values();
+        }
+
+        if (!ClaimMask.hasUsername(claimMask)) {
+            allMappers.remove(OIDCLoginProtocolFactory.USERNAME);
+        }
+        if (!ClaimMask.hasEmail(claimMask)) {
+            allMappers.remove(OIDCLoginProtocolFactory.EMAIL);
+        }
+        if (!ClaimMask.hasName(claimMask)) {
+            allMappers.remove(OIDCLoginProtocolFactory.FAMILY_NAME);
+            allMappers.remove(OIDCLoginProtocolFactory.FULL_NAME);
+            allMappers.remove(OIDCLoginProtocolFactory.GIVEN_NAME);
+        }
+
+        return allMappers.values();
+    }
+
+    private static Map<String, ProtocolMapperModel> getAllDefaultMappers(KeycloakSession session) {
+        Map<String, ProtocolMapperModel> allMappers = new HashMap<String, ProtocolMapperModel>();
+
+        List<ProviderFactory> loginProtocolFactories = session.getKeycloakSessionFactory().getProviderFactories(LoginProtocol.class);
+
+        for (ProviderFactory factory : loginProtocolFactories) {
+            LoginProtocolFactory loginProtocolFactory = (LoginProtocolFactory) factory;
+            List<ProtocolMapperModel> currentMappers = loginProtocolFactory.getDefaultBuiltinMappers();
+
+            for (ProtocolMapperModel protocolMapper : currentMappers) {
+                allMappers.put(protocolMapper.getName(), protocolMapper);
+            }
+        }
+
+        return allMappers;
+    }
+}
diff --git a/social/twitter/pom.xml b/social/twitter/pom.xml
index 15ff779..0043f0b 100755
--- a/social/twitter/pom.xml
+++ b/social/twitter/pom.xml
@@ -27,6 +27,18 @@
             <scope>provided</scope>
         </dependency>
         <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-events-api</artifactId>
+            <version>${project.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-services</artifactId>
+            <version>${project.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
             <groupId>org.codehaus.jackson</groupId>
             <artifactId>jackson-mapper-asl</artifactId>
             <scope>provided</scope>
diff --git a/social/twitter/src/main/java/org/keycloak/social/twitter/TwitterIdentityProvider.java b/social/twitter/src/main/java/org/keycloak/social/twitter/TwitterIdentityProvider.java
index c7d3492..6ca63bf 100755
--- a/social/twitter/src/main/java/org/keycloak/social/twitter/TwitterIdentityProvider.java
+++ b/social/twitter/src/main/java/org/keycloak/social/twitter/TwitterIdentityProvider.java
@@ -21,25 +21,41 @@
  */
 package org.keycloak.social.twitter;
 
+import org.jboss.logging.Logger;
+import org.keycloak.ClientConnection;
 import org.keycloak.broker.oidc.OAuth2IdentityProviderConfig;
 import org.keycloak.broker.provider.AbstractIdentityProvider;
 import org.keycloak.broker.provider.AuthenticationRequest;
-import org.keycloak.broker.provider.AuthenticationResponse;
 import org.keycloak.broker.provider.FederatedIdentity;
 import org.keycloak.broker.provider.IdentityBrokerException;
+import org.keycloak.events.EventBuilder;
+import org.keycloak.events.EventType;
+import org.keycloak.models.ClientModel;
 import org.keycloak.models.ClientSessionModel;
 import org.keycloak.models.FederatedIdentityModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.services.managers.ClientSessionCode;
+import org.keycloak.services.managers.EventsManager;
+import org.keycloak.services.messages.Messages;
+import org.keycloak.services.resources.flows.Flows;
 import org.keycloak.social.SocialIdentityProvider;
 import twitter4j.Twitter;
 import twitter4j.TwitterFactory;
 import twitter4j.auth.AccessToken;
 import twitter4j.auth.RequestToken;
 
+import javax.ws.rs.GET;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
 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.net.URI;
+import java.util.HashMap;
+
+import static org.keycloak.models.ClientSessionModel.Action.AUTHENTICATE;
 
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -47,12 +63,18 @@ import java.net.URI;
 public class TwitterIdentityProvider extends AbstractIdentityProvider<OAuth2IdentityProviderConfig> implements
         SocialIdentityProvider<OAuth2IdentityProviderConfig> {
 
+    protected static final Logger logger = Logger.getLogger(TwitterIdentityProvider.class);
     public TwitterIdentityProvider(OAuth2IdentityProviderConfig config) {
         super(config);
     }
 
     @Override
-    public AuthenticationResponse handleRequest(AuthenticationRequest request) {
+    public Object callback(RealmModel realm, AuthenticationCallback callback) {
+        return new Endpoint(realm, callback);
+    }
+
+    @Override
+    public Response handleRequest(AuthenticationRequest request) {
         try {
             Twitter twitter = new TwitterFactory().getInstance();
             twitter.setOAuthConsumer(getConfig().getClientId(), getConfig().getClientSecret());
@@ -67,63 +89,103 @@ public class TwitterIdentityProvider extends AbstractIdentityProvider<OAuth2Iden
 
             URI authenticationUrl = URI.create(requestToken.getAuthenticationURL());
 
-            return AuthenticationResponse.temporaryRedirect(authenticationUrl);
+            return Response.temporaryRedirect(authenticationUrl).build();
         } catch (Exception e) {
             throw new IdentityBrokerException("Could send authentication request to twitter.", e);
         }
     }
 
-    @Override
-    public String getRelayState(AuthenticationRequest request) {
-        UriInfo uriInfo = request.getUriInfo();
-        return uriInfo.getQueryParameters().getFirst("state");
-    }
+    protected class Endpoint {
+        protected RealmModel realm;
+        protected AuthenticationCallback callback;
 
-    @Override
-    public AuthenticationResponse handleResponse(AuthenticationRequest request) {
-        MultivaluedMap<String, String> queryParameters = request.getUriInfo().getQueryParameters();
+        @Context
+        protected KeycloakSession session;
 
-        if (queryParameters.getFirst("denied") != null) {
-            throw new IdentityBrokerException("Access denied.");
+        @Context
+        protected ClientConnection clientConnection;
+
+        @Context
+        protected HttpHeaders headers;
+
+        @Context
+        protected UriInfo uriInfo;
+
+        public Endpoint(RealmModel realm, AuthenticationCallback callback) {
+            this.realm = realm;
+            this.callback = callback;
         }
 
-        try {
-            Twitter twitter = new TwitterFactory().getInstance();
+        @GET
+        public Response authResponse(@QueryParam("state") String state,
+                                     @QueryParam("denied") String denied,
+                                     @QueryParam("oauth_verifier") String verifier) {
 
-            twitter.setOAuthConsumer(getConfig().getClientId(), getConfig().getClientSecret());
+            try {
+                Twitter twitter = new TwitterFactory().getInstance();
 
-            String verifier = queryParameters.getFirst("oauth_verifier");
+                twitter.setOAuthConsumer(getConfig().getClientId(), getConfig().getClientSecret());
 
-            ClientSessionModel clientSession = request.getClientSession();
+                ClientSessionModel clientSession = parseClientSessionCode(state).getClientSession();
 
-            String twitterToken = clientSession.getNote("twitter_token");
-            String twitterSecret = clientSession.getNote("twitter_tokenSecret");
+                String twitterToken = clientSession.getNote("twitter_token");
+                String twitterSecret = clientSession.getNote("twitter_tokenSecret");
 
-            RequestToken requestToken = new RequestToken(twitterToken, twitterSecret);
+                RequestToken requestToken = new RequestToken(twitterToken, twitterSecret);
 
-            AccessToken oAuthAccessToken = twitter.getOAuthAccessToken(requestToken, verifier);
-            twitter4j.User twitterUser = twitter.verifyCredentials();
+                AccessToken oAuthAccessToken = twitter.getOAuthAccessToken(requestToken, verifier);
+                twitter4j.User twitterUser = twitter.verifyCredentials();
 
-            FederatedIdentity identity = new FederatedIdentity(Long.toString(twitterUser.getId()));
+                FederatedIdentity identity = new FederatedIdentity(Long.toString(twitterUser.getId()));
 
-            identity.setUsername(twitterUser.getScreenName());
-            identity.setName(twitterUser.getName());
+                identity.setUsername(twitterUser.getScreenName());
+                identity.setName(twitterUser.getName());
 
-            StringBuilder tokenBuilder = new StringBuilder();
+                StringBuilder tokenBuilder = new StringBuilder();
 
-            tokenBuilder.append("{");
-            tokenBuilder.append("\"oauth_token\":").append("\"").append(oAuthAccessToken.getToken()).append("\"").append(",");
-            tokenBuilder.append("\"oauth_token_secret\":").append("\"").append(oAuthAccessToken.getTokenSecret()).append("\"").append(",");
-            tokenBuilder.append("\"screen_name\":").append("\"").append(oAuthAccessToken.getScreenName()).append("\"").append(",");
-            tokenBuilder.append("\"user_id\":").append("\"").append(oAuthAccessToken.getUserId()).append("\"");
-            tokenBuilder.append("}");
+                tokenBuilder.append("{");
+                tokenBuilder.append("\"oauth_token\":").append("\"").append(oAuthAccessToken.getToken()).append("\"").append(",");
+                tokenBuilder.append("\"oauth_token_secret\":").append("\"").append(oAuthAccessToken.getTokenSecret()).append("\"").append(",");
+                tokenBuilder.append("\"screen_name\":").append("\"").append(oAuthAccessToken.getScreenName()).append("\"").append(",");
+                tokenBuilder.append("\"user_id\":").append("\"").append(oAuthAccessToken.getUserId()).append("\"");
+                tokenBuilder.append("}");
 
-            identity.setToken(tokenBuilder.toString());
+                identity.setToken(tokenBuilder.toString());
 
-            return AuthenticationResponse.end(identity);
-        } catch (Exception e) {
-            throw new IdentityBrokerException("Could get user profile from twitter.", e);
+                return callback.authenticated(new HashMap<String, String>(), getConfig(), identity, state);
+            } catch (Exception e) {
+                logger.error("Could get user profile from twitter.", e);
+            }
+            EventBuilder event = new EventsManager(realm, session, clientConnection).createEventBuilder();
+            event.event(EventType.LOGIN);
+            event.error("twitter_login_failed");
+            return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.UNEXPECTED_ERROR_HANDLING_RESPONSE);
+        }
+
+        private ClientSessionCode parseClientSessionCode(String code) {
+            ClientSessionCode clientCode = ClientSessionCode.parse(code, this.session, this.realm);
+
+            if (clientCode != null && clientCode.isValid(AUTHENTICATE)) {
+                ClientSessionModel clientSession = clientCode.getClientSession();
+
+                if (clientSession != null) {
+                    ClientModel client = clientSession.getClient();
+
+                    if (client == null) {
+                        throw new IdentityBrokerException("Invalid client");
+                    }
+
+                    logger.debugf("Got authorization code from client [%s].", client.getClientId());
+                }
+
+                logger.debugf("Authorization code is valid.");
+
+                return clientCode;
+            }
+
+            throw new IdentityBrokerException("Invalid code, please login again through your application.");
         }
+
     }
 
     @Override
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 4743826..fb78299 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
@@ -157,7 +157,7 @@ public class AccountTest {
         });
     }
 
-    //@Test @Ignore
+    @Test @Ignore
     public void runit() throws Exception {
         Thread.sleep(10000000);
     }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ApplicationTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ApplicationTest.java
index 2135e09..3c07797 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ApplicationTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ApplicationTest.java
@@ -6,6 +6,8 @@ import org.keycloak.admin.client.resource.ApplicationResource;
 import org.keycloak.models.ApplicationModel;
 import org.keycloak.models.RealmModel;
 import org.keycloak.representations.idm.ApplicationRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.RoleRepresentation;
 import org.keycloak.representations.idm.UserSessionRepresentation;
 import org.keycloak.services.managers.RealmManager;
 import org.keycloak.testsuite.OAuthClient;
@@ -14,11 +16,16 @@ import org.keycloak.testsuite.rule.WebResource;
 import org.keycloak.testsuite.rule.WebRule;
 import org.openqa.selenium.WebDriver;
 
+import javax.ws.rs.NotFoundException;
+import java.util.LinkedList;
 import java.util.List;
 
+import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -84,4 +91,26 @@ public class ApplicationTest extends AbstractClientTest {
         assertEquals(1, userSessions.get(0).getApplications().size());
     }
 
+    @Test
+    // KEYCLOAK-1110
+    public void deleteDefaultRole() {
+        ApplicationRepresentation rep = new ApplicationRepresentation();
+        rep.setName("my-app");
+        rep.setEnabled(true);
+        realm.applications().create(rep);
+
+        RoleRepresentation role = new RoleRepresentation("test", "test");
+        realm.applications().get("my-app").roles().create(role);
+
+        rep = realm.applications().get("my-app").toRepresentation();
+        rep.setDefaultRoles(new String[] { "test" });
+        realm.applications().get("my-app").update(rep);
+
+        assertArrayEquals(new String[] { "test" }, realm.applications().get("my-app").toRepresentation().getDefaultRoles());
+
+        realm.applications().get("my-app").roles().deleteRole("test");
+
+        assertNull(realm.applications().get("my-app").toRepresentation().getDefaultRoles());
+    }
+
 }
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 564cb85..1b02d0b 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
@@ -4,14 +4,18 @@ import org.junit.Test;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.RoleRepresentation;
 import org.keycloak.services.managers.RealmManager;
 
+import javax.ws.rs.NotFoundException;
+import java.util.LinkedList;
 import java.util.List;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -101,4 +105,27 @@ public class RealmTest extends AbstractClientTest {
         assertNotNull(rep.getCertificate());
     }
 
+    @Test
+    // KEYCLOAK-1110
+    public void deleteDefaultRole() {
+        RoleRepresentation role = new RoleRepresentation("test", "test");
+        realm.roles().create(role);
+
+        assertNotNull(realm.roles().get("test").toRepresentation());
+
+        RealmRepresentation rep = realm.toRepresentation();
+        rep.setDefaultRoles(new LinkedList<String>());
+        rep.getDefaultRoles().add("test");
+
+        realm.update(rep);
+
+        realm.roles().deleteRole("test");
+
+        try {
+            realm.roles().get("testsadfsadf").toRepresentation();
+            fail("Expected NotFoundException");
+        } catch (NotFoundException e) {
+        }
+    }
+
 }
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 7ea8348..2630878 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
@@ -32,6 +32,7 @@ import org.keycloak.models.IdentityProviderModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserModel;
+import org.keycloak.models.UserModel.RequiredAction;
 import org.keycloak.representations.IDToken;
 import org.keycloak.services.resources.flows.Urls;
 import org.keycloak.testsuite.OAuthClient;
@@ -70,7 +71,6 @@ import static com.thoughtworks.selenium.SeleneseTestBase.fail;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
 /**
@@ -127,7 +127,7 @@ public abstract class AbstractIdentityProviderTest {
     public void testSuccessfulAuthentication() {
         IdentityProviderModel identityProviderModel = getIdentityProviderModel();
 
-        assertSuccessfulAuthentication(identityProviderModel, "test-user");
+        assertSuccessfulAuthentication(identityProviderModel, "test-user", "new@email.com");
     }
 
     @Test
@@ -135,7 +135,29 @@ public abstract class AbstractIdentityProviderTest {
         IdentityProviderModel identityProviderModel = getIdentityProviderModel();
         identityProviderModel.setUpdateProfileFirstLogin(false);
 
-        assertSuccessfulAuthentication(identityProviderModel, "test-user");
+        assertSuccessfulAuthentication(identityProviderModel, "test-user", "test-user@localhost");
+    }
+
+    /**
+     * Test for KEYCLOAK-1053 - verify email action is not performed if email is not provided, login is normal, but action stays in set to be performed later
+     */
+    @Test
+    public void testSuccessfulAuthenticationWithoutUpdateProfile_emailNotProvided_emailVerifyEnabled() {
+        getRealm().setVerifyEmail(true);
+        brokerServerRule.stopSession(this.session, true);
+        this.session = brokerServerRule.startSession();
+
+        try {
+            IdentityProviderModel identityProviderModel = getIdentityProviderModel();
+            identityProviderModel.setUpdateProfileFirstLogin(false);
+
+            UserModel federatedUser = assertSuccessfulAuthentication(identityProviderModel, "test-user-noemail", null);
+
+            federatedUser.getRequiredActions().contains(RequiredAction.VERIFY_EMAIL);
+
+        } finally {
+            getRealm().setVerifyEmail(false);
+        }
     }
 
     @Test
@@ -163,7 +185,7 @@ public abstract class AbstractIdentityProviderTest {
 
             assertEquals("test-user@localhost", federatedUser.getUsername());
 
-            doAssertFederatedUser(federatedUser, identityProviderModel);
+            doAssertFederatedUser(federatedUser, identityProviderModel, "test-user@localhost");
 
             Set<FederatedIdentityModel> federatedIdentities = this.session.users().getFederatedIdentities(federatedUser, realm);
 
@@ -196,18 +218,38 @@ public abstract class AbstractIdentityProviderTest {
 
             authenticateWithIdentityProvider(identityProviderModel, "test-user-noemail");
 
+            // check correct user is created with username from provider as email is not available
             RealmModel realm = getRealm();
-            UserModel federatedUser = session.users().getUserByUsername("test-user-noemail", realm);
-            assertNull(federatedUser);
+            UserModel federatedUser = getFederatedUser();
+            assertNotNull(federatedUser);
 
-            // assert page is shown with correct error message
-            assertEquals("Email is not provided. Use another provider to create account please.", this.driver.findElement(By.className("kc-feedback-text")).getText());
+            doAssertFederatedUserNoEmail(federatedUser);
+
+            Set<FederatedIdentityModel> federatedIdentities = this.session.users().getFederatedIdentities(federatedUser, realm);
+
+            assertEquals(1, federatedIdentities.size());
+
+            FederatedIdentityModel federatedIdentityModel = federatedIdentities.iterator().next();
+
+            assertEquals(getProviderId(), federatedIdentityModel.getIdentityProvider());
+
+            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"));
 
         } finally {
             getRealm().setRegistrationEmailAsUsername(false);
         }
     }
 
+    protected void doAssertFederatedUserNoEmail(UserModel federatedUser) {
+        assertEquals("test-user-noemail", federatedUser.getUsername());
+        assertEquals(null, federatedUser.getEmail());
+        assertEquals("Test", federatedUser.getFirstName());
+        assertEquals("User", federatedUser.getLastName());
+    }
+
     @Test
     public void testDisabled() {
         IdentityProviderModel identityProviderModel = getIdentityProviderModel();
@@ -508,7 +550,7 @@ public abstract class AbstractIdentityProviderTest {
 
     protected abstract void doAssertTokenRetrieval(String pageSource);
 
-    private void assertSuccessfulAuthentication(IdentityProviderModel identityProviderModel, String username) {
+    private UserModel assertSuccessfulAuthentication(IdentityProviderModel identityProviderModel, String username, String expectedEmail) {
         authenticateWithIdentityProvider(identityProviderModel, username);
 
         // authenticated and redirected to app
@@ -518,7 +560,7 @@ public abstract class AbstractIdentityProviderTest {
 
         assertNotNull(federatedUser);
 
-        doAssertFederatedUser(federatedUser, identityProviderModel);
+        doAssertFederatedUser(federatedUser, identityProviderModel, expectedEmail);
 
         RealmModel realm = getRealm();
 
@@ -535,6 +577,7 @@ public abstract class AbstractIdentityProviderTest {
         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;
     }
 
     private void authenticateWithIdentityProvider(IdentityProviderModel identityProviderModel, String username) {
@@ -593,17 +636,16 @@ public abstract class AbstractIdentityProviderTest {
         return this.session.realms().getRealm("realm-with-broker");
     }
 
-    protected void doAssertFederatedUser(UserModel federatedUser, IdentityProviderModel identityProviderModel) {
+    protected void doAssertFederatedUser(UserModel federatedUser, IdentityProviderModel identityProviderModel, String expectedEmail) {
         if (identityProviderModel.isUpdateProfileFirstLogin()) {
-            String userEmail = "new@email.com";
             String userFirstName = "New first";
             String userLastName = "New last";
 
-            assertEquals(userEmail, federatedUser.getEmail());
+            assertEquals(expectedEmail, federatedUser.getEmail());
             assertEquals(userFirstName, federatedUser.getFirstName());
             assertEquals(userLastName, federatedUser.getLastName());
         } else {
-            assertEquals("test-user@localhost", federatedUser.getEmail());
+            assertEquals(expectedEmail, federatedUser.getEmail());
             assertEquals("Test", federatedUser.getFirstName());
             assertEquals("User", federatedUser.getLastName());
         }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/provider/CustomIdentityProvider.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/provider/CustomIdentityProvider.java
old mode 100644
new mode 100755
index 0c0e369..f785926
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/provider/CustomIdentityProvider.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/provider/CustomIdentityProvider.java
@@ -19,7 +19,6 @@ package org.keycloak.testsuite.broker.provider;
 
 import org.keycloak.broker.provider.AbstractIdentityProvider;
 import org.keycloak.broker.provider.AuthenticationRequest;
-import org.keycloak.broker.provider.AuthenticationResponse;
 import org.keycloak.models.FederatedIdentityModel;
 import org.keycloak.models.IdentityProviderModel;
 
@@ -35,17 +34,7 @@ public class CustomIdentityProvider extends AbstractIdentityProvider<IdentityPro
     }
 
     @Override
-    public AuthenticationResponse handleRequest(AuthenticationRequest request) {
-        return null;
-    }
-
-    @Override
-    public String getRelayState(AuthenticationRequest request) {
-        return null;
-    }
-
-    @Override
-    public AuthenticationResponse handleResponse(AuthenticationRequest request) {
+    public Response handleRequest(AuthenticationRequest request) {
         return null;
     }
 
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/provider/social/CustomSocialProvider.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/provider/social/CustomSocialProvider.java
old mode 100644
new mode 100755
index e3a2bd2..4127668
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/provider/social/CustomSocialProvider.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/provider/social/CustomSocialProvider.java
@@ -19,7 +19,6 @@ package org.keycloak.testsuite.broker.provider.social;
 
 import org.keycloak.broker.provider.AbstractIdentityProvider;
 import org.keycloak.broker.provider.AuthenticationRequest;
-import org.keycloak.broker.provider.AuthenticationResponse;
 import org.keycloak.models.FederatedIdentityModel;
 import org.keycloak.models.IdentityProviderModel;
 import org.keycloak.social.SocialIdentityProvider;
@@ -36,17 +35,7 @@ public class CustomSocialProvider extends AbstractIdentityProvider<IdentityProvi
     }
 
     @Override
-    public AuthenticationResponse handleRequest(AuthenticationRequest request) {
-        return null;
-    }
-
-    @Override
-    public String getRelayState(AuthenticationRequest request) {
-        return null;
-    }
-
-    @Override
-    public AuthenticationResponse handleResponse(AuthenticationRequest request) {
+    public Response handleRequest(AuthenticationRequest request) {
         return null;
     }
 
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 c77e57f..2c57f04 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
@@ -46,17 +46,27 @@ public class SAMLKeyCloakServerBrokerBasicTest extends AbstractIdentityProviderT
     }
 
     @Override
-    protected void doAssertFederatedUser(UserModel federatedUser, IdentityProviderModel identityProviderModel) {
+    protected void doAssertFederatedUser(UserModel federatedUser, IdentityProviderModel identityProviderModel, String expectedEmail) {
         if (identityProviderModel.isUpdateProfileFirstLogin()) {
-            super.doAssertFederatedUser(federatedUser, identityProviderModel);
+            super.doAssertFederatedUser(federatedUser, identityProviderModel, expectedEmail);
         } else {
-            assertEquals("test-user@localhost", federatedUser.getEmail());
+            if (expectedEmail == null)
+                expectedEmail = "";
+            assertEquals(expectedEmail, federatedUser.getEmail());
             assertNull(federatedUser.getFirstName());
             assertNull(federatedUser.getLastName());
         }
     }
 
     @Override
+    protected void doAssertFederatedUserNoEmail(UserModel federatedUser) {
+        assertEquals("", federatedUser.getUsername());
+        assertEquals("", federatedUser.getEmail());
+        assertEquals(null, federatedUser.getFirstName());
+        assertEquals(null, federatedUser.getLastName());
+    }
+
+    @Override
     protected void doAssertTokenRetrieval(String pageSource) {
         try {
             SAML2Request saml2Request = new SAML2Request();
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 1d8b264..124d7f0 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
@@ -45,17 +45,27 @@ public class SAMLKeyCloakServerBrokerWithSignatureTest extends AbstractIdentityP
     }
 
     @Override
-    protected void doAssertFederatedUser(UserModel federatedUser, IdentityProviderModel identityProviderModel) {
+    protected void doAssertFederatedUser(UserModel federatedUser, IdentityProviderModel identityProviderModel, String expectedEmail) {
         if (identityProviderModel.isUpdateProfileFirstLogin()) {
-            super.doAssertFederatedUser(federatedUser, identityProviderModel);
+            super.doAssertFederatedUser(federatedUser, identityProviderModel, expectedEmail);
         } else {
-            assertEquals("test-user@localhost", federatedUser.getEmail());
+            if (expectedEmail == null)
+                expectedEmail = "";
+            assertEquals(expectedEmail, federatedUser.getEmail());
             assertNull(federatedUser.getFirstName());
             assertNull(federatedUser.getLastName());
         }
     }
 
     @Override
+    protected void doAssertFederatedUserNoEmail(UserModel federatedUser) {
+        assertEquals("", federatedUser.getUsername());
+        assertEquals("", federatedUser.getEmail());
+        assertEquals(null, federatedUser.getFirstName());
+        assertEquals(null, federatedUser.getLastName());
+    }
+
+    @Override
     protected void doAssertTokenRetrieval(String pageSource) {
         try {
             SAML2Request saml2Request = new SAML2Request();
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 b427a16..9a4fb5f 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
@@ -9,7 +9,9 @@ import org.keycloak.models.utils.KeycloakModelUtils;
 import org.keycloak.models.utils.ModelToRepresentation;
 import org.keycloak.representations.idm.RealmRepresentation;
 
+import java.util.Arrays;
 import java.util.HashMap;
+import java.util.HashSet;
 
 public class ModelTest extends AbstractModelTest {
 
@@ -33,11 +35,14 @@ public class ModelTest extends AbstractModelTest {
         smtp.put("hostname", "localhost");
         realm.setSmtpConfig(smtp);
 
-        HashMap<String, String> social = new HashMap<String,String>();
-        social.put("google.key", "1234");
-        social.put("google.secret", "5678");
-        //FIXME: KEYCLOAK-883
-//        realm.setSocialConfig(social);
+        realm.setDefaultLocale("en");
+        realm.setAccessCodeLifespanLogin(100);
+        realm.setInternationalizationEnabled(true);
+        realm.setRegistrationEmailAsUsername(true);
+        realm.setSupportedLocales(new HashSet<String>(Arrays.asList("en", "cz")));
+        realm.setEventsListeners(new HashSet<String>(Arrays.asList("jpa", "mongo", "foo")));
+        realm.setEventsExpiration(200);
+        realm.setEventsEnabled(true);
 
         RealmModel persisted = realmManager.getRealm(realm.getId());
         assertEquals(realm, persisted);
@@ -62,8 +67,15 @@ public class ModelTest extends AbstractModelTest {
         Assert.assertEquals(expected.getDefaultRoles(), actual.getDefaultRoles());
 
         Assert.assertEquals(expected.getSmtpConfig(), actual.getSmtpConfig());
-        //FIXME: KEYCLOAK-883
-//        Assert.assertEquals(expected.getSocialConfig(), actual.getSocialConfig());
+
+        Assert.assertEquals(expected.getDefaultLocale(), actual.getDefaultLocale());
+        Assert.assertEquals(expected.getAccessCodeLifespanLogin(), actual.getAccessCodeLifespanLogin());
+        Assert.assertEquals(expected.isInternationalizationEnabled(), actual.isInternationalizationEnabled());
+        Assert.assertEquals(expected.isRegistrationEmailAsUsername(), actual.isRegistrationEmailAsUsername());
+        Assert.assertEquals(expected.getSupportedLocales(), actual.getSupportedLocales());
+        Assert.assertEquals(expected.getEventsListeners(), actual.getEventsListeners());
+        Assert.assertEquals(expected.getEventsExpiration(), actual.getEventsExpiration());
+        Assert.assertEquals(expected.isEventsEnabled(), actual.isEventsEnabled());
     }
 
     private RealmModel importExport(RealmModel src, String copyName) {
diff --git a/testsuite/integration/src/test/resources/broker-test/test-broker-realm-with-kc-oidc.json b/testsuite/integration/src/test/resources/broker-test/test-broker-realm-with-kc-oidc.json
index 1fd510f..01a1c2c 100755
--- a/testsuite/integration/src/test/resources/broker-test/test-broker-realm-with-kc-oidc.json
+++ b/testsuite/integration/src/test/resources/broker-test/test-broker-realm-with-kc-oidc.json
@@ -12,7 +12,7 @@
         "enabled": true,
         "secret": "secret",
         "redirectUris": [
-          "http://localhost:8081/auth/realms/realm-with-broker/broker/kc-oidc-idp"
+          "http://localhost:8081/auth/realms/realm-with-broker/broker/kc-oidc-idp/endpoint"
         ],
         "claims": {
           "name" : true,