keycloak-uncached

Changes

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

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

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

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 bc007ae..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
@@ -19,6 +19,7 @@ package org.keycloak.broker.provider;
 
 import org.keycloak.models.IdentityProviderModel;
 import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserSessionModel;
 
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
@@ -48,4 +49,13 @@ public abstract class AbstractIdentityProvider<C extends IdentityProviderModel> 
         // no-op
     }
 
+    @Override
+    public Object callback(RealmModel realm, AuthenticationCallback callback) {
+        return null;
+    }
+
+    @Override
+    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 f754eeb..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
@@ -20,16 +20,39 @@ package org.keycloak.broker.provider;
 import org.keycloak.models.FederatedIdentityModel;
 import org.keycloak.models.IdentityProviderModel;
 import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserSessionModel;
 import org.keycloak.provider.Provider;
 
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
+import java.util.Map;
 
 /**
  * @author Pedro Igor
  */
 public interface IdentityProvider<C extends IdentityProviderModel> extends Provider {
 
+    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 for when the remote IDP wants to callback to keycloak.
+     *
+     * @return
+     */
+    Object callback(RealmModel realm, AuthenticationCallback callback);
+
     /**
      * <p>Initiates the authentication process by sending an authentication request to an identity provider. This method is called
      * only once during the authentication.</p>
@@ -44,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
@@ -80,6 +79,17 @@ public interface IdentityProvider<C extends IdentityProviderModel> extends Provi
     Response retrieveToken(FederatedIdentityModel identity);
 
     /**
+     * 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
      *
      * @return

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);
+        }
+    }
 }

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

diff --git a/broker/saml/pom.xml b/broker/saml/pom.xml
index ddd174c..300df94 100755
--- a/broker/saml/pom.xml
+++ b/broker/saml/pom.xml
@@ -31,6 +31,23 @@
             <groupId>org.picketlink</groupId>
             <artifactId>picketlink-federation</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-services</artifactId>
+            <version>${project.version}</version>
+            <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.jboss.logging</groupId>
+            <artifactId>jboss-logging</artifactId>
+            <scope>provided</scope>
+        </dependency>
     </dependencies>
 
 </project>
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
new file mode 100755
index 0000000..849b2b5
--- /dev/null
+++ b/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLEndpoint.java
@@ -0,0 +1,372 @@
+package org.keycloak.broker.saml;
+
+import org.jboss.logging.Logger;
+import org.jboss.resteasy.spi.HttpRequest;
+import org.keycloak.ClientConnection;
+import org.keycloak.VerificationException;
+import org.keycloak.broker.provider.FederatedIdentity;
+import org.keycloak.broker.provider.IdentityBrokerException;
+import org.keycloak.broker.provider.IdentityProvider;
+import org.keycloak.events.Details;
+import org.keycloak.events.Errors;
+import org.keycloak.events.EventBuilder;
+import org.keycloak.events.EventType;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserSessionModel;
+import org.keycloak.protocol.saml.SAMLRequestParser;
+import org.keycloak.protocol.saml.SamlProtocol;
+import org.keycloak.protocol.saml.SamlProtocolUtils;
+import org.keycloak.services.managers.AuthenticationManager;
+import org.keycloak.services.managers.EventsManager;
+import org.keycloak.services.messages.Messages;
+import org.keycloak.services.resources.flows.Flows;
+import org.picketlink.common.constants.GeneralConstants;
+import org.picketlink.common.constants.JBossSAMLConstants;
+import org.picketlink.common.constants.JBossSAMLURIConstants;
+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.response.SAML2Response;
+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.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.protocol.ResponseType;
+import org.picketlink.identity.federation.saml.v2.protocol.StatusResponseType;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+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.Response;
+import javax.ws.rs.core.UriInfo;
+import javax.xml.namespace.QName;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.cert.X509Certificate;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class SAMLEndpoint {
+    protected static final Logger logger = Logger.getLogger(SAMLEndpoint.class);
+    protected RealmModel realm;
+    protected EventBuilder event;
+    protected SAMLIdentityProviderConfig config;
+    protected IdentityProvider.AuthenticationCallback callback;
+
+    @Context
+    private UriInfo uriInfo;
+
+    @Context
+    private KeycloakSession session;
+
+    @Context
+    private ClientConnection clientConnection;
+
+    @Context
+    private HttpRequest request;
+
+    @Context
+    private HttpHeaders headers;
+
+
+    public SAMLEndpoint(RealmModel realm, SAMLIdentityProviderConfig config, IdentityProvider.AuthenticationCallback callback) {
+        this.realm = realm;
+        this.config = config;
+        this.callback = callback;
+    }
+
+    @GET
+    public Response redirectBinding(@QueryParam(GeneralConstants.SAML_REQUEST_KEY) String samlRequest,
+                                    @QueryParam(GeneralConstants.SAML_RESPONSE_KEY) String samlResponse,
+                                    @QueryParam(GeneralConstants.RELAY_STATE) String relayState)  {
+        return new RedirectBinding().execute(samlRequest, samlResponse, relayState);
+    }
+
+
+    /**
+     */
+    @POST
+    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+    public Response postBinding(@FormParam(GeneralConstants.SAML_REQUEST_KEY) String samlRequest,
+                                @FormParam(GeneralConstants.SAML_RESPONSE_KEY) String samlResponse,
+                                @FormParam(GeneralConstants.RELAY_STATE) String relayState) {
+        return new PostBinding().execute(samlRequest, samlResponse, relayState);
+    }
+
+    protected abstract class Binding {
+        private boolean checkSsl() {
+            if (uriInfo.getBaseUri().getScheme().equals("https")) {
+                return true;
+            } else {
+                return !realm.getSslRequired().isRequired(clientConnection);
+            }
+        }
+
+        protected Response basicChecks(String samlRequest, String samlResponse) {
+            if (!checkSsl()) {
+                event.event(EventType.LOGIN);
+                event.error(Errors.SSL_REQUIRED);
+                return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.HTTPS_REQUIRED);
+            }
+            if (!realm.isEnabled()) {
+                event.event(EventType.LOGIN_ERROR);
+                event.error(Errors.REALM_DISABLED);
+                return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.REALM_NOT_ENABLED);
+            }
+
+            if (samlRequest == null && samlResponse == null) {
+                event.event(EventType.LOGIN);
+                event.error(Errors.INVALID_REQUEST);
+                return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.INVALID_REQUEST );
+
+            }
+            return null;
+        }
+
+        protected abstract String getBindingType();
+        protected abstract void verifySignature(SAMLDocumentHolder documentHolder) throws VerificationException;
+        protected abstract SAMLDocumentHolder extractRequestDocument(String samlRequest);
+        protected abstract SAMLDocumentHolder extractResponseDocument(String response);
+        protected PublicKey getIDPKey() {
+            X509Certificate certificate = null;
+            try {
+                certificate = XMLSignatureUtil.getX509CertificateFromKeyInfoString(config.getSigningCertificate().replaceAll("\\s", ""));
+            } catch (ProcessingException e) {
+                throw new RuntimeException(e);
+            }
+            return certificate.getPublicKey();
+        }
+
+        public Response execute(String samlRequest, String samlResponse, String relayState) {
+            event = new EventsManager(realm, session, clientConnection).createEventBuilder();
+            Response response = basicChecks(samlRequest, samlResponse);
+            if (response != null) return response;
+            if (samlRequest != null) throw new RuntimeException("NOT IMPLEMETED");//return handleSamlRequest(samlRequest, relayState);
+            else return handleSamlResponse(samlResponse, relayState);
+        }
+
+        protected Response handleLoginResponse(String samlResponse, SAMLDocumentHolder holder, ResponseType responseType, String relayState) {
+            if (config.isValidateSignature()) {
+                try {
+                    verifySignature(holder);
+                } catch (VerificationException e) {
+                    logger.error("validation failed", e);
+                    event.event(EventType.LOGIN);
+                    event.error(Errors.INVALID_SIGNATURE);
+                    return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.INVALID_REQUESTER);
+                }
+            }
+
+            try {
+                AssertionType assertion = getAssertion(responseType);
+                SubjectType subject = assertion.getSubject();
+                SubjectType.STSubType subType = subject.getSubType();
+                NameIDType subjectNameID = (NameIDType) subType.getBaseID();
+                Map<String, String> notes = new HashMap<>();
+                notes.put("SAML_FEDERATED_SUBJECT", subjectNameID.getValue());
+                if (subjectNameID.getFormat() != null) notes.put("SAML_FEDERATED_SUBJECT_NAMEFORMAT", subjectNameID.getFormat().toString());
+                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 (config.isStoreToken()) {
+                    identity.setToken(samlResponse);
+                }
+
+                AuthnStatementType authn = null;
+                for (Object statement : assertion.getStatements()) {
+                    if (statement instanceof AuthnStatementType) {
+                        authn = (AuthnStatementType)statement;
+                        break;
+                    }
+                }
+                if (authn != null && authn.getSessionIndex() != null) {
+                    notes.put("SAML_FEDERATED_SESSION_INDEX", authn.getSessionIndex());
+                }
+                return callback.authenticated(notes, config, identity, relayState);
+
+            } catch (Exception e) {
+                throw new IdentityBrokerException("Could not process response from SAML identity provider.", e);
+            }
+
+
+        }
+
+        private AssertionType getAssertion(ResponseType responseType) throws ProcessingException {
+            List<ResponseType.RTChoiceType> assertions = responseType.getAssertions();
+
+            if (assertions.isEmpty()) {
+                throw new IdentityBrokerException("No assertion from response.");
+            }
+
+            ResponseType.RTChoiceType rtChoiceType = assertions.get(0);
+            EncryptedAssertionType encryptedAssertion = rtChoiceType.getEncryptedAssertion();
+
+            if (encryptedAssertion != null) {
+                decryptAssertion(responseType, realm.getPrivateKey());
+
+            }
+            return responseType.getAssertions().get(0).getAssertion();
+        }
+
+        public Response handleSamlResponse(String samlResponse, String relayState) {
+            SAMLDocumentHolder holder = extractResponseDocument(samlResponse);
+            StatusResponseType statusResponse = (StatusResponseType)holder.getSamlObject();
+            // validate destination
+            if (!uriInfo.getAbsolutePath().toString().equals(statusResponse.getDestination())) {
+                event.event(EventType.IDENTITY_PROVIDER_RESPONSE);
+                event.error(Errors.INVALID_SAML_RESPONSE);
+                event.detail(Details.REASON, "invalid_destination");
+                return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.INVALID_REQUEST);
+            }
+            if (statusResponse instanceof ResponseType) {
+                return handleLoginResponse(samlResponse, holder, (ResponseType)statusResponse, relayState);
+
+            } else {
+                // todo need to check that it is actually a LogoutResponse
+                return handleLogoutResponse(holder, statusResponse, relayState);
+            }
+            //throw new RuntimeException("Unknown response type");
+
+        }
+
+        protected Response handleLogoutResponse(SAMLDocumentHolder holder, StatusResponseType responseType, String relayState) {
+            if (config.isValidateSignature()) {
+                try {
+                    verifySignature(holder);
+                } catch (VerificationException e) {
+                    logger.error("logout response validation failed", e);
+                    event.event(EventType.LOGOUT);
+                    event.error(Errors.INVALID_SIGNATURE);
+                    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.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.IDENTITY_PROVIDER_UNEXPECTED_ERROR);
+            }
+            if (userSession.getState() != UserSessionModel.State.LOGGING_OUT) {
+                logger.error("usersession in different state");
+                event.event(EventType.LOGOUT);
+                event.error(Errors.USER_SESSION_NOT_FOUND);
+                return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.SESSION_NOT_ACTIVE);
+            }
+            return AuthenticationManager.finishBrowserLogout(session, realm, userSession, uriInfo, clientConnection, headers);
+        }
+
+
+        protected 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 ResponseType.RTChoiceType(assertion));
+
+                return responseType;
+            } catch (Exception e) {
+                throw new IdentityBrokerException("Could not decrypt assertion.", e);
+            }
+        }
+
+
+    }
+
+    protected class PostBinding extends Binding {
+        @Override
+        protected void verifySignature(SAMLDocumentHolder documentHolder) throws VerificationException {
+            SamlProtocolUtils.verifyDocumentSignature(documentHolder.getSamlDocument(), getIDPKey());
+        }
+
+        @Override
+        protected SAMLDocumentHolder extractRequestDocument(String samlRequest) {
+            return SAMLRequestParser.parseRequestPostBinding(samlRequest);
+        }
+        @Override
+        protected SAMLDocumentHolder extractResponseDocument(String response) {
+            return SAMLRequestParser.parseResponsePostBinding(response);
+        }
+
+        @Override
+        protected String getBindingType() {
+            return SamlProtocol.SAML_POST_BINDING;
+        }
+    }
+
+    protected class RedirectBinding extends Binding {
+        @Override
+        protected void verifySignature(SAMLDocumentHolder documentHolder) throws VerificationException {
+            PublicKey publicKey = getIDPKey();
+            SamlProtocolUtils.verifyRedirectSignature(publicKey, uriInfo);
+        }
+
+
+
+        @Override
+        protected SAMLDocumentHolder extractRequestDocument(String samlRequest) {
+            return SAMLRequestParser.parseRequestRedirectBinding(samlRequest);
+        }
+
+        @Override
+        protected SAMLDocumentHolder extractResponseDocument(String response) {
+            return SAMLRequestParser.parseRequestRedirectBinding(response);
+        }
+
+        @Override
+        protected String getBindingType() {
+            return SamlProtocol.SAML_REDIRECT_BINDING;
+        }
+
+    }
+
+}
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 625424b..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,75 +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.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.picketlink.common.constants.JBossSAMLConstants;
 import org.picketlink.common.constants.JBossSAMLURIConstants;
-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.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 AuthenticationResponse handleRequest(AuthenticationRequest request) {
+    public Object callback(RealmModel realm, AuthenticationCallback callback) {
+        return new SAMLEndpoint(realm, getConfig(), callback);
+    }
+
+    @Override
+    public Response handleRequest(AuthenticationRequest request) {
         try {
             UriInfo uriInfo = request.getUriInfo();
             RealmModel realm = request.getRealm();
@@ -99,12 +64,14 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
 
             String protocolBinding = JBossSAMLURIConstants.SAML_HTTP_REDIRECT_BINDING.get();
 
+            String assertionConsumerServiceUrl = request.getRedirectUri();
+
             if (getConfig().isPostBindingResponse()) {
                 protocolBinding = JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.get();
             }
 
             SAML2AuthnRequestBuilder authnRequestBuilder = new SAML2AuthnRequestBuilder()
-                    .assertionConsumerUrl(request.getRedirectUri())
+                    .assertionConsumerUrl(assertionConsumerServiceUrl)
                     .destination(destinationUrl)
                     .issuer(issuerURL)
                     .forceAuthn(getConfig().isForceAuthn())
@@ -117,11 +84,11 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
                 PublicKey publicKey = realm.getPublicKey();
 
                 if (privateKey == null) {
-                    throw new IdentityBrokerException("Identity Provider [" + getConfig().getName() + "] wants a signed authentication request. But the Realm [" + realm.getName() + "] does not have a private key.");
+                    throw new IdentityBrokerException("Identity Provider [" + getConfig().getAlias() + "] wants a signed authentication request. But the Realm [" + realm.getName() + "] does not have a private key.");
                 }
 
                 if (publicKey == null) {
-                    throw new IdentityBrokerException("Identity Provider [" + getConfig().getName() + "] wants a signed authentication request. But the Realm [" + realm.getName() + "] does not have a public key.");
+                    throw new IdentityBrokerException("Identity Provider [" + getConfig().getAlias() + "] wants a signed authentication request. But the Realm [" + realm.getName() + "] does not have a public key.");
                 }
 
                 KeyPair keypair = new KeyPair(publicKey, privateKey);
@@ -131,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);
@@ -145,151 +112,29 @@ 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() + ".");
+    @Override
+    public Response keycloakInitiatedBrowserLogout(UserSessionModel userSession, UriInfo uriInfo, RealmModel realm) {
+        if (getConfig().getSingleLogoutServiceUrl() == null) return null;
+
+        SAML2LogoutRequestBuilder logoutBuilder = new SAML2LogoutRequestBuilder()
+                .issuer(getEntityId(uriInfo, realm))
+                .sessionIndex(userSession.getNote("SAML_FEDERATED_SESSION_INDEX"))
+                .userPrincipal(userSession.getNote("SAML_FEDERATED_SUBJECT"), userSession.getNote("SAML_FEDERATED_SUBJECT_NAMEFORMAT"))
+                .destination(getConfig().getSingleLogoutServiceUrl());
+        if (getConfig().isWantAuthnRequestsSigned()) {
+            logoutBuilder.signWith(realm.getPrivateKey(), realm.getPublicKey(), realm.getCertificate())
+                    .signDocument();
         }
-    }
-
-    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;
+            return logoutBuilder.relayState(userSession.getId()).postBinding().request();
         } 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();
+            throw new RuntimeException(e);
         }
 
-        return requestParameters.getFirst(parameterName);
     }
 
     @Override
@@ -301,7 +146,12 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
             authnBinding = JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.get();
         }
 
-        String assertionConsumerService = uriInfo.getBaseUriBuilder().path("realms").path(realm.getName()).path("broker").path(getConfig().getId()).build().toString();
+        String endpoint = uriInfo.getBaseUriBuilder()
+                .path("realms").path(realm.getName())
+                .path("broker")
+                .path(getConfig().getAlias())
+                .path("endpoint")
+                .build().toString();
 
 
 
@@ -311,10 +161,9 @@ 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=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\" Location=\"http://localhost:8081/sales-metadata/\"/>\n" +
+                "        <SingleLogoutService Binding=\"" + authnBinding + "\" Location=\"" + endpoint + "\"/>\n" +
                 "        <AssertionConsumerService\n" +
-                "                Binding=\"" + authnBinding + "\" Location=\"" + assertionConsumerService + "\"\n" +
+                "                Binding=\"" + authnBinding + "\" Location=\"" + endpoint + "\"\n" +
                 "                index=\"1\" isDefault=\"true\" />\n";
         if (getConfig().isWantAuthnRequestsSigned()) {
             descriptor +=
diff --git a/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProviderConfig.java b/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProviderConfig.java
old mode 100644
new mode 100755
index 98ebb28..10ef464
--- a/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProviderConfig.java
+++ b/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProviderConfig.java
@@ -39,6 +39,14 @@ public class SAMLIdentityProviderConfig extends IdentityProviderModel {
         getConfig().put("singleSignOnServiceUrl", singleSignOnServiceUrl);
     }
 
+    public String getSingleLogoutServiceUrl() {
+        return getConfig().get("singleLogoutServiceUrl");
+    }
+
+    public void setSingleLogoutServiceUrl(String singleLogoutServiceUrl) {
+        getConfig().put("singleLogoutServiceUrl", singleLogoutServiceUrl);
+    }
+
     public boolean isValidateSignature() {
         return Boolean.valueOf(getConfig().get("validateSignature"));
     }
diff --git a/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProviderFactory.java b/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProviderFactory.java
index 2370a16..559b415 100755
--- a/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProviderFactory.java
+++ b/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProviderFactory.java
@@ -56,7 +56,7 @@ public class SAMLIdentityProviderFactory extends AbstractIdentityProviderFactory
     }
 
     @Override
-    public Map<String, String>  parseConfig(InputStream inputStream) {
+    public Map<String, String> parseConfig(InputStream inputStream) {
         try {
             Object parsedObject = new SAMLParser().parse(inputStream);
             EntityDescriptorType entityType;
@@ -90,6 +90,18 @@ public class SAMLIdentityProviderFactory extends AbstractIdentityProviderFactory
                                 singleSignOnServiceUrl = endpoint.getLocation().toString();
                             }
                         }
+                        String singleLogoutServiceUrl = null;
+                        for (EndpointType endpoint : idpDescriptor.getSingleLogoutService()) {
+                            if (postBinding && endpoint.getBinding().toString().equals(JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.get())) {
+                                singleLogoutServiceUrl = endpoint.getLocation().toString();
+                                break;
+                            } else if (!postBinding && endpoint.getBinding().toString().equals(JBossSAMLURIConstants.SAML_HTTP_REDIRECT_BINDING.get())){
+                                singleLogoutServiceUrl = endpoint.getLocation().toString();
+                                break;
+                            }
+
+                        }
+                        samlIdentityProviderConfig.setSingleLogoutServiceUrl(singleLogoutServiceUrl);
                         samlIdentityProviderConfig.setSingleSignOnServiceUrl(singleSignOnServiceUrl);
                         samlIdentityProviderConfig.setWantAuthnRequestsSigned(idpDescriptor.isWantAuthnRequestsSigned());
                         samlIdentityProviderConfig.setValidateSignature(idpDescriptor.isWantAuthnRequestsSigned());
diff --git a/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.2.0.Beta1.xml b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.2.0.Beta1.xml
index b545aa3..27eb99f 100755
--- a/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.2.0.Beta1.xml
+++ b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.2.0.Beta1.xml
@@ -47,8 +47,7 @@
                 <constraints nullable="false"/>
             </column>
             <column name="ENABLED" type="BOOLEAN" defaultValueBoolean="false"/>
-            <column name="PROVIDER_NONIMAL_ID" type="VARCHAR(255)"/>
-            <column name="PROVIDER_NAME" type="VARCHAR(255)"/>
+            <column name="PROVIDER_ALIAS" type="VARCHAR(255)"/>
             <column name="PROVIDER_ID" type="VARCHAR(255)"/>
             <column name="UPDATE_PROFILE_FIRST_LOGIN" type="BOOLEAN" defaultValueBoolean="false"/>
             <column name="STORE_TOKEN" type="BOOLEAN" defaultValueBoolean="false"/>
@@ -95,7 +94,7 @@
         <addForeignKeyConstraint baseColumnNames="IDENTITY_PROVIDER_ID" baseTableName="CLIENT_IDENTITY_PROVIDER_MAPPING" constraintName="FK_7CELWNIBJI49AVXSRTUF6XJ12" referencedColumnNames="INTERNAL_ID" referencedTableName="IDENTITY_PROVIDER"/>
         <addForeignKeyConstraint baseColumnNames="CLIENT_ID" baseTableName="CLIENT_IDENTITY_PROVIDER_MAPPING" constraintName="FK_56ELWNIBJI49AVXSRTUF6XJ23" referencedColumnNames="ID" referencedTableName="CLIENT"/>
         <addForeignKeyConstraint baseColumnNames="REALM_ID" baseTableName="REALM_SUPPORTED_LOCALES" constraintName="FK_SUPPORTED_LOCALES_REALM" referencedColumnNames="ID" referencedTableName="REALM"/>
-        <addUniqueConstraint columnNames="PROVIDER_NONIMAL_ID" constraintName="UK_2DAELWNIBJI49AVXSRTUF6XJ33" tableName="IDENTITY_PROVIDER"/>
+        <addUniqueConstraint columnNames="PROVIDER_ALIAS, REALM_ID" constraintName="UK_2DAELWNIBJI49AVXSRTUF6XJ33" tableName="IDENTITY_PROVIDER"/>
         <addUniqueConstraint columnNames="IDENTITY_PROVIDER_ID,CLIENT_ID" constraintName="UK_7CAELWNIBJI49AVXSRTUF6XJ12" tableName="CLIENT_IDENTITY_PROVIDER_MAPPING"/>
 
         <addColumn tableName="REALM">
diff --git a/core/src/main/java/org/keycloak/representations/idm/IdentityProviderRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/IdentityProviderRepresentation.java
old mode 100644
new mode 100755
index c0b0852..2e89c64
--- a/core/src/main/java/org/keycloak/representations/idm/IdentityProviderRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/IdentityProviderRepresentation.java
@@ -25,15 +25,13 @@ import java.util.Map;
  */
 public class IdentityProviderRepresentation {
 
-    protected String id;
+    protected String alias;
     protected String internalId;
     protected String providerId;
-    protected String name;
     protected boolean enabled = true;
     protected boolean updateProfileFirstLogin = true;
     protected boolean storeToken;
     protected boolean authenticateByDefault;
-    protected String groupName;
     protected Map<String, String> config = new HashMap<String, String>();
 
     public String getInternalId() {
@@ -44,12 +42,12 @@ public class IdentityProviderRepresentation {
         this.internalId = internalId;
     }
 
-    public String getId() {
-        return this.id;
+    public String getAlias() {
+        return this.alias;
     }
 
-    public void setId(String id) {
-        this.id = id;
+    public void setAlias(String alias) {
+        this.alias = alias;
     }
 
     public String getProviderId() {
@@ -60,14 +58,6 @@ public class IdentityProviderRepresentation {
         this.providerId = providerId;
     }
 
-    public String getName() {
-        return this.name;
-    }
-
-    public void setName(String name) {
-        this.name = name;
-    }
-
     public Map<String, String> getConfig() {
         return this.config;
     }
@@ -107,12 +97,4 @@ public class IdentityProviderRepresentation {
     public void setStoreToken(boolean storeToken) {
         this.storeToken = storeToken;
     }
-
-    public String getGroupName() {
-        return this.groupName;
-    }
-
-    public void setGroupName(String groupName) {
-        this.groupName = groupName;
-    }
 }
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 7a4404d..41b501d 100755
--- a/events/api/src/main/java/org/keycloak/events/Errors.java
+++ b/events/api/src/main/java/org/keycloak/events/Errors.java
@@ -26,6 +26,7 @@ public interface Errors {
     String INVALID_REDIRECT_URI = "invalid_redirect_uri";
     String INVALID_CODE = "invalid_code";
     String INVALID_TOKEN = "invalid_token";
+    String INVALID_SAML_RESPONSE = "invalid_saml_response";
     String INVALID_SAML_AUTHN_REQUEST = "invalid_authn_request";
     String INVALID_SAML_LOGOUT_REQUEST = "invalid_logout_request";
     String INVALID_SAML_LOGOUT_RESPONSE = "invalid_logout_response";
@@ -48,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";
 }
diff --git a/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/model/AccountFederatedIdentityBean.java b/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/model/AccountFederatedIdentityBean.java
index f8d10be..775d8f5 100755
--- a/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/model/AccountFederatedIdentityBean.java
+++ b/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/model/AccountFederatedIdentityBean.java
@@ -34,7 +34,7 @@ public class AccountFederatedIdentityBean {
         int availableIdentities = 0;
         if (identityProviders != null && !identityProviders.isEmpty()) {
             for (IdentityProviderModel provider : identityProviders) {
-                String providerId = provider.getId();
+                String providerId = provider.getAlias();
 
                 FederatedIdentityModel identity = getIdentity(identities, providerId);
 
@@ -49,7 +49,7 @@ public class AccountFederatedIdentityBean {
                         .queryParam("stateChecker", stateChecker)
                         .build().toString();
 
-                FederatedIdentityEntry entry = new FederatedIdentityEntry(identity, provider.getId(), provider.getName(), actionUrl);
+                FederatedIdentityEntry entry = new FederatedIdentityEntry(identity, provider.getAlias(), actionUrl);
                 this.identities.add(entry);
             }
         }
@@ -79,13 +79,11 @@ public class AccountFederatedIdentityBean {
 
         private FederatedIdentityModel federatedIdentityModel;
         private final String providerId;
-        private final String providerName;
         private final String actionUrl;
 
-        public FederatedIdentityEntry(FederatedIdentityModel federatedIdentityModel, String providerId, String providerName, String actionUrl) {
+        public FederatedIdentityEntry(FederatedIdentityModel federatedIdentityModel, String providerId, String actionUrl) {
             this.federatedIdentityModel = federatedIdentityModel;
             this.providerId = providerId;
-            this.providerName = providerName;
             this.actionUrl = actionUrl;
         }
 
@@ -93,10 +91,6 @@ public class AccountFederatedIdentityBean {
             return providerId;
         }
 
-        public String getProviderName() {
-            return providerName;
-        }
-
         public String getUserId() {
             return federatedIdentityModel != null ? federatedIdentityModel.getUserId() : null;
         }
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/app.js b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/app.js
index c34debe..d39c8e5 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/app.js
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/app.js
@@ -170,7 +170,7 @@ module.config([ '$routeProvider', function($routeProvider) {
             },
             controller : 'RealmIdentityProviderCtrl'
         })
-        .when('/realms/:realm/identity-provider-settings/provider/:provider_id/:id', {
+        .when('/realms/:realm/identity-provider-settings/provider/:provider_id/:alias', {
             templateUrl : function(params){ return resourceUrl + '/partials/realm-identity-provider-' + params.provider_id + '.html'; },
             resolve : {
                 realm : function(RealmLoader) {
@@ -188,7 +188,7 @@ module.config([ '$routeProvider', function($routeProvider) {
             },
             controller : 'RealmIdentityProviderCtrl'
         })
-        .when('/realms/:realm/identity-provider-settings/provider/:provider_id/:id/export', {
+        .when('/realms/:realm/identity-provider-settings/provider/:provider_id/:alias/export', {
             templateUrl : resourceUrl + '/partials/realm-identity-provider-export.html',
             resolve : {
                 realm : function(RealmLoader) {
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/realm.js b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/realm.js
index 42562dd..55b74f0 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/realm.js
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/realm.js
@@ -638,44 +638,93 @@ module.controller('RealmDefaultRolesCtrl', function ($scope, Realm, realm, appli
 
 });
 
-module.controller('RealmIdentityProviderCtrl', function($scope, $filter, $upload, $http, realm, instance, providerFactory, IdentityProvider, serverInfo, $location, Notifications) {
+module.controller('RealmIdentityProviderCtrl', function($scope, $filter, $upload, $http, realm, instance, providerFactory, IdentityProvider, serverInfo, $location, Notifications, Dialog) {
     console.log('RealmIdentityProviderCtrl');
 
     $scope.realm = angular.copy(realm);
 
-    $scope.hidePassword = true;
+    $scope.initSamlProvider = function() {
+        $scope.nameIdFormats = [
+            {
+                format: "urn:oasis:names:tc:SAML:2.0:nameid-format:transient",
+                name: "Transient"
+            },
+            {
+                format: "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent",
+                name: "Persistent"
+
+            },
+            {
+                format: "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress",
+                name: "Email"
+
+            },
+            {
+                format: "urn:oasis:names:tc:SAML:2.0:nameid-format:kerberos",
+                name: "Kerberos"
+
+            },
+            {
+                format: "urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName",
+                name: "X.509 Subject Name"
+
+            },
+            {
+                format: "urn:oasis:names:tc:SAML:1.1:nameid-format:WindowsDomainQualifiedName",
+                name: "Windows Domain Qualified Name"
+
+            },
+            {
+                format: "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified",
+                name: "Unspecified"
+
+            }
+        ];
+        if (instance && instance.alias) {
 
-    $scope.getBoolean = function(value) {
-        if (value == 'true') {
-            return true;
-        } else if (value == 'false') {
-            return false;
         } else {
-            return value;
+            $scope.identityProvider.config.nameIDPolicyFormat = $scope.nameIdFormats[0].format;
         }
     }
 
-    if (instance && instance.id) {
+    $scope.hidePassword = true;
+
+    if (instance && instance.alias) {
         $scope.identityProvider = angular.copy(instance);
         $scope.newIdentityProvider = false;
     } else {
         $scope.identityProvider = {};
         $scope.identityProvider.config = {};
-        $scope.identityProvider.id = "";
+        $scope.identityProvider.alias = providerFactory.name;
         $scope.identityProvider.providerId = providerFactory.id;
-        $scope.identityProvider.name = providerFactory.name;
         $scope.identityProvider.enabled = true;
         $scope.identityProvider.updateProfileFirstLogin = true;
         $scope.identityProvider.authenticateByDefault = false;
         $scope.newIdentityProvider = true;
     }
 
+    $scope.changed = $scope.newIdentityProvider;
+
+    $scope.$watch('identityProvider', function() {
+        if (!angular.equals($scope.identityProvider, instance)) {
+            $scope.changed = true;
+        }
+    }, true);
+
+
     $scope.serverInfo = serverInfo;
 
     $scope.allProviders = angular.copy(serverInfo.identityProviders);
 
     $scope.configuredProviders = angular.copy(realm.identityProviders);
 
+    $scope.$watch(function() {
+        return $location.path();
+    }, function() {
+        $scope.path = $location.path().substring(1).split("/");
+    });
+
+
     $scope.files = [];
     $scope.importFile = false;
     $scope.importUrl = false;
@@ -689,9 +738,23 @@ module.controller('RealmIdentityProviderCtrl', function($scope, $filter, $upload
         $scope.importUrl = false;
         $scope.importFile = false;
         $scope.files = null;
+    };
+
+    var setConfig = function(data) {
+        for (var key in data) {
+            $scope.identityProvider.config[key] = data[key];
+        }
     }
 
+
     $scope.uploadFile = function() {
+        if (!$scope.identityProvider.alias) {
+            Notifications.error("You must specify an alias");
+            return;
+        }
+        var input = {
+            providerId: providerFactory.id
+        }
         //$files: an array of files selected, each file has name, size, and type.
         for (var i = 0; i < $scope.files.length; i++) {
             var $file = $scope.files[i];
@@ -699,7 +762,7 @@ module.controller('RealmIdentityProviderCtrl', function($scope, $filter, $upload
                 url: authUrl + '/admin/realms/' + realm.realm + '/identity-provider/import',
                 // method: POST or PUT,
                 // headers: {'headerKey': 'headerValue'}, withCredential: true,
-                data: $scope.identityProvider,
+                data: input,
                 file: $file
                 /* set file formData name for 'Content-Desposition' header. Default: 'file' */
                 //fileFormDataName: myFile,
@@ -708,8 +771,9 @@ module.controller('RealmIdentityProviderCtrl', function($scope, $filter, $upload
             }).progress(function(evt) {
                 console.log('percent: ' + parseInt(100.0 * evt.loaded / evt.total));
             }).success(function(data, status, headers) {
-                $location.url("/realms/" + realm.realm + "/identity-provider-settings");
-                Notifications.success("The " + $scope.identityProvider.name + " provider has been created.");
+                setConfig(data);
+                $scope.clearFileSelect();
+                Notifications.success("The IDP metadata has been loaded from file.");
             }).error(function() {
                 Notifications.error("The file can not be uploaded. Please verify the file.");
             });
@@ -717,13 +781,22 @@ module.controller('RealmIdentityProviderCtrl', function($scope, $filter, $upload
     };
 
     $scope.importFrom = function() {
-        $scope.identityProvider.fromUrl = $scope.fromUrl;
-        $http.post(authUrl + '/admin/realms/' + realm.realm + '/identity-provider/import', $scope.identityProvider)
+        if (!$scope.identityProvider.alias) {
+            Notifications.error("You must specify an alias");
+            return;
+        }
+        var input = {
+            fromUrl: $scope.fromUrl,
+            providerId: providerFactory.id
+        }
+        $http.post(authUrl + '/admin/realms/' + realm.realm + '/identity-provider/import-config', input)
             .success(function(data, status, headers) {
-                $location.url("/realms/" + realm.realm + "/identity-provider-settings");
-                Notifications.success("The " + $scope.identityProvider.name + " provider has been created.");
+                setConfig(data);
+                $scope.fromUrl = null;
+                $scope.importUrl = false;
+                Notifications.success("Imported config information from url.");
             }).error(function() {
-                Notifications.error("The provider can not be imported. Please verify the url.");
+                Notifications.error("Config can not be imported. Please verify the url.");
             });
     };
     $scope.$watch('fromUrl', function(newVal, oldVal){
@@ -756,24 +829,30 @@ module.controller('RealmIdentityProviderCtrl', function($scope, $filter, $upload
     $scope.callbackUrl = $location.absUrl().replace(/\/admin.*/, "/realms/") + realm.realm + "/broker/" ;
 
     $scope.addProvider = function(provider) {
+        console.log('addProvider');
         $location.url("/create/identity-provider/" + realm.realm + "/" + provider.id);
     };
 
     $scope.remove = function() {
-        IdentityProvider.delete({
-            realm: $scope.realm.realm,
-            id: $scope.identityProvider.id
-        }, $scope.identityProvider, function () {
-            $scope.changed = false;
-            $location.url("/realms/" + realm.realm + "/identity-provider-settings");
-            Notifications.success("The " + $scope.identityProvider.name + " provider has been deleted.");
+        Dialog.confirmDelete($scope.identityProvider.alias, 'provider', function() {
+            $scope.identityProvider.$remove({
+                realm : realm.realm,
+                alias : $scope.identityProvider.alias
+            }, function() {
+                $location.url("/realms/" + realm.realm + "/identity-provider-settings");
+                Notifications.success("The application has been deleted.");
+            });
         });
     };
 
     $scope.save = function() {
         if ($scope.newIdentityProvider) {
-            IdentityProvider.create({
-                realm: $scope.realm.realm
+            if (!$scope.identityProvider.alias) {
+                Notifications.error("You must specify an alias");
+                return;
+            }
+            IdentityProvider.save({
+                realm: $scope.realm.realm, alias: ''
             }, $scope.identityProvider, function () {
                 $location.url("/realms/" + realm.realm + "/identity-provider-settings");
                 Notifications.success("The " + $scope.identityProvider.name + " provider has been created.");
@@ -789,6 +868,11 @@ module.controller('RealmIdentityProviderCtrl', function($scope, $filter, $upload
         }
     };
 
+    $scope.cancel = function() {
+        $location.url("/realms/" + realm.realm + "/identity-provider-settings");
+    };
+
+
     $scope.reset = function() {
         $scope.identityProvider = {};
         $scope.configuredProviders = angular.copy($scope.realm.identityProviders);
@@ -798,39 +882,6 @@ module.controller('RealmIdentityProviderCtrl', function($scope, $filter, $upload
         $scope.hidePassword = flag;
     };
 
-    $scope.getBoolean = function(value) {
-        if (value == 'true') {
-            return true;
-        } else if (value == 'false') {
-            return false;
-        } else {
-            return value;
-        }
-    }
-
-    $scope.initSamlProvider = function() {
-        if (instance && instance.id) {
-            $scope.identityProvider.config.validateSignature = $scope.getBoolean($scope.identityProvider.config.validateSignature);
-            $scope.identityProvider.config.forceAuthn = $scope.getBoolean($scope.identityProvider.config.forceAuthn);
-            $scope.identityProvider.config.postBindingAuthnRequest = $scope.getBoolean($scope.identityProvider.config.postBindingAuthnRequest);
-            $scope.identityProvider.config.postBindingResponse = $scope.getBoolean($scope.identityProvider.config.postBindingResponse);
-            $scope.identityProvider.config.wantAuthnRequestsSigned = $scope.getBoolean($scope.identityProvider.config.wantAuthnRequestsSigned);
-        } else {
-            $scope.identityProvider.config.validateSignature = true;
-            $scope.identityProvider.config.postBindingAuthnRequest = true;
-            $scope.identityProvider.config.postBindingResponse = true;
-            $scope.identityProvider.config.wantAuthnRequestsSigned = true;
-            $scope.identityProvider.config.nameIDPolicyFormat = 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient';
-        }
-    }
-
-    $scope.initKerberosProvider = function() {
-        if (instance && instance.id) {
-            $scope.identityProvider.config.debug = $scope.getBoolean($scope.identityProvider.config.debug);
-        } else {
-            $scope.identityProvider.config.debug = false;
-        }
-    }
 });
 
 module.controller('RealmIdentityProviderExportCtrl', function(realm, identityProvider, $scope, $http, IdentityProviderExport) {
@@ -840,7 +891,7 @@ module.controller('RealmIdentityProviderExportCtrl', function(realm, identityPro
     $scope.exported = "";
     $scope.exportedType = "";
 
-    var url = IdentityProviderExport.url({realm: realm.realm, id: identityProvider.id}) ;
+    var url = IdentityProviderExport.url({realm: realm.realm, alias: identityProvider.alias}) ;
     $http.get(url).success(function(data, status, headers, config) {
         $scope.exportedType = headers('Content-Type');
         $scope.exported = data;
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 e9c3480..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
@@ -301,7 +301,7 @@ module.factory('IdentityProviderLoader', function(Loader, IdentityProvider, $rou
     return Loader.get(IdentityProvider, function () {
         return {
             realm: $route.current.params.realm,
-            id: $route.current.params.id
+            alias: $route.current.params.alias
         }
     });
 });
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/services.js b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/services.js
index 4b53346..6dbe6b8 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/services.js
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/services.js
@@ -1102,15 +1102,10 @@ module.factory('PasswordPolicy', function() {
 });
 
 module.factory('IdentityProvider', function($resource) {
-    return $resource(authUrl + '/admin/realms/:realm/identity-provider/instances/:id', {
-        realm : '@realm'
+    return $resource(authUrl + '/admin/realms/:realm/identity-provider/instances/:alias', {
+        realm : '@realm',
+        alias : '@alias'
     }, {
-        create : {
-            method : 'POST'
-        },
-        delete : {
-            method : 'DELETE'
-        },
         update: {
             method : 'PUT'
         }
@@ -1118,11 +1113,11 @@ module.factory('IdentityProvider', function($resource) {
 });
 
 module.factory('IdentityProviderExport', function($resource) {
-    var url = authUrl + '/admin/realms/:realm/identity-provider/instances/:id/export';
+    var url = authUrl + '/admin/realms/:realm/identity-provider/instances/:alias/export';
     return {
         url : function(parameters)
         {
-            return url.replace(':realm', parameters.realm).replace(':id', parameters.id);
+            return url.replace(':realm', parameters.realm).replace(':alias', parameters.alias);
         }
     }
 });
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 ab7cfa4..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
@@ -4,7 +4,6 @@
     <h2></h2>
     <div id="content">
         <h2 class="pull-left"><span>{{realm.realm}}</span> Identity Providers Settings</h2>
-        <p class="subtitle"><span class="required">*</span> Required fields</p>
 
         <form name="realmForm" novalidate class="form-horizontal">
             <fieldset>
@@ -18,7 +17,6 @@
                                     <div class="select-kc">
                                         <select ng-model="provider"
                                                 ng-options="p.name group by p.groupName for p in allProviders track by p.id"
-                                                ng-
                                                 data-ng-change="addProvider(provider); provider = null">
                                             <option value="" disabled selected>Add provider...</option>
                                         </select>
@@ -28,27 +26,22 @@
                         </tr>
                         <tr ng-show="configuredProviders.length > 0">
                             <th>Name</th>
-                            <th>Redirect URI</th>
+                            <th>Callback URI</th>
                         </tr>
                         </thead>
                         <tbody ng-show="configuredProviders.length > 0">
                         <tr ng-repeat="identityProvider in configuredProviders">
                             <td>
-                                <a href="#/realms/{{realm.realm}}/identity-provider-settings/provider/{{identityProvider.providerId}}/{{identityProvider.id}}">{{identityProvider.name}}</a>
+                                <a href="#/realms/{{realm.realm}}/identity-provider-settings/provider/{{identityProvider.providerId}}/{{identityProvider.alias}}">{{identityProvider.alias}}</a>
                             </td>
-                            <td ng-show="!changed">
-                                {{callbackUrl}}{{identityProvider.id}}
+                            <td>
+                                {{callbackUrl}}{{identityProvider.alias}}/endpoint
                             </td>
                         </tr>
                         </tbody>
                     </table>
                 </div>
             </fieldset>
-
-            <div class="pull-right form-actions">
-                <button type="submit" kc-reset data-ng-show="changed">Clear changes</button>
-                <button type="submit" kc-save class="primary" data-ng-show="changed">Save changes</button>
-            </div>
         </form>
     </div>
 </div>
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-identity-provider-export.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-identity-provider-export.html
index fc97a02..40d106d 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-identity-provider-export.html
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-identity-provider-export.html
@@ -5,10 +5,10 @@
     <div id="content">
         <ol class="breadcrumb">
             <li><a href="#/realms/{{realm.realm}}/identity-provider-settings">Identity Providers</a></li>
-            <li class="active"><a href="#/realms/{{realm.realm}}/identity-provider-settings/provider/{{identityProvider.providerId}}/{{identityProvider.id}}">{{identityProvider.name}} Provider</a></li>
-            <li class="active">{{identityProvider.name}} Provider Export</li>
+            <li class="active"><a href="#/realms/{{realm.realm}}/identity-provider-settings/provider/{{identityProvider.providerId}}/{{identityProvider.alias}}">{{identityProvider.alias}} Provider</a></li>
+            <li class="active">{{identityProvider.alias}} Provider Export</li>
         </ol>
-        <h2 class="pull-left">{{identityProvider.name}} Provider Export</h2>
+        <h2 class="pull-left">{{identityProvider.alias}} Provider Export</h2>
         <form class="form-horizontal" name="realmForm" novalidate>
             <fieldset class="border-top">
                 <div class="form-group">
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-identity-provider-oidc.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-identity-provider-oidc.html
index d33ffad..df99908 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-identity-provider-oidc.html
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-identity-provider-oidc.html
@@ -19,13 +19,6 @@
                         <span tooltip-placement="right" tooltip="The alias unique identifies an identity provider and it is also used to build the redirect uri." class="fa fa-info-circle"></span>
                     </div>
                     <div class="form-group clearfix">
-                        <label class="col-sm-2 control-label" for="name">Name <span class="required">*</span></label>
-                        <div class="col-sm-4">
-                            <input class="form-control" id="name" type="text" ng-model="identityProvider.name" required>
-                        </div>
-                        <span tooltip-placement="right" tooltip="The friendly name for this identity provider." class="fa fa-info-circle"></span>
-                    </div>
-                    <div class="form-group clearfix">
                         <label class="col-sm-2 control-label" for="authorizationUrl">Authorization Url <span class="required">*</span></label>
                         <div class="col-sm-4">
                             <input class="form-control" id="authorizationUrl" type="text" ng-model="identityProvider.config.authorizationUrl" required>
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-identity-provider-saml.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-identity-provider-saml.html
index 576f3d3..4e1d88c 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-identity-provider-saml.html
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-identity-provider-saml.html
@@ -5,26 +5,19 @@
         <div id="content">
             <ol class="breadcrumb">
                 <li><a href="#/realms/{{realm.realm}}/identity-provider-settings">Identity Providers</a></li>
-                <li class="active">{{identityProvider.name}} Provider Settings</li>
+                <li class="active">{{identityProvider.alias}} Provider Settings</li>
             </ol>
-            <h2 class="pull-left">{{identityProvider.name}} Provider Settings</h2>
+            <h2 class="pull-left">{{identityProvider.alias}} Provider Settings</h2>
             <p class="subtitle"><span class="required">*</span> Required fields</p>
             <form class="form-horizontal" name="realmForm" novalidate>
                 <fieldset>
                     <div class="form-group clearfix">
                         <label class="col-sm-2 control-label" for="identifier">Alias <span class="required">*</span></label>
                         <div class="col-sm-4">
-                            <input class="form-control" id="identifier" type="text" ng-model="identityProvider.id" data-ng-readonly="!newIdentityProvider" required>
+                            <input class="form-control" id="identifier" type="text" ng-model="identityProvider.alias" data-ng-readonly="!newIdentityProvider" required>
                         </div>
                         <span tooltip-placement="right" tooltip="The alias unique identifies an identity provider and it is also used to build the redirect uri." class="fa fa-info-circle"></span>
                     </div>
-                    <div class="form-group clearfix">
-                        <label class="col-sm-2 control-label" for="name">Name <span class="required">*</span></label>
-                        <div class="col-sm-4">
-                            <input class="form-control" id="name" type="text" ng-model="identityProvider.name" required>
-                        </div>
-                        <span tooltip-placement="right" tooltip="The friendly name for this identity provider." class="fa fa-info-circle"></span>
-                    </div>
                     <div class="form-group" data-ng-show="newIdentityProvider && !importFile">
                         <label class="col-sm-2 control-label" for="fromUrl">Import From Url</label>
                         <div class="col-sm-4">
@@ -52,17 +45,18 @@
                         <span tooltip-placement="right" tooltip="The Url that must be used to send authentication requests(SAML AuthnRequest)." class="fa fa-info-circle"></span>
                     </div>
                     <div class="form-group clearfix" data-ng-show="!importFile && !importUrl">
+                        <label class="col-sm-2 control-label" for="singleSignOnServiceUrl">Single Logout Service Url</label>
+                        <div class="col-sm-4">
+                            <input class="form-control" id="singleLogoutServiceUrl" type="text" ng-model="identityProvider.config.singleLogoutServiceUrl" required>
+                        </div>
+                        <span tooltip-placement="right" tooltip="The Url that must be used to send logout requests." class="fa fa-info-circle"></span>
+                    </div>
+                    <div class="form-group clearfix" data-ng-show="!importFile && !importUrl">
                         <label class="col-sm-2 control-label" for="nameIDPolicyFormat">NameID Policy Format</label>
                         <div class="col-sm-4">
-                            <select id="nameIDPolicyFormat" ng-model="identityProvider.config.nameIDPolicyFormat">
-                                <option value="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">Transient</option>
-                                <option value="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">Persistent</option>
-                                <option value="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">Email</option>
-                                <option value="urn:oasis:names:tc:SAML:2.0:nameid-format:kerberos">Kerberos</option>
-                                <option value="urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName">X.509 Subject Name</option>
-                                <option value="urn:oasis:names:tc:SAML:1.1:nameid-format:WindowsDomainQualifiedName">Windows Domain Qualified Name</option>
-                                <option value="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">Unspecified</option>
-                            </select>
+                            <select id="nameIDPolicyFormat" ng-model="identityProvider.config.nameIDPolicyFormat"
+                                    ng-options="nameFormat.format as nameFormat.name for nameFormat in nameIdFormats">
+                             </select>
                             <!-- <input class="form-control" id="nameIDPolicyFormat" type="text" ng-model="identityProvider.config.nameIDPolicyFormat"> -->
                         </div>
                         <span tooltip-placement="right" tooltip="Specifies the URI reference corresponding to a name identifier format. Defaults to urn:oasis:names:tc:SAML:2.0:nameid-format:persistent." class="fa fa-info-circle"></span>
@@ -77,35 +71,35 @@
                     <div class="form-group" data-ng-show="!importFile && !importUrl">
                         <label class="col-sm-2 control-label" for="wantAuthnRequestsSigned">Want AuthnRequests Signed</label>
                         <div class="col-sm-4">
-                            <input ng-model="identityProvider.config.wantAuthnRequestsSigned" id="wantAuthnRequestsSigned" onoffswitch />
+                            <input ng-model="identityProvider.config.wantAuthnRequestsSigned" id="wantAuthnRequestsSigned" value="'true'" onoffswitchmodel />
                         </div>
                         <span tooltip-placement="right" tooltip=" Indicates whether the identity provider expects signed a AuthnRequest." class="fa fa-info-circle"></span>
                     </div>
                     <div class="form-group" data-ng-show="!importFile && !importUrl">
                         <label class="col-sm-2 control-label" for="forceAuthn">Force Authentication</label>
                         <div class="col-sm-4">
-                            <input ng-model="identityProvider.config.forceAuthn" id="forceAuthn" onoffswitch />
+                            <input ng-model="identityProvider.config.forceAuthn" id="forceAuthn" value="'true'" onoffswitchmodel />
                         </div>
                         <span tooltip-placement="right" tooltip=" Indicates whether the identity provider must authenticate the presenter directly rather than rely on a previous security context." class="fa fa-info-circle"></span>
                     </div>
                     <div class="form-group" data-ng-show="!importFile && !importUrl">
                         <label class="col-sm-2 control-label" for="validateSignature">Validate Signature</label>
                         <div class="col-sm-4">
-                            <input ng-model="identityProvider.config.validateSignature" id="validateSignature" onoffswitch />
+                            <input ng-model="identityProvider.config.validateSignature" id="validateSignature" value="'true'" onoffswitchmodel />
                         </div>
                         <span tooltip-placement="right" tooltip="Enable/disable signature validation of SAML responses." class="fa fa-info-circle"></span>
                     </div>
                     <div class="form-group" data-ng-show="!importFile && !importUrl">
                         <label class="col-sm-2 control-label" for="postBindingResponse">HTTP-POST Binding Response</label>
                         <div class="col-sm-4">
-                            <input ng-model="identityProvider.config.postBindingResponse" id="postBindingResponse" onoffswitch />
+                            <input ng-model="identityProvider.config.postBindingResponse" id="postBindingResponse" value="'true'" onoffswitchmodel />
                         </div>
                         <span tooltip-placement="right" tooltip="Indicates whether the identity provider must respond to the AuthnRequest using HTTP-POST binding. If false, HTTP-REDIRECT binding will be used." class="fa fa-info-circle"></span>
                     </div>
                     <div class="form-group" data-ng-show="!importFile && !importUrl">
                         <label class="col-sm-2 control-label" for="postBindingAuthnRequest">HTTP-POST Binding for AuthnRequest</label>
                         <div class="col-sm-4">
-                            <input ng-model="identityProvider.config.postBindingAuthnRequest" id="postBindingAuthnRequest" onoffswitch />
+                            <input ng-model="identityProvider.config.postBindingAuthnRequest" id="postBindingAuthnRequest" value="'true'" onoffswitchmodel />
                         </div>
                         <span tooltip-placement="right" tooltip="Indicates whether the AuthnRequest must be sent using HTTP-POST binding. If false, HTTP-REDIRECT binding will be used." class="fa fa-info-circle"></span>
                     </div>
@@ -140,9 +134,9 @@
                 </fieldset>
 
                 <div class="pull-right form-actions">
-                    <a class="btn btn-lg btn-primary" href="#/realms/{{realm.realm}}/identity-provider-settings/provider/{{identityProvider.providerId}}/{{identityProvider.id}}/export" data-ng-show="!importFile && !newIdentityProvider">Export</a>
-                    <button kc-save data-ng-show="!importFile && !importUrl">Save</button>
-                    <button type="submit" data-ng-click="clearFileSelect()" data-ng-show="importFile || importUrl" class="btn btn-lg btn-default">Cancel</button>
+                    <a class="btn btn-lg btn-primary" href="#/realms/{{realm.realm}}/identity-provider-settings/provider/{{identityProvider.providerId}}/{{identityProvider.alias}}/export" data-ng-show="!importFile && !newIdentityProvider">Export</a>
+                    <button kc-save data-ng-show="changed">Save</button>
+                    <button type="submit" data-ng-click="cancel()" data-ng-show="changed" class="btn btn-lg btn-default">Cancel</button>
                     <button type="submit" data-ng-click="uploadFile()" data-ng-show="importFile" class="btn btn-lg btn-primary">Import</button>
                     <button type="submit" data-ng-click="importFrom()" data-ng-show="importUrl" class="btn btn-lg btn-primary">Import</button>
                     <button kc-delete data-ng-click="remove()" data-ng-show="!newIdentityProvider">Delete</button>
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-identity-provider-social.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-identity-provider-social.html
index d0aadec..d37e6a3 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-identity-provider-social.html
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-identity-provider-social.html
@@ -5,27 +5,13 @@
         <div id="content">
             <ol class="breadcrumb">
                 <li><a href="#/realms/{{realm.realm}}/identity-provider-settings">Social Providers</a></li>
-                <li class="active">{{identityProvider.name}} Settings</li>
+                <li class="active">{{identityProvider.alias}} Settings</li>
             </ol>
-            <h2 class="pull-left">{{identityProvider.name}} Provider Settings</h2>
+            <h2 class="pull-left">{{identityProvider.alias}} Provider Settings</h2>
             <p class="subtitle"><span class="required">*</span> Required fields</p>
             <form class="form-horizontal" name="realmForm" novalidate>
                 <fieldset>
                     <div class="form-group clearfix">
-                        <label class="col-sm-2 control-label" for="identifier">Alias <span class="required">*</span></label>
-                        <div class="col-sm-4">
-                            <input class="form-control" id="identifier" type="text" ng-model="identityProvider.id" required>
-                        </div>
-                        <span tooltip-placement="right" tooltip="The alias unique identifies an identity provider and it is also used to build the redirect uri." class="fa fa-info-circle"></span>
-                    </div>
-                    <div class="form-group clearfix">
-                        <label class="col-sm-2 control-label" for="name">Name <span class="required">*</span></label>
-                        <div class="col-sm-4">
-                            <input class="form-control" id="name" type="text" ng-model="identityProvider.name" required>
-                        </div>
-                        <span tooltip-placement="right" tooltip="The friendly name for this identity provider." class="fa fa-info-circle"></span>
-                    </div>
-                    <div class="form-group clearfix">
                         <label class="col-sm-2 control-label" for="clientId">Client ID <span class="required">*</span></label>
                         <div class="col-sm-4">
                             <input class="form-control" id="clientId" type="text" ng-model="identityProvider.config.clientId" required>
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-menu.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-menu.html
index 8415ba2..098f317 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-menu.html
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-menu.html
@@ -1,6 +1,6 @@
 <ul data-ng-hide="createRealm">
     <li data-ng-show="access.viewRealm" data-ng-class="((!path[2] ||
-    path[2] == 'social-settings' || path[2] == 'required-credentials'
+    path[2] == 'identity-provider-settings' || path[2] == 'required-credentials'
     || path[2] == 'login-settings'
     || path[2] == 'theme-settings'
     || path[2] == 'cache-settings'
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 e97b35a..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
@@ -75,7 +75,7 @@
             <div id="kc-social-providers">
                 <ul>
                     <#list social.providers as p>
-                        <li><a href="${p.loginUrl}" id="zocial-${p.id}" class="zocial ${p.providerId}"> <span class="text">${p.name}</span></a></li>
+                        <li><a href="${p.loginUrl}" id="zocial-${p.alias}" class="zocial ${p.providerId}"> <span class="text">${p.alias}</span></a></li>
                     </#list>
                 </ul>
             </div>
diff --git a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/IdentityProviderBean.java b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/IdentityProviderBean.java
index 9cbf469..8da7f4d 100755
--- a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/IdentityProviderBean.java
+++ b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/IdentityProviderBean.java
@@ -64,8 +64,8 @@ public class IdentityProviderBean {
     }
 
     private void addIdentityProvider(RealmModel realm, URI baseURI, IdentityProviderModel identityProvider) {
-        String loginUrl = Urls.identityProviderAuthnRequest(baseURI, identityProvider.getId(), realm.getName()).toString();
-        providers.add(new IdentityProvider(identityProvider.getId(), identityProvider.getProviderId(), identityProvider.getName(), loginUrl));
+        String loginUrl = Urls.identityProviderAuthnRequest(baseURI, identityProvider.getAlias(), realm.getName()).toString();
+        providers.add(new IdentityProvider(identityProvider.getAlias(), identityProvider.getProviderId(), loginUrl));
     }
 
     public List<IdentityProvider> getProviders() {
@@ -78,29 +78,19 @@ public class IdentityProviderBean {
 
     public static class IdentityProvider {
 
-        private final String id;
+        private final String alias;
         private final String providerId; // This refer to providerType (facebook, google, etc.)
-        private final String name;
         private final String loginUrl;
 
-        public IdentityProvider(String id, String providerId, String name, String loginUrl) {
-            this.id = id;
+        public IdentityProvider(String alias, String providerId,String loginUrl) {
+            this.alias = alias;
             this.providerId = providerId;
 
-            if (name == null) {
-                name = id;
-            }
-
-            this.name = name;
             this.loginUrl = loginUrl;
         }
 
-        public String getId() {
-            return id;
-        }
-
-        public String getName() {
-            return name;
+        public String getAlias() {
+            return alias;
         }
 
         public String getLoginUrl() {
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/IdentityProvidersResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/IdentityProvidersResource.java
index 9f8a581..c47ab06 100755
--- a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/IdentityProvidersResource.java
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/IdentityProvidersResource.java
@@ -20,10 +20,12 @@ public interface IdentityProvidersResource {
     IdentityProviderResource get(@PathParam("id") String id);
 
     @GET
+    @Path("instances")
     @Produces(MediaType.APPLICATION_JSON)
     List<IdentityProviderRepresentation> findAll();
 
     @POST
+    @Path("instances")
     @Consumes(MediaType.APPLICATION_JSON)
     void create(IdentityProviderRepresentation identityProvider);
 }
diff --git a/model/api/src/main/java/org/keycloak/models/entities/IdentityProviderEntity.java b/model/api/src/main/java/org/keycloak/models/entities/IdentityProviderEntity.java
old mode 100644
new mode 100755
index 3343b90..4effc07
--- a/model/api/src/main/java/org/keycloak/models/entities/IdentityProviderEntity.java
+++ b/model/api/src/main/java/org/keycloak/models/entities/IdentityProviderEntity.java
@@ -26,7 +26,7 @@ import java.util.Map;
 public class IdentityProviderEntity {
 
     private String internalId;
-    private String id;
+    private String alias;
     private String providerId;
     private String name;
     private boolean enabled;
@@ -92,12 +92,12 @@ public class IdentityProviderEntity {
         this.providerId = providerId;
     }
 
-    public String getId() {
-        return id;
+    public String getAlias() {
+        return alias;
     }
 
-    public void setId(String providerNonimalId) {
-        this.id = providerNonimalId;
+    public void setAlias(String alias) {
+        this.alias = alias;
     }
 
     public Map<String, String> getConfig() {
diff --git a/model/api/src/main/java/org/keycloak/models/IdentityProviderModel.java b/model/api/src/main/java/org/keycloak/models/IdentityProviderModel.java
old mode 100644
new mode 100755
index ca7063f..0328087
--- a/model/api/src/main/java/org/keycloak/models/IdentityProviderModel.java
+++ b/model/api/src/main/java/org/keycloak/models/IdentityProviderModel.java
@@ -33,7 +33,7 @@ public class IdentityProviderModel {
     /**
      * <p>An user-defined identifier to unique identify an identity provider instance.</p>
      */
-    private String id;
+    private String alias;
 
     /**
      * <p>An identifier used to reference a specific identity provider implementation. The value of this field is the same
@@ -41,11 +41,6 @@ public class IdentityProviderModel {
      */
     private String providerId;
 
-    /**
-     * <p>An user-defined friendly name for an identity provider instance.</p>
-     */
-    private String name;
-
     private boolean enabled;
 
     private boolean updateProfileFirstLogin = true;
@@ -69,8 +64,7 @@ public class IdentityProviderModel {
     public IdentityProviderModel(IdentityProviderModel model) {
         this.internalId = model.getInternalId();
         this.providerId = model.getProviderId();
-        this.id = model.getId();
-        this.name = model.getName();
+        this.alias = model.getAlias();
         this.config = new HashMap<String, String>(model.getConfig());
         this.enabled = model.isEnabled();
         this.updateProfileFirstLogin = model.isUpdateProfileFirstLogin();
@@ -86,12 +80,12 @@ public class IdentityProviderModel {
         this.internalId = internalId;
     }
 
-    public String getId() {
-        return this.id;
+    public String getAlias() {
+        return this.alias;
     }
 
-    public void setId(String id) {
-        this.id = id;
+    public void setAlias(String id) {
+        this.alias = id;
     }
 
     public String getProviderId() {
@@ -102,14 +96,6 @@ public class IdentityProviderModel {
         this.providerId = providerId;
     }
 
-    public String getName() {
-        return this.name;
-    }
-
-    public void setName(String name) {
-        this.name = name;
-    }
-
     public boolean isEnabled() {
         return this.enabled;
     }
diff --git a/model/api/src/main/java/org/keycloak/models/RealmModel.java b/model/api/src/main/java/org/keycloak/models/RealmModel.java
index 7308565..f74d54c 100755
--- a/model/api/src/main/java/org/keycloak/models/RealmModel.java
+++ b/model/api/src/main/java/org/keycloak/models/RealmModel.java
@@ -185,9 +185,9 @@ public interface RealmModel extends RoleContainerModel {
     void setSmtpConfig(Map<String, String> smtpConfig);
 
     List<IdentityProviderModel> getIdentityProviders();
-    IdentityProviderModel getIdentityProviderById(String identityProviderId);
+    IdentityProviderModel getIdentityProviderByAlias(String alias);
     void addIdentityProvider(IdentityProviderModel identityProvider);
-    void removeIdentityProviderById(String providerId);
+    void removeIdentityProviderByAlias(String alias);
     void updateIdentityProvider(IdentityProviderModel identityProvider);
 
     List<UserFederationProviderModel> getUserFederationProviders();
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 5574bc1..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
@@ -353,8 +353,7 @@ public class ModelToRepresentation {
 
         providerRep.setInternalId(identityProviderModel.getInternalId());
         providerRep.setProviderId(identityProviderModel.getProviderId());
-        providerRep.setId(identityProviderModel.getId());
-        providerRep.setName(identityProviderModel.getName());
+        providerRep.setAlias(identityProviderModel.getAlias());
         providerRep.setEnabled(identityProviderModel.isEnabled());
         providerRep.setStoreToken(identityProviderModel.isStoreToken());
         providerRep.setUpdateProfileFirstLogin(identityProviderModel.isUpdateProfileFirstLogin());
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 41f2ad4..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
@@ -272,9 +272,8 @@ public class RepresentationToModel {
                         String secret = rep.getSocialProviders().get(k.replace(".key", ".secret"));
 
                         IdentityProviderRepresentation identityProvider = new IdentityProviderRepresentation();
-                        identityProvider.setId(providerId);
+                        identityProvider.setAlias(providerId);
                         identityProvider.setProviderId(providerId);
-                        identityProvider.setName(providerId);
                         identityProvider.setEnabled(true);
                         identityProvider.setUpdateProfileFirstLogin(updateProfileFirstLogin);
 
@@ -850,9 +849,8 @@ public class RepresentationToModel {
         IdentityProviderModel identityProviderModel = new IdentityProviderModel();
 
         identityProviderModel.setInternalId(representation.getInternalId());
-        identityProviderModel.setId(representation.getId());
+        identityProviderModel.setAlias(representation.getAlias());
         identityProviderModel.setProviderId(representation.getProviderId());
-        identityProviderModel.setName(representation.getName());
         identityProviderModel.setEnabled(representation.isEnabled());
         identityProviderModel.setUpdateProfileFirstLogin(representation.isUpdateProfileFirstLogin());
         identityProviderModel.setAuthenticateByDefault(representation.isAuthenticateByDefault());
diff --git a/model/file/src/main/java/org/keycloak/models/file/adapter/RealmAdapter.java b/model/file/src/main/java/org/keycloak/models/file/adapter/RealmAdapter.java
index 202cb8e..5894784 100755
--- a/model/file/src/main/java/org/keycloak/models/file/adapter/RealmAdapter.java
+++ b/model/file/src/main/java/org/keycloak/models/file/adapter/RealmAdapter.java
@@ -871,9 +871,9 @@ public class RealmAdapter implements RealmModel {
     }
 
     @Override
-    public IdentityProviderModel getIdentityProviderById(String identityProviderId) {
+    public IdentityProviderModel getIdentityProviderByAlias(String alias) {
         for (IdentityProviderModel identityProviderModel : getIdentityProviders()) {
-            if (identityProviderModel.getId().equals(identityProviderId)) {
+            if (identityProviderModel.getAlias().equals(alias)) {
                 return identityProviderModel;
             }
         }
@@ -883,15 +883,15 @@ public class RealmAdapter implements RealmModel {
 
     @Override
     public void addIdentityProvider(IdentityProviderModel identityProvider) {
-        if (identityProvider.getId() == null) throw new NullPointerException("identityProvider.getId() == null");
+        if (identityProvider.getAlias() == null) throw new NullPointerException("identityProvider.getAlias() == null");
         if (identityProvider.getInternalId() == null) identityProvider.setInternalId(KeycloakModelUtils.generateId());
         allIdProviders.put(identityProvider.getInternalId(), identityProvider);
     }
 
     @Override
-    public void removeIdentityProviderById(String providerId) {
+    public void removeIdentityProviderByAlias(String alias) {
         for (IdentityProviderModel provider : getIdentityProviders()) {
-            if (provider.getId().equals(providerId)) {
+            if (provider.getAlias().equals(alias)) {
                 allIdProviders.remove(provider.getInternalId());
                 break;
             }
@@ -900,7 +900,7 @@ public class RealmAdapter implements RealmModel {
 
     @Override
     public void updateIdentityProvider(IdentityProviderModel identityProvider) {
-        removeIdentityProviderById(identityProvider.getId());
+        removeIdentityProviderByAlias(identityProvider.getAlias());
         addIdentityProvider(identityProvider);
     }
 
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java
index 77b84e6..16c1d34 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java
@@ -643,9 +643,9 @@ public class RealmAdapter implements RealmModel {
     }
 
     @Override
-    public IdentityProviderModel getIdentityProviderById(String identityProviderId) {
+    public IdentityProviderModel getIdentityProviderByAlias(String alias) {
         for (IdentityProviderModel identityProviderModel : getIdentityProviders()) {
-            if (identityProviderModel.getId().equals(identityProviderId)) {
+            if (identityProviderModel.getAlias().equals(alias)) {
                 return identityProviderModel;
             }
         }
@@ -666,9 +666,9 @@ public class RealmAdapter implements RealmModel {
     }
 
     @Override
-    public void removeIdentityProviderById(String providerId) {
+    public void removeIdentityProviderByAlias(String alias) {
         getDelegateForUpdate();
-        updated.removeIdentityProviderById(providerId);
+        updated.removeIdentityProviderByAlias(alias);
     }
 
     @Override
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java
index 1d2cb05..bf0fefc 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java
@@ -317,7 +317,7 @@ public abstract class ClientAdapter implements ClientModel {
             boolean toRemove = true;
 
             for (ClientIdentityProviderMappingModel model : identityProviders) {
-                if (model.getIdentityProvider().equals(identityProvider.getId())) {
+                if (model.getIdentityProvider().equals(identityProvider.getAlias())) {
                     toRemove = false;
                     break;
                 }
@@ -326,7 +326,7 @@ public abstract class ClientAdapter implements ClientModel {
             if (toRemove) {
                 remove.add(entity);
             } else {
-                already.add(entity.getIdentityProvider().getId());
+                already.add(entity.getIdentityProvider().getAlias());
             }
         }
         for (ClientIdentityProviderMappingEntity entity : remove) {
@@ -342,14 +342,14 @@ public abstract class ClientAdapter implements ClientModel {
                 entities.add(mappingEntity);
             } else {
                 for (ClientIdentityProviderMappingEntity entity : entities) {
-                    if (entity.getIdentityProvider().getId().equals(model.getIdentityProvider())) {
+                    if (entity.getIdentityProvider().getAlias().equals(model.getIdentityProvider())) {
                         mappingEntity = entity;
                         break;
                     }
                 }
             }
 
-            TypedQuery<IdentityProviderEntity> query = em.createNamedQuery("findIdentityProviderById", IdentityProviderEntity.class).setParameter("id", model.getIdentityProvider());
+            TypedQuery<IdentityProviderEntity> query = em.createNamedQuery("findIdentityProviderByAlias", IdentityProviderEntity.class).setParameter("alias", model.getIdentityProvider());
             IdentityProviderEntity identityProviderEntity = query.getSingleResult();
 
             mappingEntity.setIdentityProvider(identityProviderEntity);
@@ -368,7 +368,7 @@ public abstract class ClientAdapter implements ClientModel {
         for (ClientIdentityProviderMappingEntity entity : this.entity.getIdentityProviders()) {
             ClientIdentityProviderMappingModel model = new ClientIdentityProviderMappingModel();
 
-            model.setIdentityProvider(entity.getIdentityProvider().getId());
+            model.setIdentityProvider(entity.getIdentityProvider().getAlias());
             model.setRetrieveToken(entity.isRetrieveToken());
 
             models.add(model);
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientIdentityProviderMappingEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientIdentityProviderMappingEntity.java
index fe8485d..e760b3c 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientIdentityProviderMappingEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientIdentityProviderMappingEntity.java
@@ -83,7 +83,7 @@ public class ClientIdentityProviderMappingEntity {
 
             Key key = (Key) o;
 
-            if (identityProvider != null ? !identityProvider.getId().equals(key.identityProvider.getId()) : key.identityProvider != null)
+            if (identityProvider != null ? !identityProvider.getAlias().equals(key.identityProvider.getAlias()) : key.identityProvider != null)
                 return false;
             if (client != null ? !client.getId().equals(key.client != null ? key.client.getId() : null) : key.client != null) return false;
 
@@ -105,7 +105,7 @@ public class ClientIdentityProviderMappingEntity {
 
         ClientIdentityProviderMappingEntity key = (ClientIdentityProviderMappingEntity) o;
 
-        if (identityProvider != null ? !identityProvider.getId().equals(key.identityProvider.getId()) : key.identityProvider != null)
+        if (identityProvider != null ? !identityProvider.getAlias().equals(key.identityProvider.getAlias()) : key.identityProvider != null)
             return false;
         if (client != null ? !client.getId().equals(key.client != null ? key.client.getId() : null) : key.client != null) return false;
 
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/IdentityProviderEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/IdentityProviderEntity.java
index cf85fad..d2e159a 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/IdentityProviderEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/IdentityProviderEntity.java
@@ -20,7 +20,7 @@ import java.util.Map;
 @Entity
 @Table(name="IDENTITY_PROVIDER")
 @NamedQueries({
-        @NamedQuery(name="findIdentityProviderById", query="select identityProvider from IdentityProviderEntity identityProvider where identityProvider.id = :id")
+        @NamedQuery(name="findIdentityProviderByAlias", query="select identityProvider from IdentityProviderEntity identityProvider where identityProvider.alias = :alias")
 })
 public class IdentityProviderEntity {
 
@@ -35,11 +35,8 @@ public class IdentityProviderEntity {
     @Column(name="PROVIDER_ID")
     private String providerId;
 
-    @Column(name="PROVIDER_NONIMAL_ID")
-    private String id;
-
-    @Column(name="PROVIDER_NAME")
-    private String name;
+    @Column(name="PROVIDER_ALIAS")
+    private String alias;
 
     @Column(name="ENABLED")
     private boolean enabled;
@@ -83,20 +80,12 @@ public class IdentityProviderEntity {
         this.realm = realm;
     }
 
-    public String getId() {
-        return this.id;
-    }
-
-    public void setId(String id) {
-        this.id = id;
-    }
-
-    public String getName() {
-        return this.name;
+    public String getAlias() {
+        return this.alias;
     }
 
-    public void setName(String name) {
-        this.name = name;
+    public void setAlias(String alias) {
+        this.alias = alias;
     }
 
     public boolean 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 38178c4..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
@@ -1160,9 +1160,8 @@ public class RealmAdapter implements RealmModel {
             IdentityProviderModel identityProviderModel = new IdentityProviderModel();
 
             identityProviderModel.setProviderId(entity.getProviderId());
-            identityProviderModel.setId(entity.getId());
+            identityProviderModel.setAlias(entity.getAlias());
             identityProviderModel.setInternalId(entity.getInternalId());
-            identityProviderModel.setName(entity.getName());
             identityProviderModel.setConfig(entity.getConfig());
             identityProviderModel.setEnabled(entity.isEnabled());
             identityProviderModel.setUpdateProfileFirstLogin(entity.isUpdateProfileFirstLogin());
@@ -1176,9 +1175,9 @@ public class RealmAdapter implements RealmModel {
     }
 
     @Override
-    public IdentityProviderModel getIdentityProviderById(String identityProviderId) {
+    public IdentityProviderModel getIdentityProviderByAlias(String alias) {
         for (IdentityProviderModel identityProviderModel : getIdentityProviders()) {
-            if (identityProviderModel.getId().equals(identityProviderId)) {
+            if (identityProviderModel.getAlias().equals(alias)) {
                 return identityProviderModel;
             }
         }
@@ -1191,9 +1190,8 @@ public class RealmAdapter implements RealmModel {
         IdentityProviderEntity entity = new IdentityProviderEntity();
 
         entity.setInternalId(KeycloakModelUtils.generateId());
-        entity.setId(identityProvider.getId());
+        entity.setAlias(identityProvider.getAlias());
         entity.setProviderId(identityProvider.getProviderId());
-        entity.setName(identityProvider.getName());
         entity.setEnabled(identityProvider.isEnabled());
         entity.setStoreToken(identityProvider.isStoreToken());
         entity.setUpdateProfileFirstLogin(identityProvider.isUpdateProfileFirstLogin());
@@ -1207,9 +1205,9 @@ public class RealmAdapter implements RealmModel {
     }
 
     @Override
-    public void removeIdentityProviderById(String providerId) {
+    public void removeIdentityProviderByAlias(String alias) {
         for (IdentityProviderEntity entity : realm.getIdentityProviders()) {
-            if (entity.getId().equals(providerId)) {
+            if (entity.getAlias().equals(alias)) {
                 em.remove(entity);
                 em.flush();
             }
@@ -1220,8 +1218,7 @@ public class RealmAdapter implements RealmModel {
     public void updateIdentityProvider(IdentityProviderModel identityProvider) {
         for (IdentityProviderEntity entity : this.realm.getIdentityProviders()) {
             if (entity.getInternalId().equals(identityProvider.getInternalId())) {
-                entity.setId(identityProvider.getId());
-                entity.setName(identityProvider.getName());
+                entity.setAlias(identityProvider.getAlias());
                 entity.setEnabled(identityProvider.isEnabled());
                 entity.setUpdateProfileFirstLogin(identityProvider.isUpdateProfileFirstLogin());
                 entity.setAuthenticateByDefault(identityProvider.isAuthenticateByDefault());
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 bf0ea87..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
@@ -833,9 +833,8 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
             IdentityProviderModel identityProviderModel = new IdentityProviderModel();
 
             identityProviderModel.setProviderId(entity.getProviderId());
-            identityProviderModel.setId(entity.getId());
+            identityProviderModel.setAlias(entity.getAlias());
             identityProviderModel.setInternalId(entity.getInternalId());
-            identityProviderModel.setName(entity.getName());
             identityProviderModel.setConfig(entity.getConfig());
             identityProviderModel.setEnabled(entity.isEnabled());
             identityProviderModel.setUpdateProfileFirstLogin(entity.isUpdateProfileFirstLogin());
@@ -849,9 +848,9 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
     }
 
     @Override
-    public IdentityProviderModel getIdentityProviderById(String identityProviderId) {
+    public IdentityProviderModel getIdentityProviderByAlias(String alias) {
         for (IdentityProviderModel identityProviderModel : getIdentityProviders()) {
-            if (identityProviderModel.getId().equals(identityProviderId)) {
+            if (identityProviderModel.getAlias().equals(alias)) {
                 return identityProviderModel;
             }
         }
@@ -864,9 +863,8 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
         IdentityProviderEntity entity = new IdentityProviderEntity();
 
         entity.setInternalId(KeycloakModelUtils.generateId());
-        entity.setId(identityProvider.getId());
+        entity.setAlias(identityProvider.getAlias());
         entity.setProviderId(identityProvider.getProviderId());
-        entity.setName(identityProvider.getName());
         entity.setEnabled(identityProvider.isEnabled());
         entity.setUpdateProfileFirstLogin(identityProvider.isUpdateProfileFirstLogin());
         entity.setStoreToken(identityProvider.isStoreToken());
@@ -878,10 +876,10 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
     }
 
     @Override
-    public void removeIdentityProviderById(String providerId) {
+    public void removeIdentityProviderByAlias(String alias) {
         IdentityProviderEntity toRemove;
         for (IdentityProviderEntity entity : realm.getIdentityProviders()) {
-            if (entity.getId().equals(providerId)) {
+            if (entity.getAlias().equals(alias)) {
                 realm.getIdentityProviders().remove(entity);
                 updateRealm();
                 break;
@@ -893,8 +891,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
     public void updateIdentityProvider(IdentityProviderModel identityProvider) {
         for (IdentityProviderEntity entity : this.realm.getIdentityProviders()) {
             if (entity.getInternalId().equals(identityProvider.getInternalId())) {
-                entity.setId(identityProvider.getId());
-                entity.setName(identityProvider.getName());
+                entity.setAlias(identityProvider.getAlias());
                 entity.setEnabled(identityProvider.isEnabled());
                 entity.setUpdateProfileFirstLogin(identityProvider.isUpdateProfileFirstLogin());
                 entity.setAuthenticateByDefault(identityProvider.isAuthenticateByDefault());
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SALM2LoginResponseBuilder.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SALM2LoginResponseBuilder.java
index e5d12e8..cd494ee 100755
--- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SALM2LoginResponseBuilder.java
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SALM2LoginResponseBuilder.java
@@ -43,8 +43,14 @@ public class SALM2LoginResponseBuilder {
     protected String requestID;
     protected String authMethod;
     protected String requestIssuer;
+    protected String sessionIndex;
 
 
+    public SALM2LoginResponseBuilder sessionIndex(String sessionIndex) {
+        this.sessionIndex = sessionIndex;
+        return this;
+    }
+
     public SALM2LoginResponseBuilder destination(String destination) {
         this.destination = destination;
         return this;
@@ -135,8 +141,8 @@ public class SALM2LoginResponseBuilder {
 
             AuthnStatementType authnStatement = StatementUtil.createAuthnStatement(XMLTimeUtil.getIssueInstant(),
                     authContextRef);
-
-            authnStatement.setSessionIndex(assertion.getID());
+            if (sessionIndex != null) authnStatement.setSessionIndex(sessionIndex);
+            else authnStatement.setSessionIndex(assertion.getID());
 
             assertion.addStatement(authnStatement);
         }
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SAML2LogoutRequestBuilder.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SAML2LogoutRequestBuilder.java
index 1d76e2f..5cf301f 100755
--- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SAML2LogoutRequestBuilder.java
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SAML2LogoutRequestBuilder.java
@@ -19,6 +19,7 @@ import java.net.URI;
 public class SAML2LogoutRequestBuilder extends SAML2BindingBuilder<SAML2LogoutRequestBuilder> {
     protected String userPrincipal;
     protected String userPrincipalFormat;
+    protected String sessionIndex;
 
     public SAML2LogoutRequestBuilder userPrincipal(String nameID, String nameIDformat) {
         this.userPrincipal = nameID;
@@ -26,6 +27,11 @@ public class SAML2LogoutRequestBuilder extends SAML2BindingBuilder<SAML2LogoutRe
         return this;
     }
 
+    public SAML2LogoutRequestBuilder sessionIndex(String index) {
+        this.sessionIndex = index;
+        return this;
+    }
+
     public RedirectBindingBuilder redirectBinding()  throws ConfigurationException, ProcessingException, ParsingException {
         Document samlResponseDocument = buildDocument();
         return new RedirectBindingBuilder(samlResponseDocument);
@@ -58,7 +64,7 @@ public class SAML2LogoutRequestBuilder extends SAML2BindingBuilder<SAML2LogoutRe
             issuerID.setValue(issuer);
             lort.setIssuer(issuerID);
         }
-
+        if (sessionIndex != null) lort.addSessionIndex(sessionIndex);
 
         long assertionValidity = PicketLinkCoreSTS.instance().getConfiguration().getIssuedTokenTimeout();
 
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 4423686..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
@@ -4,6 +4,7 @@ import org.jboss.logging.Logger;
 import org.jboss.resteasy.client.ClientRequest;
 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.ClientModel;
 import org.keycloak.models.ClientSessionModel;
@@ -94,6 +95,8 @@ public class SamlProtocol implements LoginProtocol {
 
     protected HttpHeaders headers;
 
+    protected EventBuilder event;
+
 
     @Override
     public SamlProtocol setSession(KeycloakSession session) {
@@ -120,6 +123,13 @@ public class SamlProtocol implements LoginProtocol {
     }
 
     @Override
+    public SamlProtocol setEventBuilder(EventBuilder event) {
+        this.event = event;
+        return this;
+    }
+
+
+    @Override
     public Response cancelLogin(ClientSessionModel clientSession) {
         return getErrorResponse(clientSession, JBossSAMLURIConstants.STATUS_REQUEST_DENIED.get());
     }
@@ -262,6 +272,7 @@ public class SamlProtocol implements LoginProtocol {
         builder.requestID(requestID)
                .destination(redirectUri)
                .issuer(responseIssuer)
+               .sessionIndex(clientSession.getId())
                .requestIssuer(clientSession.getClient().getClientId())
                .nameIdentifier(nameIdFormat, nameId)
                .authMethod(JBossSAMLURIConstants.AC_UNSPECIFIED.get());
@@ -350,10 +361,6 @@ public class SamlProtocol implements LoginProtocol {
         return "true".equals(client.getAttribute(SAML_AUTHNSTATEMENT));
     }
 
-    public static boolean multivaluedRoles(ClientModel client) {
-        return "true".equals(client.getAttribute(SAML_MULTIVALUED_ROLES));
-    }
-
     public static SignatureAlgorithm getSignatureAlgorithm(ClientModel client) {
         String alg = client.getAttribute(SAML_SIGNATURE_ALGORITHM);
         if (alg != null) {
@@ -457,10 +464,13 @@ public class SamlProtocol implements LoginProtocol {
     @Override
     public Response finishLogout(UserSessionModel userSession) {
         logger.debug("finishLogout");
+        String logoutBindingUri = userSession.getNote(SAML_LOGOUT_BINDING_URI);
+        String logoutRelayState = userSession.getNote(SAML_LOGOUT_RELAY_STATE);
         SAML2LogoutResponseBuilder builder = new SAML2LogoutResponseBuilder();
         builder.logoutRequestID(userSession.getNote(SAML_LOGOUT_REQUEST_ID));
-        builder.destination(userSession.getNote(SAML_LOGOUT_ISSUER));
+        builder.destination(logoutBindingUri);
         builder.issuer(getResponseIssuer(realm));
+        builder.relayState(logoutRelayState);
         String signingAlgorithm = userSession.getNote(SAML_LOGOUT_SIGNATURE_ALGORITHM);
         if (signingAlgorithm != null) {
             SignatureAlgorithm algorithm = SignatureAlgorithm.valueOf(signingAlgorithm);
@@ -471,9 +481,9 @@ public class SamlProtocol implements LoginProtocol {
 
         try {
             if (isLogoutPostBindingForInitiator(userSession)) {
-                return builder.postBinding().response(userSession.getNote(SAML_LOGOUT_BINDING_URI));
+                return builder.postBinding().response(logoutBindingUri);
             } else {
-                return builder.redirectBinding().response(userSession.getNote(SAML_LOGOUT_BINDING_URI));
+                return builder.redirectBinding().response(logoutBindingUri);
             }
         } catch (ConfigurationException e) {
             throw new RuntimeException(e);
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocolUtils.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocolUtils.java
index 7ddabe9..0e8c3c2 100755
--- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocolUtils.java
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocolUtils.java
@@ -3,11 +3,17 @@ package org.keycloak.protocol.saml;
 import org.keycloak.VerificationException;
 import org.keycloak.models.ClientModel;
 import org.keycloak.util.PemUtils;
+import org.picketlink.common.constants.GeneralConstants;
 import org.picketlink.common.exceptions.ProcessingException;
 import org.picketlink.identity.federation.api.saml.v2.sig.SAML2Signature;
+import org.picketlink.identity.federation.web.util.RedirectBindingUtil;
 import org.w3c.dom.Document;
 
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
 import java.security.PublicKey;
+import java.security.Signature;
 import java.security.cert.Certificate;
 
 /**
@@ -20,8 +26,12 @@ public class SamlProtocolUtils {
         if (!"true".equals(client.getAttribute(SamlProtocol.SAML_CLIENT_SIGNATURE_ATTRIBUTE))) {
             return;
         }
-        SAML2Signature saml2Signature = new SAML2Signature();
         PublicKey publicKey = getSignatureValidationKey(client);
+        verifyDocumentSignature(document, publicKey);
+    }
+
+    public static void verifyDocumentSignature(Document document, PublicKey publicKey) throws VerificationException {
+        SAML2Signature saml2Signature = new SAML2Signature();
         try {
             if (!saml2Signature.validate(document, publicKey)) {
                 throw new VerificationException("Invalid signature on document");
@@ -51,5 +61,43 @@ public class SamlProtocolUtils {
         return cert.getPublicKey();
     }
 
+    public static void verifyRedirectSignature(PublicKey publicKey, UriInfo uriInformation) throws VerificationException {
+        MultivaluedMap<String, String> encodedParams = uriInformation.getQueryParameters(false);
+        String request = encodedParams.getFirst(GeneralConstants.SAML_REQUEST_KEY);
+        String algorithm = encodedParams.getFirst(GeneralConstants.SAML_SIG_ALG_REQUEST_KEY);
+        String signature = encodedParams.getFirst(GeneralConstants.SAML_SIGNATURE_REQUEST_KEY);
+        String decodedAlgorithm = uriInformation.getQueryParameters(true).getFirst(GeneralConstants.SAML_SIG_ALG_REQUEST_KEY);
+
+        if (request == null) throw new VerificationException("SAMLRequest as null");
+        if (algorithm == null) throw new VerificationException("SigAlg as null");
+        if (signature == null) throw new VerificationException("Signature as null");
+
+        // Shibboleth doesn't sign the document for redirect binding.
+        // todo maybe a flag?
+
+
+        UriBuilder builder = UriBuilder.fromPath("/")
+                .queryParam(GeneralConstants.SAML_REQUEST_KEY, request);
+        if (encodedParams.containsKey(GeneralConstants.RELAY_STATE)) {
+            builder.queryParam(GeneralConstants.RELAY_STATE, encodedParams.getFirst(GeneralConstants.RELAY_STATE));
+        }
+        builder.queryParam(GeneralConstants.SAML_SIG_ALG_REQUEST_KEY, algorithm);
+        String rawQuery = builder.build().getRawQuery();
+
+        try {
+            byte[] decodedSignature = RedirectBindingUtil.urlBase64Decode(signature);
+
+            SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.getFromXmlMethod(decodedAlgorithm);
+            Signature validator = signatureAlgorithm.createSignature(); // todo plugin signature alg
+            validator.initVerify(publicKey);
+            validator.update(rawQuery.getBytes("UTF-8"));
+            if (!validator.verify(decodedSignature)) {
+                throw new VerificationException("Invalid query param signature");
+            }
+        } catch (Exception e) {
+            throw new VerificationException(e);
+        }
+    }
+
 
 }
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java
index 3e7cd2f..3aa016c 100755
--- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java
@@ -358,7 +358,6 @@ public class SamlService {
                 if (relayState != null) userSession.setNote(SamlProtocol.SAML_LOGOUT_RELAY_STATE, relayState);
                 userSession.setNote(SamlProtocol.SAML_LOGOUT_REQUEST_ID, logoutRequest.getID());
                 userSession.setNote(SamlProtocol.SAML_LOGOUT_BINDING, logoutBinding);
-                userSession.setNote(SamlProtocol.SAML_LOGOUT_ISSUER, logoutRequest.getIssuer().getValue());
                 userSession.setNote(AuthenticationManager.KEYCLOAK_LOGOUT_PROTOCOL, SamlProtocol.LOGIN_PROTOCOL);
                 // remove client from logout requests
                 for (ClientSessionModel clientSession : userSession.getClientSessions()) {
@@ -446,46 +445,11 @@ public class SamlService {
             if (!"true".equals(client.getAttribute("saml.client.signature"))) {
                 return;
             }
-            MultivaluedMap<String, String> encodedParams = uriInfo.getQueryParameters(false);
-            String request = encodedParams.getFirst(GeneralConstants.SAML_REQUEST_KEY);
-            String algorithm = encodedParams.getFirst(GeneralConstants.SAML_SIG_ALG_REQUEST_KEY);
-            String signature = encodedParams.getFirst(GeneralConstants.SAML_SIGNATURE_REQUEST_KEY);
-
-            if (request == null) throw new VerificationException("SAMLRequest as null");
-            if (algorithm == null) throw new VerificationException("SigAlg as null");
-            if (signature == null) throw new VerificationException("Signature as null");
-
-            // Shibboleth doesn't sign the document for redirect binding.
-            // todo maybe a flag?
-            // SamlProtocolUtils.verifyDocumentSignature(client, documentHolder.getSamlDocument());
-
             PublicKey publicKey = SamlProtocolUtils.getSignatureValidationKey(client);
+            SamlProtocolUtils.verifyRedirectSignature(publicKey, uriInfo);
+        }
 
 
-            UriBuilder builder = UriBuilder.fromPath("/")
-                    .queryParam(GeneralConstants.SAML_REQUEST_KEY, request);
-            if (encodedParams.containsKey(GeneralConstants.RELAY_STATE)) {
-                builder.queryParam(GeneralConstants.RELAY_STATE, encodedParams.getFirst(GeneralConstants.RELAY_STATE));
-            }
-            builder.queryParam(GeneralConstants.SAML_SIG_ALG_REQUEST_KEY, algorithm);
-            String rawQuery = builder.build().getRawQuery();
-
-            try {
-                byte[] decodedSignature = RedirectBindingUtil.urlBase64Decode(signature);
-
-                SignatureAlgorithm signatureAlgorithm = SamlProtocol.getSignatureAlgorithm(client);
-                Signature validator = signatureAlgorithm.createSignature(); // todo plugin signature alg
-                validator.initVerify(publicKey);
-                validator.update(rawQuery.getBytes("UTF-8"));
-                if (!validator.verify(decodedSignature)) {
-                    throw new VerificationException("Invalid query param signature");
-                }
-            } catch (Exception e) {
-                throw new VerificationException(e);
-            }
-
-
-        }
 
         @Override
         protected SAMLDocumentHolder extractRequestDocument(String samlRequest) {
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SignatureAlgorithm.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SignatureAlgorithm.java
index 6e9f47e..e169201 100755
--- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SignatureAlgorithm.java
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SignatureAlgorithm.java
@@ -1,6 +1,8 @@
 package org.keycloak.protocol.saml;
 
 import java.security.Signature;
+import java.util.HashMap;
+import java.util.Map;
 
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -16,6 +18,29 @@ public enum SignatureAlgorithm {
     private final String xmlSignatureDigestMethod;
     private final String javaSignatureAlgorithm;
 
+    private static final Map<String, SignatureAlgorithm> signatureMethodMap = new HashMap<>();
+    private static final Map<String, SignatureAlgorithm> signatureDigestMethodMap = new HashMap<>();
+
+    static {
+        signatureMethodMap.put(RSA_SHA1.getXmlSignatureMethod(), RSA_SHA1);
+        signatureMethodMap.put(RSA_SHA256.getXmlSignatureMethod(), RSA_SHA256);
+        signatureMethodMap.put(RSA_SHA512.getXmlSignatureMethod(), RSA_SHA512);
+        signatureMethodMap.put(DSA_SHA1.getXmlSignatureMethod(), DSA_SHA1);
+
+        signatureDigestMethodMap.put(RSA_SHA1.getXmlSignatureDigestMethod(), RSA_SHA1);
+        signatureDigestMethodMap.put(RSA_SHA256.getXmlSignatureDigestMethod(), RSA_SHA256);
+        signatureDigestMethodMap.put(RSA_SHA512.getXmlSignatureDigestMethod(), RSA_SHA512);
+        signatureDigestMethodMap.put(DSA_SHA1.getXmlSignatureDigestMethod(), DSA_SHA1);
+    }
+
+    public static SignatureAlgorithm getFromXmlMethod(String xml) {
+        return signatureMethodMap.get(xml);
+    }
+
+    public static SignatureAlgorithm getFromXmlDigest(String xml) {
+        return signatureDigestMethodMap.get(xml);
+    }
+
     SignatureAlgorithm(String xmlSignatureMethod, String xmlSignatureDigestMethod, String javaSignatureAlgorithm) {
         this.xmlSignatureMethod = xmlSignatureMethod;
         this.xmlSignatureDigestMethod = xmlSignatureDigestMethod;
diff --git a/services/src/main/java/org/keycloak/protocol/LoginProtocol.java b/services/src/main/java/org/keycloak/protocol/LoginProtocol.java
index 0290771..be1711b 100755
--- a/services/src/main/java/org/keycloak/protocol/LoginProtocol.java
+++ b/services/src/main/java/org/keycloak/protocol/LoginProtocol.java
@@ -1,5 +1,6 @@
 package org.keycloak.protocol;
 
+import org.keycloak.events.EventBuilder;
 import org.keycloak.models.ClientSessionModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
@@ -24,6 +25,8 @@ public interface LoginProtocol extends Provider {
 
     LoginProtocol setHttpHeaders(HttpHeaders headers);
 
+    LoginProtocol setEventBuilder(EventBuilder event);
+
     Response cancelLogin(ClientSessionModel clientSession);
     Response invalidSessionError(ClientSessionModel clientSession);
     Response authenticated(UserSessionModel userSession, ClientSessionCode accessCode);
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java
old mode 100644
new mode 100755
index 824b176..dd06346
--- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java
@@ -235,7 +235,7 @@ public class AuthorizationEndpoint {
         String accessCode = new ClientSessionCode(realm, clientSession).getCode();
 
         if (idpHint != null && !"".equals(idpHint)) {
-            IdentityProviderModel identityProviderModel = realm.getIdentityProviderById(idpHint);
+            IdentityProviderModel identityProviderModel = realm.getIdentityProviderByAlias(idpHint);
 
             if (identityProviderModel == null) {
                 return Flows.forms(session, realm, null, uriInfo, headers)
@@ -254,14 +254,14 @@ public class AuthorizationEndpoint {
         if (httpAuthOutput.getResponse() != null) return httpAuthOutput.getResponse();
 
         if (prompt != null && prompt.equals("none")) {
-            OIDCLoginProtocol oauth = new OIDCLoginProtocol(session, realm, uriInfo, headers);
+            OIDCLoginProtocol oauth = new OIDCLoginProtocol(session, realm, uriInfo, headers, event);
             return oauth.cancelLogin(clientSession);
         }
 
         List<IdentityProviderModel> identityProviders = realm.getIdentityProviders();
         for (IdentityProviderModel identityProvider : identityProviders) {
             if (identityProvider.isAuthenticateByDefault()) {
-                return buildRedirectToIdentityProvider(identityProvider.getId(), accessCode);
+                return buildRedirectToIdentityProvider(identityProvider.getAlias(), accessCode);
             }
         }
 
@@ -269,7 +269,7 @@ public class AuthorizationEndpoint {
         if (requiredCredentials.isEmpty()) {
             if (!identityProviders.isEmpty()) {
                 if (identityProviders.size() == 1) {
-                    return buildRedirectToIdentityProvider(identityProviders.get(0).getId(), accessCode);
+                    return buildRedirectToIdentityProvider(identityProviders.get(0).getAlias(), accessCode);
                 }
 
                 return Flows.forms(session, realm, null, uriInfo, headers).setError(Messages.IDENTITY_PROVIDER_NOT_UNIQUE, realm.getName()).createErrorPage();
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/LogoutEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/LogoutEndpoint.java
old mode 100644
new mode 100755
index a47aa6a..ad5b302
--- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/LogoutEndpoint.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/LogoutEndpoint.java
@@ -78,23 +78,28 @@ public class LogoutEndpoint {
      */
     @GET
     @NoCache
-    public Response logout(final @QueryParam(OIDCLoginProtocol.REDIRECT_URI_PARAM) String redirectUri) {
-        event.event(EventType.LOGOUT);
+    public Response logout(@QueryParam(OIDCLoginProtocol.REDIRECT_URI_PARAM) String redirectUri) {
         if (redirectUri != null) {
-            event.detail(Details.REDIRECT_URI, redirectUri);
+            String validatedUri = RedirectUtils.verifyRealmRedirectUri(uriInfo, redirectUri, realm);
+            if (validatedUri == null) {
+                event.event(EventType.LOGOUT);
+                event.detail(Details.REDIRECT_URI, redirectUri);
+                event.error(Errors.INVALID_REDIRECT_URI);
+                return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.INVALID_REDIRECT_URI);
+            }
+            redirectUri = validatedUri;
         }
+
         // authenticate identity cookie, but ignore an access token timeout as we're logging out anyways.
         AuthenticationManager.AuthResult authResult = authManager.authenticateIdentityCookie(session, realm, uriInfo, clientConnection, headers, false);
         if (authResult != null) {
-            logout(authResult.getSession());
+            if (redirectUri != null) authResult.getSession().setNote(OIDCLoginProtocol.LOGOUT_REDIRECT_URI, redirectUri);
+            authResult.getSession().setNote(AuthenticationManager.KEYCLOAK_LOGOUT_PROTOCOL, OIDCLoginProtocol.LOGIN_PROTOCOL);
+            return AuthenticationManager.browserLogout(session, realm, authResult.getSession(), uriInfo, clientConnection, headers);
         }
 
         if (redirectUri != null) {
-            String validatedRedirect = RedirectUtils.verifyRealmRedirectUri(uriInfo, redirectUri, realm);
-            if (validatedRedirect == null) {
-                return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.INVALID_REDIRECT_URI);
-            }
-            return Response.status(302).location(UriBuilder.fromUri(validatedRedirect).build()).build();
+            return Response.status(302).location(UriBuilder.fromUri(redirectUri).build()).build();
         } else {
             return Response.ok().build();
         }
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java
index 1c473f9..cdbef96 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java
@@ -24,6 +24,9 @@ package org.keycloak.protocol.oidc;
 import org.jboss.logging.Logger;
 import org.jboss.resteasy.client.core.executors.ApacheHttpClient4Executor;
 import org.keycloak.OAuth2Constants;
+import org.keycloak.events.Details;
+import org.keycloak.events.EventBuilder;
+import org.keycloak.events.EventType;
 import org.keycloak.models.ApplicationModel;
 import org.keycloak.models.ClientSessionModel;
 import org.keycloak.models.KeycloakSession;
@@ -54,6 +57,7 @@ public class OIDCLoginProtocol implements LoginProtocol {
     public static final String CLIENT_ID_PARAM = "client_id";
     public static final String PROMPT_PARAM = "prompt";
     public static final String LOGIN_HINT_PARAM = "login_hint";
+    public static final String LOGOUT_REDIRECT_URI = "OIDC_LOGOUT_REDIRECT_URI";
 
     private static final Logger log = Logger.getLogger(OIDCLoginProtocol.class);
 
@@ -65,11 +69,14 @@ public class OIDCLoginProtocol implements LoginProtocol {
 
     protected HttpHeaders headers;
 
-    public OIDCLoginProtocol(KeycloakSession session, RealmModel realm, UriInfo uriInfo, HttpHeaders headers) {
+    protected EventBuilder event;
+
+    public OIDCLoginProtocol(KeycloakSession session, RealmModel realm, UriInfo uriInfo, HttpHeaders headers, EventBuilder event) {
         this.session = session;
         this.realm = realm;
         this.uriInfo = uriInfo;
         this.headers = headers;
+        this.event = event;
     }
 
     public OIDCLoginProtocol(){
@@ -101,6 +108,12 @@ public class OIDCLoginProtocol implements LoginProtocol {
     }
 
     @Override
+    public OIDCLoginProtocol setEventBuilder(EventBuilder event) {
+        this.event = event;
+        return this;
+    }
+
+    @Override
     public Response cancelLogin(ClientSessionModel clientSession) {
         String redirect = clientSession.getRedirectUri();
         String state = clientSession.getNote(OIDCLoginProtocol.STATE_PARAM);
@@ -168,7 +181,19 @@ public class OIDCLoginProtocol implements LoginProtocol {
 
     @Override
     public Response finishLogout(UserSessionModel userSession) {
-        throw new RuntimeException("NOT IMPLEMENTED");
+        String redirectUri = userSession.getNote(OIDCLoginProtocol.LOGOUT_REDIRECT_URI);
+        event.event(EventType.LOGOUT);
+        if (redirectUri != null) {
+            event.detail(Details.REDIRECT_URI, redirectUri);
+        }
+        event.user(userSession.getUser()).session(userSession).success();
+
+
+        if (redirectUri != null) {
+            return Response.status(302).location(UriBuilder.fromUri(redirectUri).build()).build();
+        } else {
+            return Response.ok().build();
+        }
     }
 
     @Override
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProvider.java b/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProvider.java
old mode 100644
new mode 100755
index 54e4009..19ecd44
--- a/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProvider.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProvider.java
@@ -37,6 +37,7 @@ public class OIDCWellKnownProvider implements WellKnownProvider {
         config.setAuthorizationEndpoint(uriBuilder.clone().path(OIDCLoginProtocolService.class, "auth").build(realm.getName(), OIDCLoginProtocol.LOGIN_PROTOCOL).toString());
         config.setTokenEndpoint(uriBuilder.clone().path(OIDCLoginProtocolService.class, "token").build(realm.getName(), OIDCLoginProtocol.LOGIN_PROTOCOL).toString());
         config.setUserinfoEndpoint(uriBuilder.clone().path(OIDCLoginProtocolService.class, "issueUserInfo").build(realm.getName(), OIDCLoginProtocol.LOGIN_PROTOCOL).toString());
+        config.setLogoutEndpoint(uriBuilder.clone().path(OIDCLoginProtocolService.class, "logout").build(realm.getName(), OIDCLoginProtocol.LOGIN_PROTOCOL).toString());
         config.setJwksUri(uriBuilder.clone().path(OIDCLoginProtocolService.class, "certs").build(realm.getName(), OIDCLoginProtocol.LOGIN_PROTOCOL).toString());
 
         config.setIdTokenSigningAlgValuesSupported(DEFAULT_ID_TOKEN_SIGNING_ALG_VALUES_SUPPORTED);
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/representations/OIDCConfigurationRepresentation.java b/services/src/main/java/org/keycloak/protocol/oidc/representations/OIDCConfigurationRepresentation.java
old mode 100644
new mode 100755
index 0760b64..0e3d4f3
--- a/services/src/main/java/org/keycloak/protocol/oidc/representations/OIDCConfigurationRepresentation.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/representations/OIDCConfigurationRepresentation.java
@@ -23,6 +23,9 @@ public class OIDCConfigurationRepresentation {
     @JsonProperty("userinfo_endpoint")
     private String userinfoEndpoint;
 
+    @JsonProperty("end_session_endpoint")
+    private String logoutEndpoint;
+
     @JsonProperty("jwks_uri")
     private String jwksUri;
 
@@ -81,6 +84,14 @@ public class OIDCConfigurationRepresentation {
         this.jwksUri = jwksUri;
     }
 
+    public String getLogoutEndpoint() {
+        return logoutEndpoint;
+    }
+
+    public void setLogoutEndpoint(String logoutEndpoint) {
+        this.logoutEndpoint = logoutEndpoint;
+    }
+
     public List<String> getGrantTypesSupported() {
         return grantTypesSupported;
     }
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 ffc61d3..383f5e3 100755
--- a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
@@ -6,6 +6,7 @@ import org.jboss.resteasy.spi.HttpRequest;
 import org.keycloak.ClientConnection;
 import org.keycloak.RSATokenVerifier;
 import org.keycloak.VerificationException;
+import org.keycloak.broker.provider.IdentityProvider;
 import org.keycloak.events.Details;
 import org.keycloak.events.EventBuilder;
 import org.keycloak.events.EventType;
@@ -27,6 +28,7 @@ import org.keycloak.protocol.LoginProtocol;
 import org.keycloak.protocol.oidc.TokenManager;
 import org.keycloak.representations.AccessToken;
 import org.keycloak.representations.idm.CredentialRepresentation;
+import org.keycloak.services.resources.IdentityBrokerService;
 import org.keycloak.services.resources.LoginActionsService;
 import org.keycloak.services.resources.RealmsResource;
 import org.keycloak.services.resources.flows.Flows;
@@ -144,9 +146,6 @@ public class AuthenticationManager {
             }
         }
 
-        if (redirectClients.size() == 0) {
-            return finishBrowserLogout(session, realm, userSession, uriInfo, connection, headers);
-        }
         for (ClientSessionModel nextRedirectClient : redirectClients) {
             String authMethod = nextRedirectClient.getAuthMethod();
             LoginProtocol protocol = session.getProvider(LoginProtocol.class, authMethod);
@@ -167,18 +166,26 @@ public class AuthenticationManager {
             }
 
         }
+        String brokerId = userSession.getNote(IdentityBrokerService.BROKER_PROVIDER_ID);
+        if (brokerId != null) {
+            IdentityProvider identityProvider = IdentityBrokerService.getIdentityProvider(session, realm, brokerId);
+            Response response = identityProvider.keycloakInitiatedBrowserLogout(userSession, uriInfo, realm);
+            if (response != null) return response;
+        }
         return finishBrowserLogout(session, realm, userSession, uriInfo, connection, headers);
     }
 
-    protected static Response finishBrowserLogout(KeycloakSession session, RealmModel realm, UserSessionModel userSession, UriInfo uriInfo, ClientConnection connection, HttpHeaders headers) {
+    public static Response finishBrowserLogout(KeycloakSession session, RealmModel realm, UserSessionModel userSession, UriInfo uriInfo, ClientConnection connection, HttpHeaders headers) {
         expireIdentityCookie(realm, uriInfo, connection);
         expireRememberMeCookie(realm, uriInfo, connection);
         userSession.setState(UserSessionModel.State.LOGGED_OUT);
         String method = userSession.getNote(KEYCLOAK_LOGOUT_PROTOCOL);
+        EventBuilder event = new EventsManager(realm, session, connection).createEventBuilder();
         LoginProtocol protocol = session.getProvider(LoginProtocol.class, method);
         protocol.setRealm(realm)
                 .setHttpHeaders(headers)
-                .setUriInfo(uriInfo);
+                .setUriInfo(uriInfo)
+                .setEventBuilder(event);
         Response response = protocol.finishLogout(userSession);
         session.sessions().removeUserSession(realm, userSession);
         return response;
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 cf59818..0c219da 100755
--- a/services/src/main/java/org/keycloak/services/messages/Messages.java
+++ b/services/src/main/java/org/keycloak/services/messages/Messages.java
@@ -171,4 +171,6 @@ public class Messages {
     public static final String CLIENT_NOT_FOUND = "clientNotFoundMessage";
 
     public static final String INVALID_PARAMETER = "invalidParameterMessage";
+
+    public static final String IDENTITY_PROVIDER_LOGIN_FAILURE = "identityProviderLoginFailure";
 }
diff --git a/services/src/main/java/org/keycloak/services/resources/AccountService.java b/services/src/main/java/org/keycloak/services/resources/AccountService.java
index fae8952..7f155e0 100755
--- a/services/src/main/java/org/keycloak/services/resources/AccountService.java
+++ b/services/src/main/java/org/keycloak/services/resources/AccountService.java
@@ -652,7 +652,7 @@ public class AccountService {
         boolean hasProvider = false;
 
         for (IdentityProviderModel model : realm.getIdentityProviders()) {
-            if (model.getId().equals(providerId)) {
+            if (model.getAlias().equals(providerId)) {
                 hasProvider = true;
             }
         }
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java
index 400fba4..a5c0f50 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java
@@ -64,7 +64,7 @@ public class IdentityProviderResource {
         this.auth.requireManage();
         removeClientIdentityProviders(this.realm.getApplications(), this.identityProviderModel);
         removeClientIdentityProviders(this.realm.getOAuthClients(), this.identityProviderModel);
-        this.realm.removeIdentityProviderById(this.identityProviderModel.getId());
+        this.realm.removeIdentityProviderByAlias(this.identityProviderModel.getAlias());
         return Response.noContent().build();
     }
 
@@ -75,7 +75,7 @@ public class IdentityProviderResource {
             this.auth.requireManage();
 
             String internalId = providerRep.getInternalId();
-            String newProviderId = providerRep.getId();
+            String newProviderId = providerRep.getAlias();
             String oldProviderId = getProviderIdByInternalId(this.realm, internalId);
 
             this.realm.updateIdentityProvider(RepresentationToModel.toModel(providerRep));
@@ -92,7 +92,7 @@ public class IdentityProviderResource {
 
             return Response.noContent().build();
         } catch (ModelDuplicateException e) {
-            return Flows.errors().exists("Identity Provider " + providerRep.getId() + " already exists");
+            return Flows.errors().exists("Identity Provider " + providerRep.getAlias() + " already exists");
         }
     }
 
@@ -101,7 +101,7 @@ public class IdentityProviderResource {
         List<IdentityProviderModel> providerModels = realm.getIdentityProviders();
         for (IdentityProviderModel providerModel : providerModels) {
             if (providerModel.getInternalId().equals(providerInternalId)) {
-                return providerModel.getId();
+                return providerModel.getAlias();
             }
         }
 
@@ -175,7 +175,7 @@ public class IdentityProviderResource {
             List<ClientIdentityProviderMappingModel> identityProviders = clientModel.getIdentityProviders();
 
             for (ClientIdentityProviderMappingModel providerMappingModel : new ArrayList<ClientIdentityProviderMappingModel>(identityProviders)) {
-                if (providerMappingModel.getIdentityProvider().equals(identityProvider.getId())) {
+                if (providerMappingModel.getIdentityProvider().equals(identityProvider.getAlias())) {
                     identityProviders.remove(providerMappingModel);
                     clientModel.updateIdentityProviders(identityProviders);
                     break;
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/IdentityProvidersResource.java b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProvidersResource.java
index b2d4ebf..afae00b 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/IdentityProvidersResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProvidersResource.java
@@ -56,21 +56,6 @@ public class IdentityProvidersResource {
         this.auth.init(RealmAuth.Resource.IDENTITY_PROVIDER);
     }
 
-    @GET
-    @NoCache
-    @Produces("application/json")
-    public List<IdentityProviderRepresentation> getIdentityProviders() {
-        this.auth.requireView();
-
-        List<IdentityProviderRepresentation> representations = new ArrayList<IdentityProviderRepresentation>();
-
-        for (IdentityProviderModel identityProviderModel : realm.getIdentityProviders()) {
-            representations.add(ModelToRepresentation.toRepresentation(identityProviderModel));
-        }
-
-        return representations;
-    }
-
     @Path("/providers/{provider_id}")
     @GET
     @NoCache
@@ -87,71 +72,28 @@ public class IdentityProvidersResource {
     }
 
     @POST
-    @Consumes(MediaType.APPLICATION_JSON)
-    public Response create(@Context UriInfo uriInfo, IdentityProviderRepresentation representation) {
-        this.auth.requireManage();
-
-        try {
-            this.realm.addIdentityProvider(RepresentationToModel.toModel(representation));
-
-            return Response.created(uriInfo.getAbsolutePathBuilder().path(representation.getProviderId()).build()).build();
-        } catch (ModelDuplicateException e) {
-            return Flows.errors().exists("Identity Provider " + representation.getId() + " already exists");
-        }
-    }
-
-    @POST
-    @Path("import")
+    @Path("import-config")
     @Consumes(MediaType.MULTIPART_FORM_DATA)
-    public Response importFrom(@Context UriInfo uriInfo, MultipartFormDataInput input) throws IOException {
+    @Produces(MediaType.APPLICATION_JSON)
+    public Map<String, String> importFrom(@Context UriInfo uriInfo, MultipartFormDataInput input) throws IOException {
         this.auth.requireManage();
         Map<String, List<InputPart>> formDataMap = input.getFormDataMap();
-
-        String id = formDataMap.get("id").get(0).getBodyAsString();
-        String name = formDataMap.get("name").get(0).getBodyAsString();
         String providerId = formDataMap.get("providerId").get(0).getBodyAsString();
-        String enabled = formDataMap.get("enabled").get(0).getBodyAsString();
-        String updateProfileFirstLogin = formDataMap.get("updateProfileFirstLogin").get(0).getBodyAsString();
-        String storeToken = "false";
-
-        if (formDataMap.containsKey("storeToken")) {
-            storeToken = formDataMap.get("storeToken").get(0).getBodyAsString();
-        }
-
         InputPart file = formDataMap.get("file").get(0);
         InputStream inputStream = file.getBody(InputStream.class, null);
         IdentityProviderFactory providerFactory = getProviderFactorytById(providerId);
-        Map config = providerFactory.parseConfig(inputStream);
-        IdentityProviderRepresentation representation = new IdentityProviderRepresentation();
-
-        representation.setId(id);
-        representation.setName(name);
-        representation.setProviderId(providerId);
-        representation.setEnabled(Boolean.valueOf(enabled));
-        representation.setUpdateProfileFirstLogin(Boolean.valueOf(updateProfileFirstLogin));
-        representation.setStoreToken(Boolean.valueOf(storeToken));
-        representation.setConfig(config);
-
-        return create(uriInfo, representation);
+        Map<String, String> config = providerFactory.parseConfig(inputStream);
+        return config;
     }
 
     @POST
-    @Path("import")
+    @Path("import-config")
     @Consumes(MediaType.APPLICATION_JSON)
-    public Response importFrom(@Context UriInfo uriInfo, Map<String, Object> data) throws IOException {
+    @Produces(MediaType.APPLICATION_JSON)
+    public Map<String, String> importFrom(@Context UriInfo uriInfo, Map<String, Object> data) throws IOException {
         this.auth.requireManage();
 
-        String id = data.get("id").toString();
-        String name = data.get("name").toString();
         String providerId = data.get("providerId").toString();
-        String enabled = data.get("enabled").toString();
-        String updateProfileFirstLogin = data.get("updateProfileFirstLogin").toString();
-        String storeToken = "false";
-
-        if (data.containsKey("storeToken")) {
-            storeToken = data.get("storeToken").toString();
-        }
-
         String from = data.get("fromUrl").toString();
         ApacheHttpClient4Executor executor = ResourceAdminManager.createExecutor();
         InputStream inputStream = null;
@@ -161,34 +103,55 @@ public class IdentityProvidersResource {
             throw new RuntimeException(e);
         }
         IdentityProviderFactory providerFactory = getProviderFactorytById(providerId);
-        Map config = providerFactory.parseConfig(inputStream);
-        IdentityProviderRepresentation representation = new IdentityProviderRepresentation();
-
-        representation.setId(id);
-        representation.setName(name);
-        representation.setProviderId(providerId);
-        representation.setEnabled(Boolean.valueOf(enabled));
-        representation.setUpdateProfileFirstLogin(Boolean.valueOf(updateProfileFirstLogin));
-        representation.setStoreToken(Boolean.valueOf(storeToken));
-        representation.setConfig(config);
-
-        return create(uriInfo, representation);
+        Map<String, String> config = providerFactory.parseConfig(inputStream);
+        return config;
+    }
+
+    @GET
+    @Path("instances")
+    @NoCache
+    @Produces("application/json")
+    public List<IdentityProviderRepresentation> getIdentityProviders() {
+        this.auth.requireView();
+
+        List<IdentityProviderRepresentation> representations = new ArrayList<IdentityProviderRepresentation>();
+
+        for (IdentityProviderModel identityProviderModel : realm.getIdentityProviders()) {
+            representations.add(ModelToRepresentation.toRepresentation(identityProviderModel));
+        }
+
+        return representations;
+    }
+
+    @POST
+    @Path("instances")
+    @Consumes(MediaType.APPLICATION_JSON)
+    public Response create(@Context UriInfo uriInfo, IdentityProviderRepresentation representation) {
+        this.auth.requireManage();
+
+        try {
+            this.realm.addIdentityProvider(RepresentationToModel.toModel(representation));
+
+            return Response.created(uriInfo.getAbsolutePathBuilder().path(representation.getProviderId()).build()).build();
+        } catch (ModelDuplicateException e) {
+            return Flows.errors().exists("Identity Provider " + representation.getAlias() + " already exists");
+        }
     }
 
-    @Path("instances/{id}")
-    public IdentityProviderResource getIdentityProvider(@PathParam("id") String providerId) {
+    @Path("instances/{alias}")
+    public IdentityProviderResource getIdentityProvider(@PathParam("alias") String alias) {
         this.auth.requireView();
         IdentityProviderModel identityProviderModel = null;
 
         for (IdentityProviderModel storedIdentityProvider : this.realm.getIdentityProviders()) {
-            if (storedIdentityProvider.getId().equals(providerId)
-                    || storedIdentityProvider.getInternalId().equals(providerId)) {
+            if (storedIdentityProvider.getAlias().equals(alias)
+                    || storedIdentityProvider.getInternalId().equals(alias)) {
                 identityProviderModel = storedIdentityProvider;
             }
         }
 
         if (identityProviderModel == null) {
-            throw new NotFoundException("Could not find identity provider: " + providerId);
+            throw new NotFoundException("Could not find identity provider: " + alias);
         }
 
         IdentityProviderResource identityProviderResource = new IdentityProviderResource(this.auth, realm, session, identityProviderModel);
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoAdminResource.java
index 4bfb629..80ba402 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoAdminResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoAdminResource.java
@@ -84,13 +84,13 @@ public class ServerInfoAdminResource {
     }
 
     private void setSocialProviders(ServerInfoRepresentation info) {
-        info.socialProviders = new LinkedList<IdentityProviderRepresentation>();
+        info.socialProviders = new LinkedList<>();
         List<ProviderFactory> providerFactories = session.getKeycloakSessionFactory().getProviderFactories(SocialIdentityProvider.class);
         setIdentityProviders(providerFactories, info.socialProviders, "Social");
     }
 
     private void setIdentityProviders(ServerInfoRepresentation info) {
-        info.identityProviders = new LinkedList<IdentityProviderRepresentation>();
+        info.identityProviders = new LinkedList<>();
         List<ProviderFactory> providerFactories = session.getKeycloakSessionFactory().getProviderFactories(IdentityProvider.class);
         setIdentityProviders(providerFactories, info.identityProviders, "User-defined");
 
@@ -98,24 +98,16 @@ public class ServerInfoAdminResource {
         setIdentityProviders(providerFactories, info.identityProviders, "Social");
     }
 
-    public void setIdentityProviders(List<ProviderFactory> factories, List<IdentityProviderRepresentation> providers, String groupName) {
+    public void setIdentityProviders(List<ProviderFactory> factories, List<Map<String, String>> providers, String groupName) {
         for (ProviderFactory providerFactory : factories) {
             IdentityProviderFactory factory = (IdentityProviderFactory) providerFactory;
-            IdentityProviderRepresentation rep = new IdentityProviderRepresentation();
-
-            rep.setId(factory.getId());
-            rep.setName(factory.getName());
-            rep.setGroupName(groupName);
+            Map<String, String> data = new HashMap<>();
+            data.put("groupName", groupName);
+            data.put("name", factory.getName());
+            data.put("id", factory.getId());
 
-            providers.add(rep);
+            providers.add(data);
         }
-
-        Collections.sort(providers, new Comparator<IdentityProviderRepresentation>() {
-            @Override
-            public int compare(IdentityProviderRepresentation o1, IdentityProviderRepresentation o2) {
-                return o1.getName().compareTo(o2.getName());
-            }
-        });
     }
 
     private void setEventListeners(ServerInfoRepresentation info) {
@@ -194,8 +186,8 @@ public class ServerInfoAdminResource {
 
         private Map<String, List<String>> themes;
 
-        private List<IdentityProviderRepresentation> socialProviders;
-        public List<IdentityProviderRepresentation> identityProviders;
+        private List<Map<String, String>> socialProviders;
+        public List<Map<String, String>> identityProviders;
         private List<String> protocols;
         private List<Map<String, String>> applicationImporters;
 
@@ -220,11 +212,11 @@ public class ServerInfoAdminResource {
             return themes;
         }
 
-        public List<IdentityProviderRepresentation> getSocialProviders() {
+        public List<Map<String, String>> getSocialProviders() {
             return socialProviders;
         }
 
-        public List<IdentityProviderRepresentation> getIdentityProviders() {
+        public List<Map<String, String>> getIdentityProviders() {
             return this.identityProviders;
         }
 
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
index 6b694a7..f271a2e 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
@@ -265,7 +265,7 @@ public class UsersResource {
 
         for (FederatedIdentityModel identity : identities) {
             for (IdentityProviderModel identityProviderModel : realm.getIdentityProviders()) {
-                if (identityProviderModel.getId().equals(identity.getIdentityProvider())) {
+                if (identityProviderModel.getAlias().equals(identity.getIdentityProvider())) {
                     FederatedIdentityRepresentation rep = ModelToRepresentation.toRepresentation(identity);
                     result.add(rep);
                 }
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 cd1ac13..a835b66 100755
--- a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
+++ b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
@@ -19,9 +19,9 @@ package org.keycloak.services.resources;
 
 import org.jboss.logging.Logger;
 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;
@@ -77,9 +77,10 @@ import static org.keycloak.models.UserModel.RequiredAction.UPDATE_PROFILE;
  * @author Pedro Igor
  */
 @Path("/broker")
-public class IdentityBrokerService {
+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";
 
     private final RealmModel realmModel;
 
@@ -122,11 +123,9 @@ public class IdentityBrokerService {
         }
 
         try {
-            ClientSessionCode clientSessionCode = parseClientSessionCode(code, providerId);
-            IdentityProvider identityProvider = getIdentityProvider(providerId);
-            AuthenticationResponse authenticationResponse = identityProvider.handleRequest(createAuthenticationRequest(providerId, clientSessionCode));
-
-            Response response = authenticationResponse.getResponse();
+            ClientSessionCode clientSessionCode = parseClientSessionCode(code);
+            IdentityProvider identityProvider = getIdentityProvider(session, realmModel, providerId);
+            Response response = identityProvider.handleRequest(createAuthenticationRequest(providerId, clientSessionCode));
 
             if (response != null) {
                 this.event.success();
@@ -144,16 +143,15 @@ public class IdentityBrokerService {
         return redirectToErrorPage(Messages.COULD_NOT_PROCEED_WITH_AUTHENTICATION_REQUEST);
     }
 
-    @GET
-    @Path("{provider_id}")
-    public Response handleResponseGet(@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);
+        Object callback = identityProvider.callback(realmModel, this);
+        ResteasyProviderFactory.getInstance().injectProperties(callback);
+        //resourceContext.initResource(brokerService);
+        return callback;
+
 
-    @POST
-    @Path("{provider_id}")
-    public Response handleResponsePost(@PathParam("provider_id") String providerId) {
-        return handleResponse(providerId);
     }
 
     @Path("{provider_id}/token")
@@ -196,7 +194,7 @@ public class IdentityBrokerService {
                             .createOAuthGrant(null), clientModel);
                 }
 
-                IdentityProvider identityProvider = getIdentityProvider(providerId);
+                IdentityProvider identityProvider = getIdentityProvider(session, realmModel, providerId);
                 IdentityProviderModel identityProviderConfig = getIdentityProviderConfig(providerId);
 
                 if (identityProviderConfig.isStoreToken()) {
@@ -234,87 +232,45 @@ public class IdentityBrokerService {
         return getToken(providerId, true);
     }
 
-    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);
-
+    public Response authenticated(Map<String, String> userNotes, IdentityProviderModel identityProviderConfig, FederatedIdentity federatedIdentity, String code) {
+        ClientSessionCode clientCode = null;
         try {
-            IdentityProvider identityProvider = getIdentityProvider(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, providerId);
-            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();
+            clientCode = parseClientSessionCode(code);
+        } catch (Exception e) {
+            return redirectToErrorPage(Messages.IDENTITY_PROVIDER_AUTHENTICATION_FAILED, e, identityProviderConfig.getProviderId());
 
+        }
+        String providerId = identityProviderConfig.getAlias();
+        if (!identityProviderConfig.isStoreToken()) {
             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();
+                LOGGER.debugf("Token will not be stored for identity provider [%s].", providerId);
             }
+            federatedIdentity.setToken(null);
         }
-    }
 
-    private Response performLocalAuthentication(FederatedIdentity updatedIdentity, ClientSessionCode clientCode) {
+        federatedIdentity.setIdentityProviderId(providerId);
         ClientSessionModel clientSession = clientCode.getClientSession();
-        IdentityProviderModel identityProviderConfig = getIdentityProviderConfig(updatedIdentity.getIdentityProviderId());
-        String providerId = identityProviderConfig.getId();
-        FederatedIdentityModel federatedIdentityModel = new FederatedIdentityModel(providerId, updatedIdentity.getId(),
-                updatedIdentity.getUsername(), updatedIdentity.getToken());
+        FederatedIdentityModel federatedIdentityModel = new FederatedIdentityModel(providerId, federatedIdentity.getId(),
+                federatedIdentity.getUsername(), federatedIdentity.getToken());
 
         this.event.event(EventType.IDENTITY_PROVIDER_LOGIN)
                 .detail(Details.REDIRECT_URI, clientSession.getRedirectUri())
-                .detail(Details.IDENTITY_PROVIDER_IDENTITY, updatedIdentity.getUsername());
+                .detail(Details.IDENTITY_PROVIDER_IDENTITY, federatedIdentity.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) {
+            UserSessionModel userSession = clientSession.getUserSession();
+            for (Map.Entry<String, String> entry : userNotes.entrySet()) {
+                userSession.setNote(entry.getKey(), entry.getValue());
+            }
             return performAccountLinking(clientSession, providerId, federatedIdentityModel, federatedUser);
         }
 
         if (federatedUser == null) {
             try {
-                federatedUser = createUser(updatedIdentity);
+                federatedUser = createUser(federatedIdentity);
 
                 if (identityProviderConfig.isUpdateProfileFirstLogin()) {
                     if (isDebugEnabled()) {
@@ -327,7 +283,7 @@ public class IdentityBrokerService {
             }
         }
 
-        updateFederatedIdentity(updatedIdentity, federatedUser);
+        updateFederatedIdentity(federatedIdentity, federatedUser);
 
         UserSessionModel userSession = this.session.sessions()
                 .createUserSession(this.realmModel, federatedUser, federatedUser.getUsername(), this.clientConnection.getRemoteAddr(), "broker", false);
@@ -336,6 +292,10 @@ public class IdentityBrokerService {
         this.event.session(userSession);
 
         TokenManager.attachClientSession(userSession, clientSession);
+        for (Map.Entry<String, String> entry : userNotes.entrySet()) {
+            userSession.setNote(entry.getKey(), entry.getValue());
+        }
+        userSession.setNote(BROKER_PROVIDER_ID, providerId);
 
         if (isDebugEnabled()) {
             LOGGER.debugf("Performing local authentication for user [%s].", federatedUser);
@@ -387,7 +347,7 @@ public class IdentityBrokerService {
         }
     }
 
-    private ClientSessionCode parseClientSessionCode(String code, String providerId) {
+    private ClientSessionCode parseClientSessionCode(String code) {
         ClientSessionCode clientCode = ClientSessionCode.parse(code, this.session, this.realmModel);
 
         if (clientCode != null && clientCode.isValid(AUTHENTICATE)) {
@@ -466,28 +426,28 @@ public class IdentityBrokerService {
         return Flows.errors().error(message, Status.BAD_REQUEST);
     }
 
-    private IdentityProvider getIdentityProvider(String providerId) {
-        IdentityProviderModel identityProviderModel = this.realmModel.getIdentityProviderById(providerId);
+    public static IdentityProvider getIdentityProvider(KeycloakSession session, RealmModel realm, String alias) {
+        IdentityProviderModel identityProviderModel = realm.getIdentityProviderByAlias(alias);
 
         if (identityProviderModel != null) {
-            IdentityProviderFactory providerFactory = getIdentityProviderFactory(identityProviderModel);
+            IdentityProviderFactory providerFactory = getIdentityProviderFactory(session, identityProviderModel);
 
             if (providerFactory == null) {
-                throw new IdentityBrokerException("Could not find factory for identity provider [" + providerId + "].");
+                throw new IdentityBrokerException("Could not find factory for identity provider [" + alias + "].");
             }
 
             return providerFactory.create(identityProviderModel);
         }
 
-        throw new IdentityBrokerException("Identity Provider [" + providerId + "] not found.");
+        throw new IdentityBrokerException("Identity Provider [" + alias + "] not found.");
     }
 
-    private IdentityProviderFactory getIdentityProviderFactory(IdentityProviderModel model) {
+    private static IdentityProviderFactory getIdentityProviderFactory(KeycloakSession session, IdentityProviderModel model) {
         Map<String, IdentityProviderFactory> availableProviders = new HashMap<String, IdentityProviderFactory>();
         List<ProviderFactory> allProviders = new ArrayList<ProviderFactory>();
 
-        allProviders.addAll(this.session.getKeycloakSessionFactory().getProviderFactories(IdentityProvider.class));
-        allProviders.addAll(this.session.getKeycloakSessionFactory().getProviderFactories(SocialIdentityProvider.class));
+        allProviders.addAll(session.getKeycloakSessionFactory().getProviderFactories(IdentityProvider.class));
+        allProviders.addAll(session.getKeycloakSessionFactory().getProviderFactories(SocialIdentityProvider.class));
 
         for (ProviderFactory providerFactory : allProviders) {
             availableProviders.put(providerFactory.getId(), (IdentityProviderFactory) providerFactory);
@@ -498,7 +458,7 @@ public class IdentityBrokerService {
 
     private IdentityProviderModel getIdentityProviderConfig(String providerId) {
         for (IdentityProviderModel model : this.realmModel.getIdentityProviders()) {
-            if (model.getId().equals(providerId)) {
+            if (model.getAlias().equals(providerId)) {
                 return model;
             }
         }
diff --git a/services/src/main/java/org/keycloak/services/resources/RealmsResource.java b/services/src/main/java/org/keycloak/services/resources/RealmsResource.java
index 247a430..0feccb4 100755
--- a/services/src/main/java/org/keycloak/services/resources/RealmsResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/RealmsResource.java
@@ -189,7 +189,8 @@ public class RealmsResource {
 
         IdentityBrokerService brokerService = new IdentityBrokerService(realm);
         ResteasyProviderFactory.getInstance().injectProperties(brokerService);
-        
+        //resourceContext.initResource(brokerService);
+
         brokerService.init();
 
         return brokerService;
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/admin/AbstractClientTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/AbstractClientTest.java
index 5d04fa4..4d54909 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/AbstractClientTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/AbstractClientTest.java
@@ -102,7 +102,7 @@ public abstract class AbstractClientTest {
         } else if (o1 instanceof OAuthClientRepresentation) {
             return ((OAuthClientRepresentation) o1).getName();
         } else if (o1 instanceof IdentityProviderRepresentation) {
-            return ((IdentityProviderRepresentation) o1).getId();
+            return ((IdentityProviderRepresentation) o1).getAlias();
         }
         throw new IllegalArgumentException();
     }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/IdentityProviderTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/IdentityProviderTest.java
old mode 100644
new mode 100755
index 2d91d9f..80cc7a0
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/IdentityProviderTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/IdentityProviderTest.java
@@ -46,8 +46,7 @@ public class IdentityProviderTest extends AbstractClientTest {
         assertNotNull(representation);
 
         assertNotNull(representation.getInternalId());
-        assertEquals("New Identity Provider", representation.getName());
-        assertEquals("new-identity-provider", representation.getId());
+        assertEquals("new-identity-provider", representation.getAlias());
         assertEquals("oidc", representation.getProviderId());
         assertEquals("clientId", representation.getConfig().get("clientId"));
         assertEquals("clientSecret", representation.getConfig().get("clientSecret"));
@@ -72,9 +71,9 @@ public class IdentityProviderTest extends AbstractClientTest {
 
         assertNotNull(representation);
 
-        assertEquals("update-identity-provider", representation.getId());
+        assertEquals("update-identity-provider", representation.getAlias());
 
-        representation.setId("changed-alias");
+        representation.setAlias("changed-alias");
         representation.setEnabled(false);
         representation.setStoreToken(true);
         representation.getConfig().put("clientId", "changedClientId");
@@ -113,9 +112,8 @@ public class IdentityProviderTest extends AbstractClientTest {
     private IdentityProviderRepresentation create(String id, String providerId, String name) {
         IdentityProviderRepresentation identityProviderRepresentation = new IdentityProviderRepresentation();
 
-        identityProviderRepresentation.setId(id);
+        identityProviderRepresentation.setAlias(id);
         identityProviderRepresentation.setProviderId(providerId);
-        identityProviderRepresentation.setName(name);
         identityProviderRepresentation.setEnabled(true);
 
         return identityProviderRepresentation;
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/UserTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/UserTest.java
index 976223c..7d3fb2f 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/UserTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/UserTest.java
@@ -227,8 +227,7 @@ public class UserTest extends AbstractClientTest {
         Assert.assertEquals(0, providers.size());
 
         IdentityProviderRepresentation rep = new IdentityProviderRepresentation();
-        rep.setId("social-provider-id");
-        rep.setName("social-provider-name");
+        rep.setAlias("social-provider-id");
         rep.setProviderId("social-provider-type");
         realm.identityProviders().create(rep);
     }
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
old mode 100644
new mode 100755
index aeeb899..2630878
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java
@@ -369,7 +369,7 @@ public abstract class AbstractIdentityProviderTest {
 
         // Link my "pedroigor" identity with "test-user" from brokered Keycloak
         IdentityProviderModel identityProviderModel = getIdentityProviderModel();
-        accountFederatedIdentityPage.clickAddProvider(identityProviderModel.getId());
+        accountFederatedIdentityPage.clickAddProvider(identityProviderModel.getAlias());
 
         assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8082/auth/"));
         this.loginPage.login("test-user", "password");
@@ -377,28 +377,28 @@ public abstract class AbstractIdentityProviderTest {
 
         // Assert identity linked in account management
         assertTrue(accountFederatedIdentityPage.isCurrent());
-        assertTrue(driver.getPageSource().contains("id=\"remove-" + identityProviderModel.getId() + "\""));
+        assertTrue(driver.getPageSource().contains("id=\"remove-" + identityProviderModel.getAlias() + "\""));
 
         // Logout from account management
         accountFederatedIdentityPage.logout();
         assertTrue(driver.getTitle().equals("Log in to realm-with-broker"));
 
         // Assert I am logged immediately to account management due to previously linked "test-user" identity
-        loginPage.clickSocial(identityProviderModel.getId());
+        loginPage.clickSocial(identityProviderModel.getAlias());
         doAfterProviderAuthentication();
         assertTrue(accountFederatedIdentityPage.isCurrent());
-        assertTrue(driver.getPageSource().contains("id=\"remove-" + identityProviderModel.getId() + "\""));
+        assertTrue(driver.getPageSource().contains("id=\"remove-" + identityProviderModel.getAlias() + "\""));
 
         // Unlink my "test-user"
-        accountFederatedIdentityPage.clickRemoveProvider(identityProviderModel.getId());
-        assertTrue(driver.getPageSource().contains("id=\"add-" + identityProviderModel.getId() + "\""));
+        accountFederatedIdentityPage.clickRemoveProvider(identityProviderModel.getAlias());
+        assertTrue(driver.getPageSource().contains("id=\"add-" + identityProviderModel.getAlias() + "\""));
 
         // Logout from account management
         accountFederatedIdentityPage.logout();
         assertTrue(driver.getTitle().equals("Log in to realm-with-broker"));
 
         // Try to login. Previous link is not valid anymore, so now it should try to register new user
-        this.loginPage.clickSocial(identityProviderModel.getId());
+        this.loginPage.clickSocial(identityProviderModel.getAlias());
         doAfterProviderAuthentication();
         this.updateProfilePage.assertCurrent();
     }
@@ -589,7 +589,7 @@ public abstract class AbstractIdentityProviderTest {
         this.loginPage.clickSocial(getProviderId());
 
         assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8082/auth/"));
-
+        System.out.println(this.driver.getCurrentUrl());
         // log in to identity provider
         this.loginPage.login(username, "password");
 
@@ -622,7 +622,7 @@ public abstract class AbstractIdentityProviderTest {
     protected abstract String getProviderId();
 
     protected IdentityProviderModel getIdentityProviderModel() {
-        IdentityProviderModel identityProviderModel = getRealm().getIdentityProviderById(getProviderId());
+        IdentityProviderModel identityProviderModel = getRealm().getIdentityProviderByAlias(getProviderId());
 
         assertNotNull(identityProviderModel);
 
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/IdentityProviderRegistrationTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/IdentityProviderRegistrationTest.java
old mode 100644
new mode 100755
index 8a0d6cc..b05857f
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/IdentityProviderRegistrationTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/IdentityProviderRegistrationTest.java
@@ -61,7 +61,7 @@ public class IdentityProviderRegistrationTest extends AbstractIdentityProviderMo
 
         IdentityProviderModel identityProviderModel = new IdentityProviderModel();
 
-        identityProviderModel.setId("custom-provider");
+        identityProviderModel.setAlias("custom-provider");
 
         CustomSocialProvider customSocialProvider = providerFactory.create(identityProviderModel);
 
@@ -69,7 +69,7 @@ public class IdentityProviderRegistrationTest extends AbstractIdentityProviderMo
         IdentityProviderModel config = customSocialProvider.getConfig();
 
         assertNotNull(config);
-        assertEquals("custom-provider", config.getId());
+        assertEquals("custom-provider", config.getAlias());
     }
 
     @Test
@@ -84,7 +84,7 @@ public class IdentityProviderRegistrationTest extends AbstractIdentityProviderMo
 
         IdentityProviderModel identityProviderModel = new IdentityProviderModel();
 
-        identityProviderModel.setId("custom-provider");
+        identityProviderModel.setAlias("custom-provider");
 
         CustomIdentityProvider provider = providerFactory.create(identityProviderModel);
 
@@ -92,7 +92,7 @@ public class IdentityProviderRegistrationTest extends AbstractIdentityProviderMo
         IdentityProviderModel config = provider.getConfig();
 
         assertNotNull(config);
-        assertEquals("custom-provider", config.getId());
+        assertEquals("custom-provider", config.getAlias());
     }
 
     private Set<String> getInstalledProviders() {
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/ImportIdentityProviderTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/ImportIdentityProviderTest.java
index 3906666..d2caacf 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/ImportIdentityProviderTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/ImportIdentityProviderTest.java
@@ -72,9 +72,8 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
         assertFalse(identityProviders.isEmpty());
 
         IdentityProviderModel identityProviderModel = identityProviders.get(0);
-        String identityProviderId = identityProviderModel.getId();
+        String identityProviderId = identityProviderModel.getAlias();
 
-        identityProviderModel.setName("Changed Name");
         identityProviderModel.getConfig().put("config-added", "value-added");
         identityProviderModel.setEnabled(false);
         identityProviderModel.setUpdateProfileFirstLogin(false);
@@ -87,16 +86,14 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
 
         realm = this.realmManager.getRealm(realm.getId());
 
-        identityProviderModel = realm.getIdentityProviderById(identityProviderId);
+        identityProviderModel = realm.getIdentityProviderByAlias(identityProviderId);
 
-        assertEquals("Changed Name", identityProviderModel.getName());
         assertEquals("value-added", identityProviderModel.getConfig().get("config-added"));
         assertFalse(identityProviderModel.isEnabled());
         assertFalse(identityProviderModel.isUpdateProfileFirstLogin());
         assertTrue(identityProviderModel.isStoreToken());
         assertTrue(identityProviderModel.isAuthenticateByDefault());
 
-        identityProviderModel.setName("Changed Name Again");
         identityProviderModel.getConfig().remove("config-added");
         identityProviderModel.setEnabled(true);
         identityProviderModel.setUpdateProfileFirstLogin(true);
@@ -107,9 +104,8 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
         commit();
 
         realm = this.realmManager.getRealm(realm.getId());
-        identityProviderModel = realm.getIdentityProviderById(identityProviderId);
+        identityProviderModel = realm.getIdentityProviderByAlias(identityProviderId);
 
-        assertEquals("Changed Name Again", identityProviderModel.getName());
         assertFalse(identityProviderModel.getConfig().containsKey("config-added"));
         assertTrue(identityProviderModel.isEnabled());
         assertTrue(identityProviderModel.isUpdateProfileFirstLogin());
@@ -149,7 +145,7 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
         Set<String> checkedProviders = new HashSet<String>(getExpectedProviders());
 
         for (IdentityProviderModel identityProvider : identityProviders) {
-            if (identityProvider.getId().startsWith("model-")) {
+            if (identityProvider.getAlias().startsWith("model-")) {
                 String providerId = identityProvider.getProviderId();
 
                 if (SAMLIdentityProviderFactory.PROVIDER_ID.equals(providerId)) {
@@ -179,9 +175,8 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
         GoogleIdentityProvider googleIdentityProvider = new GoogleIdentityProviderFactory().create(identityProvider);
         OIDCIdentityProviderConfig config = googleIdentityProvider.getConfig();
 
-        assertEquals("model-google", config.getId());
+        assertEquals("model-google", config.getAlias());
         assertEquals(GoogleIdentityProviderFactory.PROVIDER_ID, config.getProviderId());
-        assertEquals("Google", config.getName());
         assertEquals(true, config.isEnabled());
         assertEquals(true, config.isUpdateProfileFirstLogin());
         assertEquals(false, config.isAuthenticateByDefault());
@@ -198,9 +193,8 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
         SAMLIdentityProvider samlIdentityProvider = new SAMLIdentityProviderFactory().create(identityProvider);
         SAMLIdentityProviderConfig config = samlIdentityProvider.getConfig();
 
-        assertEquals("model-saml-signed-idp", config.getId());
+        assertEquals("model-saml-signed-idp", config.getAlias());
         assertEquals(SAMLIdentityProviderFactory.PROVIDER_ID, config.getProviderId());
-        assertEquals("SAML Signed IdP", config.getName());
         assertEquals(true, config.isEnabled());
         assertEquals(true, config.isUpdateProfileFirstLogin());
         assertEquals(false, config.isAuthenticateByDefault());
@@ -219,9 +213,8 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
         OIDCIdentityProvider googleIdentityProvider = new OIDCIdentityProviderFactory().create(identityProvider);
         OIDCIdentityProviderConfig config = googleIdentityProvider.getConfig();
 
-        assertEquals("model-oidc-idp", config.getId());
+        assertEquals("model-oidc-idp", config.getAlias());
         assertEquals(OIDCIdentityProviderFactory.PROVIDER_ID, config.getProviderId());
-        assertEquals("OIDC IdP", config.getName());
         assertEquals(false, config.isEnabled());
         assertEquals(false, config.isUpdateProfileFirstLogin());
         assertEquals(false, config.isAuthenticateByDefault());
@@ -234,9 +227,8 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
         FacebookIdentityProvider facebookIdentityProvider = new FacebookIdentityProviderFactory().create(identityProvider);
         OAuth2IdentityProviderConfig config = facebookIdentityProvider.getConfig();
 
-        assertEquals("model-facebook", config.getId());
+        assertEquals("model-facebook", config.getAlias());
         assertEquals(FacebookIdentityProviderFactory.PROVIDER_ID, config.getProviderId());
-        assertEquals("Facebook", config.getName());
         assertEquals(true, config.isEnabled());
         assertEquals(true, config.isUpdateProfileFirstLogin());
         assertEquals(false, config.isAuthenticateByDefault());
@@ -252,9 +244,8 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
         GitHubIdentityProvider gitHubIdentityProvider = new GitHubIdentityProviderFactory().create(identityProvider);
         OAuth2IdentityProviderConfig config = gitHubIdentityProvider.getConfig();
 
-        assertEquals("model-github", config.getId());
+        assertEquals("model-github", config.getAlias());
         assertEquals(GitHubIdentityProviderFactory.PROVIDER_ID, config.getProviderId());
-        assertEquals("GitHub", config.getName());
         assertEquals(true, config.isEnabled());
         assertEquals(true, config.isUpdateProfileFirstLogin());
         assertEquals(false, config.isAuthenticateByDefault());
@@ -270,9 +261,8 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
         TwitterIdentityProvider twitterIdentityProvider = new TwitterIdentityProviderFactory().create(identityProvider);
         OAuth2IdentityProviderConfig config = twitterIdentityProvider.getConfig();
 
-        assertEquals("model-twitter", config.getId());
+        assertEquals("model-twitter", config.getAlias());
         assertEquals(TwitterIdentityProviderFactory.PROVIDER_ID, config.getProviderId());
-        assertEquals("Twitter", config.getName());
         assertEquals(true, config.isEnabled());
         assertEquals(true, config.isUpdateProfileFirstLogin());
         assertEquals(false, config.isAuthenticateByDefault());
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 90edbda..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
@@ -1,6 +1,7 @@
 package org.keycloak.testsuite.broker;
 
 import org.junit.ClassRule;
+import org.junit.Test;
 import org.keycloak.models.IdentityProviderModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
@@ -70,7 +71,8 @@ public class SAMLKeyCloakServerBrokerBasicTest extends AbstractIdentityProviderT
         try {
             SAML2Request saml2Request = new SAML2Request();
             ResponseType responseType = (ResponseType) saml2Request
-                    .getSAML2ObjectFromStream(PostBindingUtil.base64DecodeAsStream(URLDecoder.decode(pageSource, "UTF-8")));
+                    .getSAML2ObjectFromStream(PostBindingUtil.base64DecodeAsStream(pageSource));
+                    //.getSAML2ObjectFromStream(PostBindingUtil.base64DecodeAsStream(URLDecoder.decode(pageSource, "UTF-8")));
 
             assertNotNull(responseType);
             assertFalse(responseType.getAssertions().isEmpty());
@@ -78,4 +80,16 @@ public class SAMLKeyCloakServerBrokerBasicTest extends AbstractIdentityProviderT
             fail("Could not parse token.");
         }
     }
+
+    @Override
+    @Test
+    public void testSuccessfulAuthenticationWithoutUpdateProfile() {
+        super.testSuccessfulAuthenticationWithoutUpdateProfile();
+    }
+
+    @Override
+    @Test
+    public void testTokenStorageAndRetrievalByOAuthClient() {
+        super.testTokenStorageAndRetrievalByOAuthClient();
+    }
 }
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 b55baae..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
@@ -70,7 +70,7 @@ public class SAMLKeyCloakServerBrokerWithSignatureTest extends AbstractIdentityP
         try {
             SAML2Request saml2Request = new SAML2Request();
             ResponseType responseType = (ResponseType) saml2Request
-                        .getSAML2ObjectFromStream(PostBindingUtil.base64DecodeAsStream(URLDecoder.decode(pageSource, "UTF-8")));
+                        .getSAML2ObjectFromStream(PostBindingUtil.base64DecodeAsStream(pageSource));
 
             assertNotNull(responseType);
             assertFalse(responseType.getAssertions().isEmpty());
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ImportTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ImportTest.java
index dd32e7c..e4d20f8 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ImportTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ImportTest.java
@@ -207,9 +207,8 @@ public class ImportTest extends AbstractModelTest {
         List<IdentityProviderModel> identityProviders = realm.getIdentityProviders();
         Assert.assertEquals(1, identityProviders.size());
         IdentityProviderModel google = identityProviders.get(0);
-        Assert.assertEquals("google1", google.getId());
+        Assert.assertEquals("google1", google.getAlias());
         Assert.assertEquals("google", google.getProviderId());
-        Assert.assertEquals("Google", google.getName());
         Assert.assertTrue(google.isEnabled());
         Assert.assertEquals("googleId", google.getConfig().get("clientId"));
         Assert.assertEquals("googleSecret", google.getConfig().get("clientSecret"));
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,
diff --git a/testsuite/integration/src/test/resources/broker-test/test-broker-realm-with-saml.json b/testsuite/integration/src/test/resources/broker-test/test-broker-realm-with-saml.json
index 5757b28..73d2b2d 100755
--- a/testsuite/integration/src/test/resources/broker-test/test-broker-realm-with-saml.json
+++ b/testsuite/integration/src/test/resources/broker-test/test-broker-realm-with-saml.json
@@ -11,7 +11,7 @@
             "name": "http://localhost:8081/auth/realms/realm-with-broker",
             "enabled": true,
             "redirectUris": [
-                "http://localhost:8081/auth/realms/realm-with-broker/broker/kc-saml-idp-basic"
+                "http://localhost:8081/auth/realms/realm-with-broker/broker/kc-saml-idp-basic/endpoint"
             ],
             "attributes": {
                 "saml.authnstatement": "true"
diff --git a/testsuite/integration/src/test/resources/broker-test/test-broker-realm-with-saml-with-signature.json b/testsuite/integration/src/test/resources/broker-test/test-broker-realm-with-saml-with-signature.json
index db027d8..844bd5e 100755
--- a/testsuite/integration/src/test/resources/broker-test/test-broker-realm-with-saml-with-signature.json
+++ b/testsuite/integration/src/test/resources/broker-test/test-broker-realm-with-saml-with-signature.json
@@ -11,7 +11,7 @@
             "name": "http://localhost:8081/auth/realms/realm-with-broker",
             "enabled": true,
             "redirectUris": [
-                "http://localhost:8081/auth/realms/realm-with-broker/broker/kc-saml-signed-idp"
+                "http://localhost:8081/auth/realms/realm-with-broker/broker/kc-saml-signed-idp/endpoint"
             ],
             "attributes": {
                 "saml.assertion.signature": "true",
diff --git a/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json b/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json
index 73c6668..d08df51 100755
--- a/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json
+++ b/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json
@@ -10,9 +10,8 @@
     "publicKey": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgj8r0029eL0jJKXv6XbNj+QqsZO25HhZ0IjTEtb8mfh0tju/X8c6dXgILh5wU7OF00U+0mSYSE/+rrYKmY5g4oCleTe1+abavATP1tamtXGAUYqdutaXPrVn9yMsCWEPchSPZlEGq5iBJdA+xh9ejUmZJYXmln26HUVWq71/jC9GpjbRmFQ37f0X7WJoGyiqyttfKkKfUeBmRbX/0P0Zm6DVze8HjCDVPBllZE0a3HCgSF0rp0+s1xn7o91qdWKVattAVsGNjjDPz/sgwHOyyhDtSyajwXU+K/QUZ9pV4moGtwC9uIEymTylP7bu7qnxXIhfouEa+fEjAzTs0HJ5JQIDAQAB",
     "identityProviders" : [
         {
-            "id" : "model-google",
+            "alias" : "model-google",
             "providerId" : "google",
-            "name" : "Google",
             "enabled": true,
             "updateProfileFirstLogin" : "true",
             "storeToken": "true",
@@ -22,9 +21,8 @@
             }
         },
         {
-            "id" : "model-facebook",
+            "alias" : "model-facebook",
             "providerId" : "facebook",
-            "name" : "Facebook",
             "enabled": true,
             "updateProfileFirstLogin" : "true",
             "config": {
@@ -36,9 +34,8 @@
             }
         },
         {
-            "id" : "model-github",
+            "alias" : "model-github",
             "providerId" : "github",
-            "name" : "GitHub",
             "enabled": true,
             "updateProfileFirstLogin" : "true",
             "storeToken": "false",
@@ -51,9 +48,8 @@
             }
         },
         {
-            "id" : "model-twitter",
+            "alias" : "model-twitter",
             "providerId" : "twitter",
-            "name" : "Twitter",
             "enabled": true,
             "updateProfileFirstLogin" : "true",
             "storeToken": true,
@@ -66,9 +62,8 @@
             }
         },
         {
-          "id" : "model-saml-signed-idp",
+          "alias" : "model-saml-signed-idp",
           "providerId" : "saml",
-          "name" : "SAML Signed IdP",
           "enabled": true,
           "updateProfileFirstLogin" : "true",
           "config": {
@@ -83,9 +78,8 @@
           }
         },
         {
-            "id" : "kc-saml-signed-idp",
+            "alias" : "kc-saml-signed-idp",
             "providerId" : "saml",
-            "name" : "SAML Signed IdP",
             "enabled": true,
             "updateProfileFirstLogin" : "true",
             "config": {
@@ -100,9 +94,8 @@
             }
         },
         {
-            "id" : "kc-saml-idp-basic",
+            "alias" : "kc-saml-idp-basic",
             "providerId" : "saml",
-            "name" : "SAML Signed IdP",
             "enabled": true,
             "updateProfileFirstLogin" : "true",
             "config": {
@@ -114,9 +107,8 @@
             }
         },
         {
-            "id" : "model-oidc-idp",
+            "alias" : "model-oidc-idp",
             "providerId" : "oidc",
-            "name" : "OIDC IdP",
             "enabled": false,
             "updateProfileFirstLogin" : "false",
             "authenticateByDefault" : "false",
@@ -131,9 +123,8 @@
             }
         },
         {
-            "id" : "kc-oidc-idp",
+            "alias" : "kc-oidc-idp",
             "providerId" : "oidc",
-            "name" : "KeyCloak OIDC IdP",
             "enabled": true,
             "updateProfileFirstLogin" : "false",
             "config": {
@@ -147,9 +138,8 @@
             }
         },
         {
-            "id" : "model-kerberos",
+            "alias" : "model-kerberos",
             "providerId" : "kerberos",
-            "name" : "Kerberos",
             "enabled": true,
             "updateProfileFirstLogin" : "true",
             "authenticateByDefault" : "false",
diff --git a/testsuite/integration/src/test/resources/model/testrealm.json b/testsuite/integration/src/test/resources/model/testrealm.json
index f43c7fc..4044399 100755
--- a/testsuite/integration/src/test/resources/model/testrealm.json
+++ b/testsuite/integration/src/test/resources/model/testrealm.json
@@ -15,8 +15,7 @@
     "identityProviders" : [
         {
             "providerId" : "google",
-            "id" : "google1",
-            "name" : "Google",
+            "alias" : "google1",
             "enabled": true,
             "config": {
                 "clientId": "googleId",
diff --git a/testsuite/integration/src/test/resources/saml/testsaml.json b/testsuite/integration/src/test/resources/saml/testsaml.json
index cac873b..ed67040 100755
--- a/testsuite/integration/src/test/resources/saml/testsaml.json
+++ b/testsuite/integration/src/test/resources/saml/testsaml.json
@@ -45,10 +45,10 @@
             ],
             "attributes": {
                 "saml.authnstatement": "true",
-                "saml_assertion_consumer_url_post": "http://localhost:8081/sales-post",
-                "saml_assertion_consumer_url_redirect": "http://localhost:8081/sales-post",
-                "saml_single_logout_service_url_post": "http://localhost:8081/sales-post",
-                "saml_single_logout_service_url_redirect": "http://localhost:8081/sales-post"
+                "saml_assertion_consumer_url_post": "http://localhost:8081/sales-post/",
+                "saml_assertion_consumer_url_redirect": "http://localhost:8081/sales-post/",
+                "saml_single_logout_service_url_post": "http://localhost:8081/sales-post/",
+                "saml_single_logout_service_url_redirect": "http://localhost:8081/sales-post/"
             }
         },
         {
@@ -61,10 +61,10 @@
                 "http://localhost:8081/sales-post-sig/*"
             ],
             "attributes": {
-                "saml_assertion_consumer_url_post": "http://localhost:8081/sales-post-sig",
-                "saml_assertion_consumer_url_redirect": "http://localhost:8081/sales-post-sig",
-                "saml_single_logout_service_url_post": "http://localhost:8081/sales-post-sig",
-                "saml_single_logout_service_url_redirect": "http://localhost:8081/sales-post-sig",
+                "saml_assertion_consumer_url_post": "http://localhost:8081/sales-post-sig/",
+                "saml_assertion_consumer_url_redirect": "http://localhost:8081/sales-post-sig/",
+                "saml_single_logout_service_url_post": "http://localhost:8081/sales-post-sig/",
+                "saml_single_logout_service_url_redirect": "http://localhost:8081/sales-post-sig/",
                 "saml.server.signature": "true",
                 "saml.signature.algorithm": "RSA_SHA256",
                 "saml.client.signature": "true",
@@ -84,10 +84,10 @@
                 "http://localhost:8081/sales-post-sig-transient/*"
             ],
             "attributes": {
-                "saml_assertion_consumer_url_post": "http://localhost:8081/sales-post-sig-transient",
-                "saml_assertion_consumer_url_redirect": "http://localhost:8081/sales-post-sig-transient",
-                "saml_single_logout_service_url_post": "http://localhost:8081/sales-post-sig-transient",
-                "saml_single_logout_service_url_redirect": "http://localhost:8081/sales-post-sig-transient",
+                "saml_assertion_consumer_url_post": "http://localhost:8081/sales-post-sig-transient/",
+                "saml_assertion_consumer_url_redirect": "http://localhost:8081/sales-post-sig-transient/",
+                "saml_single_logout_service_url_post": "http://localhost:8081/sales-post-sig-transient/",
+                "saml_single_logout_service_url_redirect": "http://localhost:8081/sales-post-sig-transient/",
                 "saml.server.signature": "true",
                 "saml.signature.algorithm": "RSA_SHA256",
                 "saml.client.signature": "true",
@@ -106,10 +106,10 @@
                 "http://localhost:8081/sales-post-sig-persistent/*"
             ],
             "attributes": {
-                "saml_assertion_consumer_url_post": "http://localhost:8081/sales-post-sig-persistent",
-                "saml_assertion_consumer_url_redirect": "http://localhost:8081/sales-post-sig-persistent",
-                "saml_single_logout_service_url_post": "http://localhost:8081/sales-post-sig-persistent",
-                "saml_single_logout_service_url_redirect": "http://localhost:8081/sales-post-sig-persistent",
+                "saml_assertion_consumer_url_post": "http://localhost:8081/sales-post-sig-persistent/",
+                "saml_assertion_consumer_url_redirect": "http://localhost:8081/sales-post-sig-persistent/",
+                "saml_single_logout_service_url_post": "http://localhost:8081/sales-post-sig-persistent/",
+                "saml_single_logout_service_url_redirect": "http://localhost:8081/sales-post-sig-persistent/",
                 "saml.server.signature": "true",
                 "saml.signature.algorithm": "RSA_SHA256",
                 "saml.client.signature": "true",
@@ -131,10 +131,10 @@
             "attributes": {
                 "saml_force_name_id_format": "true",
                 "saml_name_id_format": "email",
-                "saml_assertion_consumer_url_post": "http://localhost:8081/sales-post-sig-email",
-                "saml_assertion_consumer_url_redirect": "http://localhost:8081/sales-post-sig-email",
-                "saml_single_logout_service_url_post": "http://localhost:8081/sales-post-sig-email",
-                "saml_single_logout_service_url_redirect": "http://localhost:8081/sales-post-sig-email",
+                "saml_assertion_consumer_url_post": "http://localhost:8081/sales-post-sig-email/",
+                "saml_assertion_consumer_url_redirect": "http://localhost:8081/sales-post-sig-email/",
+                "saml_single_logout_service_url_post": "http://localhost:8081/sales-post-sig-email/",
+                "saml_single_logout_service_url_redirect": "http://localhost:8081/sales-post-sig-email/",
                 "saml.server.signature": "true",
                 "saml.signature.algorithm": "RSA_SHA256",
                 "saml.client.signature": "true",
@@ -148,8 +148,8 @@
             "enabled": true,
             "protocol": "saml",
             "fullScopeAllowed": true,
-            "baseUrl": "http://localhost:8081/bad-realm-sales-post-sig",
-            "adminUrl": "http://localhost:8081/bad-realm-sales-post-sig",
+            "baseUrl": "http://localhost:8081/bad-realm-sales-post-sig/",
+            "adminUrl": "http://localhost:8081/bad-realm-sales-post-sig/",
             "redirectUris": [
                 "http://localhost:8081/bad-realm-sales-post-sig/*"
             ],
@@ -166,8 +166,8 @@
             "enabled": true,
             "protocol": "saml",
             "fullScopeAllowed": true,
-            "baseUrl": "http://localhost:8081/bad-client-sales-post-sig",
-            "adminUrl": "http://localhost:8081/bad-client-sales-post-sig",
+            "baseUrl": "http://localhost:8081/bad-client-sales-post-sig/",
+            "adminUrl": "http://localhost:8081/bad-client-sales-post-sig/",
             "redirectUris": [
                 "http://localhost:8081/bad-client-sales-post-sig/*"
             ],
@@ -189,10 +189,10 @@
                 "http://localhost:8081/sales-post-enc/*"
             ],
             "attributes": {
-                "saml_assertion_consumer_url_post": "http://localhost:8081/sales-post-enc",
-                "saml_assertion_consumer_url_redirect": "http://localhost:8081/sales-post-enc",
-                "saml_single_logout_service_url_post": "http://localhost:8081/sales-post-enc",
-                "saml_single_logout_service_url_redirect": "http://localhost:8081/sales-post-enc",
+                "saml_assertion_consumer_url_post": "http://localhost:8081/sales-post-enc/",
+                "saml_assertion_consumer_url_redirect": "http://localhost:8081/sales-post-enc/",
+                "saml_single_logout_service_url_post": "http://localhost:8081/sales-post-enc/",
+                "saml_single_logout_service_url_redirect": "http://localhost:8081/sales-post-enc/",
                 "saml.server.signature": "true",
                 "saml.signature.algorithm": "RSA_SHA512",
                 "saml.client.signature": "true",
@@ -213,7 +213,7 @@
             "redirectUris": [
                 "http://localhost:8081/employee-sig/*"
             ],
-            "adminUrl": "http://localhost:8081/employee-sig",
+            "adminUrl": "http://localhost:8081/employee-sig/",
             "attributes": {
                 "saml.server.signature": "true",
                 "saml.client.signature": "true",
@@ -279,15 +279,15 @@
             "protocol": "saml",
             "fullScopeAllowed": true,
             "frontchannelLogout": true,
-            "baseUrl": "http://localhost:8081/employee-sig-front",
+            "baseUrl": "http://localhost:8081/employee-sig-front/",
             "redirectUris": [
                 "http://localhost:8081/employee-sig-front/*"
             ],
             "attributes": {
-                "saml_assertion_consumer_url_post": "http://localhost:8081/employee-sig-front",
-                "saml_assertion_consumer_url_redirect": "http://localhost:8081/employee-sig-front",
-                "saml_single_logout_service_url_post": "http://localhost:8081/employee-sig-front",
-                "saml_single_logout_service_url_redirect": "http://localhost:8081/employee-sig-front",
+                "saml_assertion_consumer_url_post": "http://localhost:8081/employee-sig-front/",
+                "saml_assertion_consumer_url_redirect": "http://localhost:8081/employee-sig-front/",
+                "saml_single_logout_service_url_post": "http://localhost:8081/employee-sig-front/",
+                "saml_single_logout_service_url_redirect": "http://localhost:8081/employee-sig-front/",
                 "saml.server.signature": "true",
                 "saml.client.signature": "true",
                 "saml.signature.algorithm": "RSA_SHA1",