keycloak-uncached

Merge pull request #1175 from patriot1burke/master broker

4/23/2015 1:08:12 PM

Changes

Details

diff --git a/broker/oidc/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProvider.java b/broker/oidc/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProvider.java
index 745e16d..72c39f1 100755
--- a/broker/oidc/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProvider.java
+++ b/broker/oidc/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProvider.java
@@ -129,8 +129,9 @@ public class OIDCIdentityProvider extends AbstractOAuth2IdentityProvider<OIDCIde
     @Override
     public Response keycloakInitiatedBrowserLogout(UserSessionModel userSession, UriInfo uriInfo, RealmModel realm) {
         if (getConfig().getLogoutUrl() == null || getConfig().getLogoutUrl().trim().equals("")) return null;
+        String sessionId = userSession.getId();
         UriBuilder logoutUri = UriBuilder.fromUri(getConfig().getLogoutUrl())
-                                         .queryParam("state", userSession.getId());
+                                         .queryParam("state", sessionId);
         String idToken = userSession.getNote(FEDERATED_ID_TOKEN);
         if (idToken != null) logoutUri.queryParam("id_token_hint", idToken);
         String redirect = RealmsResource.brokerUrl(uriInfo)
diff --git a/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLEndpoint.java b/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLEndpoint.java
index e2a1902..b3efc97 100755
--- a/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLEndpoint.java
+++ b/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLEndpoint.java
@@ -7,6 +7,8 @@ import org.keycloak.broker.provider.BrokeredIdentityContext;
 import org.keycloak.broker.provider.IdentityBrokerException;
 import org.keycloak.broker.provider.IdentityProvider;
 import org.keycloak.dom.saml.v2.assertion.AssertionType;
+import org.keycloak.dom.saml.v2.assertion.AttributeStatementType;
+import org.keycloak.dom.saml.v2.assertion.AttributeType;
 import org.keycloak.dom.saml.v2.assertion.AuthnStatementType;
 import org.keycloak.dom.saml.v2.assertion.EncryptedAssertionType;
 import org.keycloak.dom.saml.v2.assertion.NameIDType;
@@ -36,6 +38,7 @@ import org.keycloak.saml.common.util.StaxParserUtil;
 import org.keycloak.saml.processing.api.saml.v2.response.SAML2Response;
 import org.keycloak.saml.processing.core.parsers.saml.SAMLParser;
 import org.keycloak.saml.processing.core.saml.v2.common.SAMLDocumentHolder;
+import org.keycloak.saml.processing.core.saml.v2.constants.X500SAMLProfileConstants;
 import org.keycloak.saml.processing.core.util.JAXPValidationUtil;
 import org.keycloak.saml.processing.core.util.XMLEncryptionUtil;
 import org.keycloak.saml.processing.core.util.XMLSignatureUtil;
@@ -295,6 +298,19 @@ public class SAMLEndpoint {
                         break;
                     }
                 }
+                if (assertion.getAttributeStatements() != null ) {
+                    for (AttributeStatementType attrStatement : assertion.getAttributeStatements()) {
+                        for (AttributeStatementType.ASTChoiceType choice : attrStatement.getAttributes()) {
+                            AttributeType attribute = choice.getAttribute();
+                            if (X500SAMLProfileConstants.EMAIL.getFriendlyName().equals(attribute.getFriendlyName())
+                                    || X500SAMLProfileConstants.EMAIL.get().equals(attribute.getName())) {
+                                if (!attribute.getAttributeValue().isEmpty()) identity.setEmail(attribute.getAttributeValue().get(0).toString());
+                            }
+                        }
+
+                    }
+
+                }
                 String brokerUserId = config.getAlias() + "." + subjectNameID.getValue();
                 identity.setBrokerUserId(brokerUserId);
                 identity.setIdpConfig(config);
diff --git a/model/api/src/main/java/org/keycloak/migration/MigrationProvider.java b/model/api/src/main/java/org/keycloak/migration/MigrationProvider.java
old mode 100644
new mode 100755
index 784ba8e..7ba3bb7
--- a/model/api/src/main/java/org/keycloak/migration/MigrationProvider.java
+++ b/model/api/src/main/java/org/keycloak/migration/MigrationProvider.java
@@ -1,9 +1,10 @@
 package org.keycloak.migration;
 
-import java.util.List;
 import org.keycloak.provider.Provider;
 import org.keycloak.representations.idm.ProtocolMapperRepresentation;
 
+import java.util.List;
+
 /**
  * Various common utils needed for migration from older version to newer
  *
diff --git a/model/api/src/main/java/org/keycloak/models/ClientModel.java b/model/api/src/main/java/org/keycloak/models/ClientModel.java
index 026e35e..2382f55 100755
--- a/model/api/src/main/java/org/keycloak/models/ClientModel.java
+++ b/model/api/src/main/java/org/keycloak/models/ClientModel.java
@@ -116,10 +116,6 @@ public interface ClientModel extends RoleContainerModel {
 
     void setNotBefore(int notBefore);
 
-    void updateIdentityProviders(List<ClientIdentityProviderMappingModel> identityProviders);
-    List<ClientIdentityProviderMappingModel> getIdentityProviders();
-    boolean isAllowedRetrieveTokenFromIdentityProvider(String providerId);
-
     Set<ProtocolMapperModel> getProtocolMappers();
     ProtocolMapperModel addProtocolMapper(ProtocolMapperModel model);
     void removeProtocolMapper(ProtocolMapperModel mapping);
diff --git a/model/api/src/main/java/org/keycloak/models/Constants.java b/model/api/src/main/java/org/keycloak/models/Constants.java
index edba3e3..08cf4ee 100755
--- a/model/api/src/main/java/org/keycloak/models/Constants.java
+++ b/model/api/src/main/java/org/keycloak/models/Constants.java
@@ -8,6 +8,7 @@ public interface Constants {
     String ADMIN_CONSOLE_CLIENT_ID = "security-admin-console";
 
     String ACCOUNT_MANAGEMENT_CLIENT_ID = "account";
+    String BROKER_SERVICE_CLIENT_ID = "broker";
 
     String INSTALLED_APP_URN = "urn:ietf:wg:oauth:2.0:oob";
     String INSTALLED_APP_URL = "http://localhost";
diff --git a/model/api/src/main/java/org/keycloak/models/entities/ProtocolMapperEntity.java b/model/api/src/main/java/org/keycloak/models/entities/ProtocolMapperEntity.java
index 21330e5..29ffca2 100755
--- a/model/api/src/main/java/org/keycloak/models/entities/ProtocolMapperEntity.java
+++ b/model/api/src/main/java/org/keycloak/models/entities/ProtocolMapperEntity.java
@@ -1,7 +1,5 @@
 package org.keycloak.models.entities;
 
-import org.keycloak.models.ProtocolMapperModel;
-
 import java.util.Map;
 
 /**
diff --git a/model/api/src/main/java/org/keycloak/models/PasswordPolicy.java b/model/api/src/main/java/org/keycloak/models/PasswordPolicy.java
index ed2282c..26ff18e 100755
--- a/model/api/src/main/java/org/keycloak/models/PasswordPolicy.java
+++ b/model/api/src/main/java/org/keycloak/models/PasswordPolicy.java
@@ -1,5 +1,7 @@
 package org.keycloak.models;
 
+import org.keycloak.models.utils.Pbkdf2PasswordEncoder;
+
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
@@ -8,8 +10,6 @@ import java.util.List;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import org.keycloak.models.utils.Pbkdf2PasswordEncoder;
-
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
  */
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 9f66440..63be7f0 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
@@ -1,7 +1,6 @@
 package org.keycloak.models.utils;
 
 import org.keycloak.models.ClientModel;
-import org.keycloak.models.ClientIdentityProviderMappingModel;
 import org.keycloak.models.ClientSessionModel;
 import org.keycloak.models.FederatedIdentityModel;
 import org.keycloak.models.IdentityProviderMapperModel;
@@ -14,8 +13,6 @@ import org.keycloak.models.UserCredentialModel;
 import org.keycloak.models.UserFederationProviderModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.UserSessionModel;
-import org.keycloak.representations.idm.ApplicationRepresentation;
-import org.keycloak.representations.idm.ClientIdentityProviderMappingRepresentation;
 import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.representations.idm.CredentialRepresentation;
 import org.keycloak.representations.idm.FederatedIdentityRepresentation;
@@ -261,10 +258,6 @@ public class ModelToRepresentation {
             rep.setRegisteredNodes(new HashMap<>(clientModel.getRegisteredNodes()));
         }
 
-        if (!clientModel.getIdentityProviders().isEmpty()) {
-            rep.setIdentityProviders(toRepresentation(clientModel.getIdentityProviders()));
-        }
-
         if (!clientModel.getProtocolMappers().isEmpty()) {
             List<ProtocolMapperRepresentation> mappings = new LinkedList<>();
             for (ProtocolMapperModel model : clientModel.getProtocolMappers()) {
@@ -276,21 +269,6 @@ public class ModelToRepresentation {
         return rep;
     }
 
-    private static List<ClientIdentityProviderMappingRepresentation> toRepresentation(List<ClientIdentityProviderMappingModel> identityProviders) {
-        ArrayList<ClientIdentityProviderMappingRepresentation> representations = new ArrayList<ClientIdentityProviderMappingRepresentation>();
-
-        for (ClientIdentityProviderMappingModel model : identityProviders) {
-            ClientIdentityProviderMappingRepresentation representation = new ClientIdentityProviderMappingRepresentation();
-
-            representation.setId(model.getIdentityProvider());
-            representation.setRetrieveToken(model.isRetrieveToken());
-
-            representations.add(representation);
-        }
-
-        return representations;
-    }
-
     public static UserFederationProviderRepresentation toRepresentation(UserFederationProviderModel model) {
         UserFederationProviderRepresentation rep = new UserFederationProviderRepresentation();
         rep.setId(model.getId());
diff --git a/model/api/src/main/java/org/keycloak/models/utils/reflection/MethodPropertyImpl.java b/model/api/src/main/java/org/keycloak/models/utils/reflection/MethodPropertyImpl.java
old mode 100644
new mode 100755
index 6fa8786..7e2952e
--- a/model/api/src/main/java/org/keycloak/models/utils/reflection/MethodPropertyImpl.java
+++ b/model/api/src/main/java/org/keycloak/models/utils/reflection/MethodPropertyImpl.java
@@ -1,13 +1,13 @@
 package org.keycloak.models.utils.reflection;
 
+import org.keycloak.util.reflections.Reflections;
+
 import java.beans.Introspector;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Member;
 import java.lang.reflect.Method;
 import java.lang.reflect.Type;
 
-import org.keycloak.util.reflections.Reflections;
-
 /**
  * A bean property based on the value represented by a getter/setter method pair
  */
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 0312ff4..282d376 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
@@ -6,7 +6,6 @@ import org.keycloak.enums.SslRequired;
 import org.keycloak.migration.MigrationProvider;
 import org.keycloak.models.BrowserSecurityHeaders;
 import org.keycloak.models.ClaimMask;
-import org.keycloak.models.ClientIdentityProviderMappingModel;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.FederatedIdentityModel;
 import org.keycloak.models.IdentityProviderMapperModel;
@@ -23,7 +22,6 @@ import org.keycloak.models.UserFederationProviderModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.representations.idm.ApplicationRepresentation;
 import org.keycloak.representations.idm.ClaimRepresentation;
-import org.keycloak.representations.idm.ClientIdentityProviderMappingRepresentation;
 import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.representations.idm.CredentialRepresentation;
 import org.keycloak.representations.idm.FederatedIdentityRepresentation;
@@ -41,7 +39,6 @@ import org.keycloak.representations.idm.UserRepresentation;
 import org.keycloak.util.UriUtils;
 
 import java.io.IOException;
-import java.net.URI;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -612,8 +609,6 @@ public class RepresentationToModel {
             }
         }
 
-        client.updateIdentityProviders(toModel(resourceRep.getIdentityProviders(), realm));
-
         return client;
     }
 
@@ -662,7 +657,6 @@ public class RepresentationToModel {
             }
         }
 
-        updateClientIdentityProviders(rep.getIdentityProviders(), resource);
     }
 
     public static long getClaimsMask(ClaimRepresentation rep) {
@@ -918,37 +912,4 @@ public class RepresentationToModel {
         return model;
     }
 
-    private static List<ClientIdentityProviderMappingModel> toModel(List<ClientIdentityProviderMappingRepresentation> repIdentityProviders, RealmModel realm) {
-        List<ClientIdentityProviderMappingModel> result = new ArrayList<ClientIdentityProviderMappingModel>();
-
-        if (repIdentityProviders != null) {
-            for (ClientIdentityProviderMappingRepresentation rep : repIdentityProviders) {
-                ClientIdentityProviderMappingModel identityProviderMapping = new ClientIdentityProviderMappingModel();
-
-                identityProviderMapping.setIdentityProvider(rep.getId());
-                identityProviderMapping.setRetrieveToken(rep.isRetrieveToken());
-
-                result.add(identityProviderMapping);
-            }
-        }
-
-        return result;
-    }
-
-    private static void updateClientIdentityProviders(List<ClientIdentityProviderMappingRepresentation> identityProviders, ClientModel resource) {
-        if (identityProviders != null) {
-            List<ClientIdentityProviderMappingModel> result = new ArrayList<ClientIdentityProviderMappingModel>();
-
-            for (ClientIdentityProviderMappingRepresentation mappingRepresentation : identityProviders) {
-                ClientIdentityProviderMappingModel identityProviderMapping = new ClientIdentityProviderMappingModel();
-
-                identityProviderMapping.setIdentityProvider(mappingRepresentation.getId());
-                identityProviderMapping.setRetrieveToken(mappingRepresentation.isRetrieveToken());
-
-                result.add(identityProviderMapping);
-            }
-
-            resource.updateIdentityProviders(result);
-        }
-    }
 }
diff --git a/model/api/src/main/java/org/keycloak/provider/ConfiguredProvider.java b/model/api/src/main/java/org/keycloak/provider/ConfiguredProvider.java
index d37afcd..c737306 100755
--- a/model/api/src/main/java/org/keycloak/provider/ConfiguredProvider.java
+++ b/model/api/src/main/java/org/keycloak/provider/ConfiguredProvider.java
@@ -1,7 +1,5 @@
 package org.keycloak.provider;
 
-import org.keycloak.provider.ProviderConfigProperty;
-
 import java.util.List;
 
 /**
diff --git a/model/api/src/main/java/org/keycloak/provider/ProviderEventManager.java b/model/api/src/main/java/org/keycloak/provider/ProviderEventManager.java
index efdfa82..dfe6782 100755
--- a/model/api/src/main/java/org/keycloak/provider/ProviderEventManager.java
+++ b/model/api/src/main/java/org/keycloak/provider/ProviderEventManager.java
@@ -1,8 +1,5 @@
 package org.keycloak.provider;
 
-import org.keycloak.provider.ProviderEvent;
-import org.keycloak.provider.ProviderEventListener;
-
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
diff --git a/model/api/src/test/java/org/keycloak/models/PasswordPolicyTest.java b/model/api/src/test/java/org/keycloak/models/PasswordPolicyTest.java
old mode 100644
new mode 100755
index 14f28fb..d091dca
--- a/model/api/src/test/java/org/keycloak/models/PasswordPolicyTest.java
+++ b/model/api/src/test/java/org/keycloak/models/PasswordPolicyTest.java
@@ -1,11 +1,11 @@
 package org.keycloak.models;
 
-import static org.junit.Assert.fail;
+import org.junit.Assert;
+import org.junit.Test;
 
 import java.util.regex.PatternSyntaxException;
 
-import org.junit.Assert;
-import org.junit.Test;
+import static org.junit.Assert.fail;
 
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
diff --git a/model/file/src/main/java/org/keycloak/models/file/adapter/ClientAdapter.java b/model/file/src/main/java/org/keycloak/models/file/adapter/ClientAdapter.java
index 34ddb06..7068a26 100755
--- a/model/file/src/main/java/org/keycloak/models/file/adapter/ClientAdapter.java
+++ b/model/file/src/main/java/org/keycloak/models/file/adapter/ClientAdapter.java
@@ -16,12 +16,18 @@
  */
 package org.keycloak.models.file.adapter;
 
+import org.keycloak.connections.file.InMemoryModel;
 import org.keycloak.models.ClientModel;
-import org.keycloak.models.ClientIdentityProviderMappingModel;
 import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.ModelDuplicateException;
 import org.keycloak.models.ProtocolMapperModel;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.entities.ClientEntity;
+import org.keycloak.models.entities.ProtocolMapperEntity;
+import org.keycloak.models.entities.RoleEntity;
+import org.keycloak.models.utils.KeycloakModelUtils;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -30,14 +36,6 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import org.keycloak.connections.file.InMemoryModel;
-import org.keycloak.models.ModelDuplicateException;
-import org.keycloak.models.UserModel;
-import org.keycloak.models.entities.ClientEntity;
-import org.keycloak.models.entities.ClientIdentityProviderMappingEntity;
-import org.keycloak.models.entities.ProtocolMapperEntity;
-import org.keycloak.models.entities.RoleEntity;
-import org.keycloak.models.utils.KeycloakModelUtils;
 
 /**
  * ApplicationModel used for JSON persistence.
@@ -364,48 +362,6 @@ public class ClientAdapter implements ClientModel {
     }
 
     @Override
-    public void updateIdentityProviders(List<ClientIdentityProviderMappingModel> identityProviders) {
-        List<ClientIdentityProviderMappingEntity> stored = new ArrayList<ClientIdentityProviderMappingEntity>();
-
-        for (ClientIdentityProviderMappingModel model : identityProviders) {
-            ClientIdentityProviderMappingEntity entity = new ClientIdentityProviderMappingEntity();
-
-            entity.setId(model.getIdentityProvider());
-            entity.setRetrieveToken(model.isRetrieveToken());
-            stored.add(entity);
-        }
-
-        entity.setIdentityProviders(stored);
-    }
-
-    @Override
-    public List<ClientIdentityProviderMappingModel> getIdentityProviders() {
-        List<ClientIdentityProviderMappingModel> models = new ArrayList<>();
-
-        for (ClientIdentityProviderMappingEntity e : entity.getIdentityProviders()) {
-            ClientIdentityProviderMappingModel model = new ClientIdentityProviderMappingModel();
-
-            model.setIdentityProvider(e.getId());
-            model.setRetrieveToken(e.isRetrieveToken());
-
-            models.add(model);
-        }
-
-        return models;
-    }
-
-    @Override
-    public boolean isAllowedRetrieveTokenFromIdentityProvider(String providerId) {
-        for (ClientIdentityProviderMappingEntity identityProviderMappingModel : entity.getIdentityProviders()) {
-            if (identityProviderMappingModel.getId().equals(providerId)) {
-                return identityProviderMappingModel.isRetrieveToken();
-            }
-        }
-
-        return false;
-    }
-
-    @Override
     public String getClientId() {
         return entity.getClientId();
     }
diff --git a/model/file/src/main/java/org/keycloak/models/file/adapter/RoleAdapter.java b/model/file/src/main/java/org/keycloak/models/file/adapter/RoleAdapter.java
index f53c0ce..9448def 100755
--- a/model/file/src/main/java/org/keycloak/models/file/adapter/RoleAdapter.java
+++ b/model/file/src/main/java/org/keycloak/models/file/adapter/RoleAdapter.java
@@ -16,18 +16,18 @@
  */
 package org.keycloak.models.file.adapter;
 
-import java.util.ArrayList;
-import java.util.Collections;
+import org.keycloak.models.ModelDuplicateException;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleContainerModel;
 import org.keycloak.models.RoleModel;
+import org.keycloak.models.entities.RoleEntity;
 import org.keycloak.models.utils.KeycloakModelUtils;
 
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
-import org.keycloak.models.ModelDuplicateException;
-import org.keycloak.models.entities.RoleEntity;
 
 /**
  * RoleModel for JSON persistence.
diff --git a/model/file/src/main/java/org/keycloak/models/file/adapter/UserAdapter.java b/model/file/src/main/java/org/keycloak/models/file/adapter/UserAdapter.java
index 0937e2c..6e622cc 100755
--- a/model/file/src/main/java/org/keycloak/models/file/adapter/UserAdapter.java
+++ b/model/file/src/main/java/org/keycloak/models/file/adapter/UserAdapter.java
@@ -16,10 +16,12 @@
  */
 package org.keycloak.models.file.adapter;
 
+import org.keycloak.connections.file.InMemoryModel;
 import org.keycloak.models.ClientModel;
 
 import static org.keycloak.models.utils.Pbkdf2PasswordEncoder.getSalt;
 
+import org.keycloak.models.ModelDuplicateException;
 import org.keycloak.models.UserConsentModel;
 import org.keycloak.models.PasswordPolicy;
 import org.keycloak.models.RealmModel;
@@ -28,7 +30,11 @@ import org.keycloak.models.UserCredentialModel;
 import org.keycloak.models.UserCredentialValueModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.entities.CredentialEntity;
+import org.keycloak.models.entities.FederatedIdentityEntity;
+import org.keycloak.models.entities.RoleEntity;
+import org.keycloak.models.entities.UserEntity;
 import org.keycloak.models.utils.Pbkdf2PasswordEncoder;
+import org.keycloak.util.Time;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -39,12 +45,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
-import org.keycloak.connections.file.InMemoryModel;
-import org.keycloak.models.ModelDuplicateException;
-import org.keycloak.models.entities.FederatedIdentityEntity;
-import org.keycloak.models.entities.RoleEntity;
-import org.keycloak.models.entities.UserEntity;
-import org.keycloak.util.Time;
+import static org.keycloak.models.utils.Pbkdf2PasswordEncoder.getSalt;
 
 /**
  * UserModel for JSON persistence.
diff --git a/model/file/src/main/java/org/keycloak/models/file/FileUserProvider.java b/model/file/src/main/java/org/keycloak/models/file/FileUserProvider.java
old mode 100644
new mode 100755
index 5c50a59..8dd783d
--- a/model/file/src/main/java/org/keycloak/models/file/FileUserProvider.java
+++ b/model/file/src/main/java/org/keycloak/models/file/FileUserProvider.java
@@ -16,34 +16,33 @@
  */
 package org.keycloak.models.file;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-
-import org.keycloak.models.ProtocolMapperModel;
-import org.keycloak.models.file.adapter.UserAdapter;
+import org.keycloak.connections.file.FileConnectionProvider;
+import org.keycloak.connections.file.InMemoryModel;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.CredentialValidationOutput;
 import org.keycloak.models.FederatedIdentityModel;
 import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.ModelDuplicateException;
+import org.keycloak.models.ProtocolMapperModel;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleModel;
 import org.keycloak.models.UserCredentialModel;
 import org.keycloak.models.UserFederationProviderModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.UserProvider;
+import org.keycloak.models.entities.FederatedIdentityEntity;
+import org.keycloak.models.entities.UserEntity;
+import org.keycloak.models.file.adapter.UserAdapter;
+import org.keycloak.models.utils.CredentialValidation;
 import org.keycloak.models.utils.KeycloakModelUtils;
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.regex.Pattern;
-import org.keycloak.connections.file.FileConnectionProvider;
-import org.keycloak.connections.file.InMemoryModel;
-import org.keycloak.models.ClientModel;
-import org.keycloak.models.CredentialValidationOutput;
-import org.keycloak.models.ModelDuplicateException;
-import org.keycloak.models.entities.FederatedIdentityEntity;
-import org.keycloak.models.entities.UserEntity;
-import org.keycloak.models.utils.CredentialValidation;
 
 /**
  * UserProvider for JSON persistence.
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/ClientAdapter.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/ClientAdapter.java
index 436405e..4dc4a03 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/ClientAdapter.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/ClientAdapter.java
@@ -1,7 +1,6 @@
 package org.keycloak.models.cache;
 
 import org.keycloak.models.ClientModel;
-import org.keycloak.models.ClientIdentityProviderMappingModel;
 import org.keycloak.models.ProtocolMapperModel;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleContainerModel;
@@ -250,24 +249,6 @@ public class ClientAdapter implements ClientModel {
     }
 
     @Override
-    public void updateIdentityProviders(List<ClientIdentityProviderMappingModel> identityProviders) {
-        getDelegateForUpdate();
-        updated.updateIdentityProviders(identityProviders);
-    }
-
-    @Override
-    public List<ClientIdentityProviderMappingModel> getIdentityProviders() {
-        if (updated != null) return updated.getIdentityProviders();
-        return cached.getIdentityProviders();
-    }
-
-    @Override
-    public boolean isAllowedRetrieveTokenFromIdentityProvider(String providerId) {
-        if (updated != null) return updated.isAllowedRetrieveTokenFromIdentityProvider(providerId);
-        return cached.isAllowedRetrieveTokenFromIdentityProvider(providerId);
-    }
-
-    @Override
     public Set<ProtocolMapperModel> getProtocolMappers() {
         if (updated != null) return updated.getProtocolMappers();
         return cached.getProtocolMappers();
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/DefaultCacheUserProvider.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/DefaultCacheUserProvider.java
index 16c77d1..a37e2a4 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/DefaultCacheUserProvider.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/DefaultCacheUserProvider.java
@@ -2,12 +2,12 @@ package org.keycloak.models.cache;
 
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.CredentialValidationOutput;
+import org.keycloak.models.FederatedIdentityModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.KeycloakTransaction;
 import org.keycloak.models.ProtocolMapperModel;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleModel;
-import org.keycloak.models.FederatedIdentityModel;
 import org.keycloak.models.UserCredentialModel;
 import org.keycloak.models.UserFederationProviderModel;
 import org.keycloak.models.UserModel;
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClient.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClient.java
index c586927..58d3cb0 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClient.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClient.java
@@ -1,14 +1,12 @@
 package org.keycloak.models.cache.entities;
 
 import org.keycloak.models.ClientModel;
-import org.keycloak.models.ClientIdentityProviderMappingModel;
 import org.keycloak.models.ProtocolMapperModel;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.RealmProvider;
 import org.keycloak.models.RoleModel;
 import org.keycloak.models.cache.RealmCache;
 
-import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedList;
@@ -37,7 +35,6 @@ public class CachedClient {
     private int notBefore;
     private Set<String> scope = new HashSet<String>();
     private Set<String> webOrigins = new HashSet<String>();
-    private List<ClientIdentityProviderMappingModel> identityProviders = new ArrayList<ClientIdentityProviderMappingModel>();
     private Set<ProtocolMapperModel> protocolMappers = new HashSet<ProtocolMapperModel>();
     private boolean surrogateAuthRequired;
     private String managementUrl;
@@ -67,7 +64,6 @@ public class CachedClient {
         for (RoleModel role : model.getScopeMappings())  {
             scope.add(role.getId());
         }
-        this.identityProviders = model.getIdentityProviders();
         for (ProtocolMapperModel mapper : model.getProtocolMappers()) {
             this.protocolMappers.add(mapper);
         }
@@ -145,34 +141,10 @@ public class CachedClient {
         return frontchannelLogout;
     }
 
-    public List<ClientIdentityProviderMappingModel> getIdentityProviders() {
-        return this.identityProviders;
-    }
-
-    public boolean hasIdentityProvider(String providerId) {
-        for (ClientIdentityProviderMappingModel model : getIdentityProviders()) {
-            if (model.getIdentityProvider().equals(providerId)) {
-                return true;
-            }
-        }
-
-        return false;
-    }
-
     public Set<ProtocolMapperModel> getProtocolMappers() {
         return protocolMappers;
     }
 
-    public boolean isAllowedRetrieveTokenFromIdentityProvider(String providerId) {
-        for (ClientIdentityProviderMappingModel model : getIdentityProviders()) {
-            if (model.getIdentityProvider().equals(providerId)) {
-                return model.isRetrieveToken();
-            }
-        }
-
-        return false;
-    }
-
     public boolean isSurrogateAuthRequired() {
         return surrogateAuthRequired;
     }
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/NoCacheUserProvider.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/NoCacheUserProvider.java
index b0b7069..5cf96ec 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/NoCacheUserProvider.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/NoCacheUserProvider.java
@@ -2,11 +2,11 @@ package org.keycloak.models.cache;
 
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.CredentialValidationOutput;
+import org.keycloak.models.FederatedIdentityModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.ProtocolMapperModel;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleModel;
-import org.keycloak.models.FederatedIdentityModel;
 import org.keycloak.models.UserCredentialModel;
 import org.keycloak.models.UserFederationProviderModel;
 import org.keycloak.models.UserModel;
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 f9f62b6..b290e48 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
@@ -1,15 +1,12 @@
 package org.keycloak.models.jpa;
 
 import org.keycloak.models.ClientModel;
-import org.keycloak.models.ClientIdentityProviderMappingModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.ProtocolMapperModel;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleContainerModel;
 import org.keycloak.models.RoleModel;
 import org.keycloak.models.jpa.entities.ClientEntity;
-import org.keycloak.models.jpa.entities.ClientIdentityProviderMappingEntity;
-import org.keycloak.models.jpa.entities.IdentityProviderEntity;
 import org.keycloak.models.jpa.entities.ProtocolMapperEntity;
 import org.keycloak.models.jpa.entities.RoleEntity;
 import org.keycloak.models.jpa.entities.ScopeMappingEntity;
@@ -263,88 +260,6 @@ public class ClientAdapter implements ClientModel {
         return copy;
     }
 
-    @Override
-    public void updateIdentityProviders(List<ClientIdentityProviderMappingModel> identityProviders) {
-        Collection<ClientIdentityProviderMappingEntity> entities = entity.getIdentityProviders();
-        Set<String> already = new HashSet<>();
-        List<ClientIdentityProviderMappingEntity> remove = new ArrayList<>();
-
-        for (ClientIdentityProviderMappingEntity entity : entities) {
-            IdentityProviderEntity identityProvider = entity.getIdentityProvider();
-            boolean toRemove = true;
-
-            for (ClientIdentityProviderMappingModel model : identityProviders) {
-                if (model.getIdentityProvider().equals(identityProvider.getAlias())) {
-                    toRemove = false;
-                    break;
-                }
-            }
-
-            if (toRemove) {
-                remove.add(entity);
-            } else {
-                already.add(entity.getIdentityProvider().getAlias());
-            }
-        }
-        for (ClientIdentityProviderMappingEntity entity : remove) {
-            entities.remove(entity);
-            em.remove(entity);
-        }
-        em.flush();
-        for (ClientIdentityProviderMappingModel model : identityProviders) {
-            ClientIdentityProviderMappingEntity mappingEntity = null;
-
-            if (!already.contains(model.getIdentityProvider())) {
-                mappingEntity = new ClientIdentityProviderMappingEntity();
-                entities.add(mappingEntity);
-            } else {
-                for (ClientIdentityProviderMappingEntity entity : entities) {
-                    if (entity.getIdentityProvider().getAlias().equals(model.getIdentityProvider())) {
-                        mappingEntity = entity;
-                        break;
-                    }
-                }
-            }
-
-            TypedQuery<IdentityProviderEntity> query = em.createNamedQuery("findIdentityProviderByAlias", IdentityProviderEntity.class).setParameter("alias", model.getIdentityProvider());
-            IdentityProviderEntity identityProviderEntity = query.getSingleResult();
-
-            mappingEntity.setIdentityProvider(identityProviderEntity);
-            mappingEntity.setClient(this.entity);
-            mappingEntity.setRetrieveToken(model.isRetrieveToken());
-
-            em.persist(mappingEntity);
-        }
-        em.flush();
-    }
-
-    @Override
-    public List<ClientIdentityProviderMappingModel> getIdentityProviders() {
-        List<ClientIdentityProviderMappingModel> models = new ArrayList<ClientIdentityProviderMappingModel>();
-
-        for (ClientIdentityProviderMappingEntity entity : this.entity.getIdentityProviders()) {
-            ClientIdentityProviderMappingModel model = new ClientIdentityProviderMappingModel();
-
-            model.setIdentityProvider(entity.getIdentityProvider().getAlias());
-            model.setRetrieveToken(entity.isRetrieveToken());
-
-            models.add(model);
-        }
-
-        return models;
-    }
-
-    @Override
-    public boolean isAllowedRetrieveTokenFromIdentityProvider(String providerId) {
-        for (ClientIdentityProviderMappingModel model : getIdentityProviders()) {
-            if (model.getIdentityProvider().equals(providerId)) {
-                return model.isRetrieveToken();
-            }
-        }
-
-        return false;
-    }
-
     public static boolean contains(String str, String[] array) {
         for (String s : array) {
             if (str.equals(s)) return true;
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/UserAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/UserAdapter.java
index 737e0e3..8cc29f7 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/UserAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/UserAdapter.java
@@ -28,6 +28,7 @@ import javax.persistence.EntityManager;
 import javax.persistence.TypedQuery;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.Collection;
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java
index 2cb2c79..9eae9f0 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java
@@ -4,12 +4,10 @@ import com.mongodb.DBObject;
 import com.mongodb.QueryBuilder;
 import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
 import org.keycloak.models.ClientModel;
-import org.keycloak.models.ClientIdentityProviderMappingModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.ProtocolMapperModel;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleModel;
-import org.keycloak.models.entities.ClientIdentityProviderMappingEntity;
 import org.keycloak.models.entities.ProtocolMapperEntity;
 import org.keycloak.models.mongo.keycloak.entities.MongoClientEntity;
 import org.keycloak.models.mongo.keycloak.entities.MongoRoleEntity;
@@ -398,49 +396,6 @@ public class ClientAdapter extends AbstractMongoAdapter<MongoClientEntity> imple
 
 
     @Override
-    public void updateIdentityProviders(List<ClientIdentityProviderMappingModel> identityProviders) {
-        List<ClientIdentityProviderMappingEntity> stored = new ArrayList<ClientIdentityProviderMappingEntity>();
-
-        for (ClientIdentityProviderMappingModel model : identityProviders) {
-            ClientIdentityProviderMappingEntity entity = new ClientIdentityProviderMappingEntity();
-
-            entity.setId(model.getIdentityProvider());
-            entity.setRetrieveToken(model.isRetrieveToken());
-            stored.add(entity);
-        }
-
-        getMongoEntity().setIdentityProviders(stored);
-        updateMongoEntity();
-    }
-
-    @Override
-    public List<ClientIdentityProviderMappingModel> getIdentityProviders() {
-        List<ClientIdentityProviderMappingModel> models = new ArrayList<ClientIdentityProviderMappingModel>();
-
-        for (ClientIdentityProviderMappingEntity entity : getMongoEntity().getIdentityProviders()) {
-            ClientIdentityProviderMappingModel model = new ClientIdentityProviderMappingModel();
-
-            model.setIdentityProvider(entity.getId());
-            model.setRetrieveToken(entity.isRetrieveToken());
-
-            models.add(model);
-        }
-
-        return models;
-    }
-
-    @Override
-    public boolean isAllowedRetrieveTokenFromIdentityProvider(String providerId) {
-        for (ClientIdentityProviderMappingEntity identityProviderMappingModel : getMongoEntity().getIdentityProviders()) {
-            if (identityProviderMappingModel.getId().equals(providerId)) {
-                return identityProviderMappingModel.isRetrieveToken();
-            }
-        }
-
-        return false;
-    }
-
-    @Override
     public boolean isSurrogateAuthRequired() {
         return getMongoEntity().isSurrogateAuthRequired();
     }
diff --git a/services/src/main/java/org/keycloak/services/managers/RealmManager.java b/services/src/main/java/org/keycloak/services/managers/RealmManager.java
index 58f11e9..8493397 100755
--- a/services/src/main/java/org/keycloak/services/managers/RealmManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/RealmManager.java
@@ -21,6 +21,7 @@ import org.keycloak.models.utils.RepresentationToModel;
 import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.representations.idm.RealmEventsConfigRepresentation;
 import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.services.resources.IdentityBrokerService;
 import org.keycloak.timer.TimerProvider;
 
 import java.util.Collections;
@@ -84,6 +85,7 @@ public class RealmManager {
         setupMasterAdminManagement(realm);
         setupRealmAdminManagement(realm);
         setupAccountManagement(realm);
+        setupBrokerService(realm);
         setupAdminConsole(realm);
 
         return realm;
@@ -214,6 +216,19 @@ public class RealmManager {
         }
     }
 
+    public void setupBrokerService(RealmModel realm) {
+        ClientModel client = realm.getClientNameMap().get(Constants.BROKER_SERVICE_CLIENT_ID);
+        if (client == null) {
+            client = new ClientManager(this).createClient(realm, Constants.BROKER_SERVICE_CLIENT_ID);
+            client.setEnabled(true);
+            client.setFullScopeAllowed(false);
+
+            for (String role : IdentityBrokerService.ROLES) {
+                client.addRole(role).setDescription("${role_"+role+"}");
+            }
+        }
+    }
+
     public RealmModel importRealm(RealmRepresentation rep) {
         String id = rep.getId();
         if (id == null) {
@@ -228,6 +243,7 @@ public class RealmManager {
         setupMasterAdminManagement(realm);
         if (!hasRealmAdminManagementClient(rep)) setupRealmAdminManagement(realm);
         if (!hasAccountManagementClient(rep)) setupAccountManagement(realm);
+        if (!hasBrokerClient(rep)) setupBrokerService(realm);
         if (!hasAdminConsoleClient(rep)) setupAdminConsole(realm);
 
         RepresentationToModel.importRealm(session, rep, realm);
@@ -260,6 +276,15 @@ public class RealmManager {
         }
         return false;
     }
+    private boolean hasBrokerClient(RealmRepresentation rep) {
+        if (rep.getClients() == null) return false;
+        for (ClientRepresentation clientRep : rep.getClients()) {
+            if (clientRep.getClientId().equals(Constants.BROKER_SERVICE_CLIENT_ID)) {
+                return true;
+            }
+        }
+        return false;
+    }
 
     private boolean hasAdminConsoleClient(RealmRepresentation rep) {
         if (rep.getClients() == null) return false;
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 35cce00..f1f1f97 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
@@ -84,8 +84,6 @@ public class IdentityProviderResource {
     public Response delete() {
         this.auth.requireManage();
 
-        removeClientIdentityProviders(this.realm.getClients(), this.identityProviderModel);
-
         this.realm.removeIdentityProviderByAlias(this.identityProviderModel.getAlias());
 
         return Response.noContent().build();
@@ -109,7 +107,6 @@ public class IdentityProviderResource {
                 // Admin changed the ID (alias) of identity provider. We must update all clients and users
                 logger.debug("Changing providerId in all clients and linked users. oldProviderId=" + oldProviderId + ", newProviderId=" + newProviderId);
 
-                updateClientsAfterProviderAliasChange(this.realm.getClients(), oldProviderId, newProviderId);
                 updateUsersAfterProviderAliasChange(this.session.users().getUsers(this.realm), oldProviderId, newProviderId);
             }
 
@@ -131,25 +128,6 @@ public class IdentityProviderResource {
         return null;
     }
 
-    private void updateClientsAfterProviderAliasChange(List<ClientModel> clients, String oldProviderId, String newProviderId) {
-        for (ClientModel client : clients) {
-            List<ClientIdentityProviderMappingModel> clientIdentityProviders = client.getIdentityProviders();
-            boolean found = true;
-
-            for (ClientIdentityProviderMappingModel mappingModel : clientIdentityProviders) {
-                if (mappingModel.getIdentityProvider().equals(oldProviderId)) {
-                    mappingModel.setIdentityProvider(newProviderId);
-                    found = true;
-                    break;
-                }
-            }
-
-            if (found) {
-                client.updateIdentityProviders(clientIdentityProviders);
-            }
-        }
-    }
-
     private void updateUsersAfterProviderAliasChange(List<UserModel> users, String oldProviderId, String newProviderId) {
         for (UserModel user : users) {
             FederatedIdentityModel federatedIdentity = this.session.users().getFederatedIdentity(user, oldProviderId, this.realm);
@@ -285,18 +263,5 @@ public class IdentityProviderResource {
         realm.removeIdentityProviderMapper(model);
     }
 
-    private void removeClientIdentityProviders(List<ClientModel> clients, IdentityProviderModel identityProvider) {
-        for (ClientModel clientModel : clients) {
-            List<ClientIdentityProviderMappingModel> identityProviders = clientModel.getIdentityProviders();
-
-            for (ClientIdentityProviderMappingModel providerMappingModel : new ArrayList<>(identityProviders)) {
-                if (providerMappingModel.getIdentityProvider().equals(identityProvider.getAlias())) {
-                    identityProviders.remove(providerMappingModel);
-                    clientModel.updateIdentityProviders(identityProviders);
-                    break;
-                }
-            }
-        }
-    }
 
 }
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 0d4b38b..b2f5a53 100755
--- a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
+++ b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
@@ -34,17 +34,20 @@ import org.keycloak.events.EventType;
 import org.keycloak.login.LoginFormsProvider;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.ClientSessionModel;
+import org.keycloak.models.Constants;
 import org.keycloak.models.FederatedIdentityModel;
 import org.keycloak.models.IdentityProviderMapperModel;
 import org.keycloak.models.IdentityProviderModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.KeycloakSessionFactory;
 import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.UserSessionModel;
 import org.keycloak.protocol.ProtocolMapper;
 import org.keycloak.protocol.oidc.TokenManager;
 import org.keycloak.provider.ProviderFactory;
+import org.keycloak.representations.AccessToken;
 import org.keycloak.services.managers.AppAuthManager;
 import org.keycloak.services.managers.AuthenticationManager;
 import org.keycloak.services.managers.AuthenticationManager.AuthResult;
@@ -92,6 +95,8 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
 
     private static final Logger LOGGER = Logger.getLogger(IdentityBrokerService.class);
     public static final String BROKER_PROVIDER_ID = "BROKER_PROVIDER_ID";
+    public static final String READ_TOKEN_ROLE = "READ_TOKEN";
+    public static final String[] ROLES = {READ_TOKEN_ROLE};
 
     private final RealmModel realmModel;
 
@@ -185,7 +190,8 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
             AuthResult authResult = authManager.authenticateBearerToken(this.session, this.realmModel, this.uriInfo, this.clientConnection, this.request.getHttpHeaders());
 
             if (authResult != null) {
-                String audience = authResult.getToken().getAudience();
+                AccessToken token = authResult.getToken();
+                String audience = token.getAudience();
                 ClientModel clientModel = this.realmModel.getClientByClientId(audience);
 
                 if (clientModel == null) {
@@ -194,16 +200,16 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
 
                 session.getContext().setClient(clientModel);
 
-                if (!clientModel.isAllowedRetrieveTokenFromIdentityProvider(providerId)) {
-                    return corsResponse(badRequest("Client [" + audience + "] not authorized to retrieve tokens from identity provider [" + providerId + "]."), clientModel);
+                ClientModel brokerClient = realmModel.getClientByClientId(Constants.BROKER_SERVICE_CLIENT_ID);
+                if (brokerClient == null) {
+                    return corsResponse(forbidden("Realm has not migrated to support the broker token exchange service"), clientModel);
+
                 }
+                Map<String, AccessToken.Access> resourceAccess = token.getResourceAccess();
+                AccessToken.Access brokerRoles = resourceAccess == null ? null : resourceAccess.get(Constants.BROKER_SERVICE_CLIENT_ID);
+                if (brokerRoles == null || !brokerRoles.isUserInRole(READ_TOKEN_ROLE)) {
+                    return corsResponse(forbidden("Client [" + audience + "] not authorized to retrieve tokens from identity provider [" + providerId + "]."), clientModel);
 
-                if (clientModel.isConsentRequired()) {
-                    return corsResponse(session.getProvider(LoginFormsProvider.class)
-                            .setClientSessionCode(authManager.extractAuthorizationHeaderToken(this.request.getHttpHeaders()))
-                            .setAccessRequest("Your information from " + providerId + " identity provider.")
-                            .setActionUri(this.uriInfo.getRequestUri())
-                            .createOAuthGrant(null), clientModel);
                 }
 
                 IdentityProvider identityProvider = getIdentityProvider(session, realmModel, providerId);
@@ -232,18 +238,6 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
         }
     }
 
-    @POST
-    @Path("{provider_id}/token")
-    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
-    public Response consentTokenRetrieval(@PathParam("provider_id") String providerId,
-                                          MultivaluedMap<String, String> formData) {
-        if (formData.containsKey("cancel")) {
-            return redirectToErrorPage(Messages.PERMISSION_NOT_APPROVED);
-        }
-
-        return getToken(providerId, true);
-    }
-
     public Response authenticated(BrokeredIdentityContext context) {
         ClientSessionCode clientCode = null;
         IdentityProviderModel identityProviderConfig = context.getIdpConfig();
@@ -445,6 +439,11 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
         return ErrorResponse.error(message, Status.BAD_REQUEST);
     }
 
+    private Response forbidden(String message) {
+        fireErrorEvent(message);
+        return ErrorResponse.error(message, Status.FORBIDDEN);
+    }
+
     public static IdentityProvider getIdentityProvider(KeycloakSession session, RealmModel realm, String alias) {
         IdentityProviderModel identityProviderModel = realm.getIdentityProviderByAlias(alias);
 
@@ -534,6 +533,13 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
         federatedUser.setFirstName(updatedIdentity.getFirstName());
         federatedUser.setLastName(updatedIdentity.getLastName());
 
+
+        if (updatedIdentity.getIdpConfig().isStoreToken()) {
+            RoleModel readTokenRole = realmModel.getClientByClientId(Constants.BROKER_SERVICE_CLIENT_ID).getRole(READ_TOKEN_ROLE);
+            federatedUser.grantRole(readTokenRole);
+        }
+
+
         this.session.users().addFederatedIdentity(this.realmModel, federatedUser, federatedIdentityModel);
 
         updatedIdentity.getIdp().importNewUser(session, realmModel, federatedUser, updatedIdentity);
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ClientTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ClientTest.java
old mode 100644
new mode 100755
index 8151ca5..9d2fa9d
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ClientTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ClientTest.java
@@ -42,7 +42,7 @@ public class ClientTest extends AbstractClientTest {
 
     @Test
     public void getClients() {
-        assertNames(realm.clients().findAll(), "account", "realm-management", "security-admin-console");
+        assertNames(realm.clients().findAll(), "account", "realm-management", "security-admin-console", "broker");
     }
 
     @Test
@@ -52,7 +52,7 @@ public class ClientTest extends AbstractClientTest {
         rep.setEnabled(true);
         realm.clients().create(rep);
 
-        assertNames(realm.clients().findAll(), "account", "realm-management", "security-admin-console", "my-app");
+        assertNames(realm.clients().findAll(), "account", "realm-management", "security-admin-console", "broker", "my-app");
     }
 
     @Test
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java
index e899999..5a783ff 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java
@@ -32,14 +32,17 @@ import org.junit.Test;
 import org.keycloak.OAuth2Constants;
 import org.keycloak.models.ClientIdentityProviderMappingModel;
 import org.keycloak.models.ClientModel;
+import org.keycloak.models.Constants;
 import org.keycloak.models.FederatedIdentityModel;
 import org.keycloak.models.IdentityProviderModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.UserModel.RequiredAction;
 import org.keycloak.representations.IDToken;
 import org.keycloak.services.Urls;
+import org.keycloak.services.resources.IdentityBrokerService;
 import org.keycloak.testsuite.OAuthClient;
 import org.keycloak.testsuite.OAuthClient.AccessTokenResponse;
 import org.keycloak.testsuite.broker.util.UserSessionStatusServlet.UserSessionStatus;
@@ -243,6 +246,7 @@ public abstract class AbstractIdentityProviderTest {
             FederatedIdentityModel federatedIdentityModel = federatedIdentities.iterator().next();
 
             assertEquals(getProviderId(), federatedIdentityModel.getIdentityProvider());
+            revokeGrant();
 
             driver.navigate().to("http://localhost:8081/test-app/logout");
             driver.navigate().to("http://localhost:8081/test-app");
@@ -285,27 +289,12 @@ public abstract class AbstractIdentityProviderTest {
         RealmModel realm = getRealm();
         ClientModel clientModel = realm.getClientByClientId("test-app");
 
-        // This client doesn't have any specific identity providers settings
-        ClientModel client2 = realm.getClientByClientId("test-app");
-        assertEquals(0, client2.getIdentityProviders().size());
-
         // Provider button is available on login page
         this.driver.navigate().to("http://localhost:8081/test-app/");
         assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/auth"));
         loginPage.findSocialButton(getProviderId());
 
-        // Add identityProvider to client model
-        List<ClientIdentityProviderMappingModel> appIdentityProviders = new ArrayList<ClientIdentityProviderMappingModel>();
-        ClientIdentityProviderMappingModel mapping = new ClientIdentityProviderMappingModel();
-        mapping.setIdentityProvider(getProviderId());
-        mapping.setRetrieveToken(true);
-        appIdentityProviders.add(mapping);
-        clientModel.updateIdentityProviders(appIdentityProviders);
-
-        // Provider button still available on login page
-        this.driver.navigate().to("http://localhost:8081/test-app/");
-        loginPage.findSocialButton(getProviderId());
-    }
+     }
 
     @Test
     public void testUserAlreadyExistsWhenUpdatingProfile() {
@@ -411,12 +400,16 @@ public abstract class AbstractIdentityProviderTest {
         revokeGrant();
 
         // Logout from account management
+        String pageSource = driver.getPageSource();
         accountFederatedIdentityPage.logout();
         assertTrue(driver.getTitle().equals("Log in to realm-with-broker"));
+        assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/auth"));
 
         // Try to login. Previous link is not valid anymore, so now it should try to register new user
         this.loginPage.clickSocial(identityProviderModel.getAlias());
+        this.loginPage.login("test-user", "password");
         doAfterProviderAuthentication();
+        String current = driver.getCurrentUrl();
         this.updateProfilePage.assertCurrent();
     }
 
@@ -429,6 +422,52 @@ public abstract class AbstractIdentityProviderTest {
         driver.findElement(By.className("model-oidc-idp"));
     }
 
+    protected void configureClientRetrieveToken(String clientId) {
+        RealmModel realm = getRealm();
+        RoleModel readTokenRole = realm.getClientByClientId(Constants.BROKER_SERVICE_CLIENT_ID).getRole(IdentityBrokerService.READ_TOKEN_ROLE);
+        ClientModel client = realm.getClientByClientId(clientId);
+        if (!client.hasScope(readTokenRole)) client.addScopeMapping(readTokenRole);
+
+        brokerServerRule.stopSession(session, true);
+        session = brokerServerRule.startSession();
+
+    }
+
+    protected void configureUserRetrieveToken(String username) {
+        RealmModel realm = getRealm();
+        UserModel user = session.users().getUserByUsername(username, realm);
+        RoleModel readTokenRole = realm.getClientByClientId(Constants.BROKER_SERVICE_CLIENT_ID).getRole(IdentityBrokerService.READ_TOKEN_ROLE);
+        if (user != null && !user.hasRole(readTokenRole)) {
+            user.grantRole(readTokenRole);
+        }
+        brokerServerRule.stopSession(session, true);
+        session = brokerServerRule.startSession();
+
+    }
+
+    protected void unconfigureClientRetrieveToken(String clientId) {
+        RealmModel realm = getRealm();
+        RoleModel readTokenRole = realm.getClientByClientId(Constants.BROKER_SERVICE_CLIENT_ID).getRole(IdentityBrokerService.READ_TOKEN_ROLE);
+        ClientModel client = realm.getClientByClientId(clientId);
+        if (client.hasScope(readTokenRole)) client.deleteScopeMapping(readTokenRole);
+
+        brokerServerRule.stopSession(session, true);
+        session = brokerServerRule.startSession();
+
+    }
+
+    protected void unconfigureUserRetrieveToken(String username) {
+        RealmModel realm = getRealm();
+        UserModel user = session.users().getUserByUsername(username, realm);
+        RoleModel readTokenRole = realm.getClientByClientId(Constants.BROKER_SERVICE_CLIENT_ID).getRole(IdentityBrokerService.READ_TOKEN_ROLE);
+        if (user != null && user.hasRole(readTokenRole)) {
+            user.deleteRoleMapping(readTokenRole);
+        }
+        brokerServerRule.stopSession(session, true);
+        session = brokerServerRule.startSession();
+
+    }
+
     @Test
     public void testTokenStorageAndRetrievalByApplication() {
         IdentityProviderModel identityProviderModel = getIdentityProviderModel();
@@ -448,8 +487,6 @@ public abstract class AbstractIdentityProviderTest {
 
         assertNotNull(identityModel.getToken());
 
-        configureRetrieveToken(realm.getClientByClientId("test-app"), getProviderId(), false);
-
         UserSessionStatus userSessionStatus = retrieveSessionStatus();
         String accessToken = userSessionStatus.getAccessTokenString();
         URI tokenEndpointUrl = Urls.identityProviderRetrieveToken(BASE_URI, getProviderId(), realm.getName());
@@ -463,112 +500,43 @@ public abstract class AbstractIdentityProviderTest {
         Client client = ClientBuilder.newBuilder().register(authFilter).build();
         WebTarget tokenEndpoint = client.target(tokenEndpointUrl);
         Response response = tokenEndpoint.request().get();
+        assertEquals(Status.OK.getStatusCode(), response.getStatus());
+        assertNotNull(response.readEntity(String.class));
+        revokeGrant();
 
-        assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
-
-        configureRetrieveToken(getRealm().getClientByClientId("test-app"), getProviderId(), true);
 
-        client = ClientBuilder.newBuilder().register(authFilter).build();
+        driver.navigate().to("http://localhost:8081/test-app/logout");
+        String currentUrl = this.driver.getCurrentUrl();
+        System.out.println("after logout currentUrl: " + currentUrl);
+        assertTrue(currentUrl.startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/auth"));
+
+        unconfigureUserRetrieveToken(getProviderId() + ".test-user");
+        loginIDP("test-user");
+        //authenticateWithIdentityProvider(identityProviderModel, "test-user");
+        assertEquals("http://localhost:8081/test-app", driver.getCurrentUrl());
+
+        userSessionStatus = retrieveSessionStatus();
+        accessToken = userSessionStatus.getAccessTokenString();
+        final String authHeader2 = "Bearer " + accessToken;
+        ClientRequestFilter authFilter2 = new ClientRequestFilter() {
+            @Override
+            public void filter(ClientRequestContext requestContext) throws IOException {
+                requestContext.getHeaders().add(HttpHeaders.AUTHORIZATION, authHeader2);
+            }
+        };
+        client = ClientBuilder.newBuilder().register(authFilter2).build();
         tokenEndpoint = client.target(tokenEndpointUrl);
         response = tokenEndpoint.request().get();
 
-        assertEquals(Status.OK.getStatusCode(), response.getStatus());
-        assertNotNull(response.readEntity(String.class));
+        assertEquals(Status.FORBIDDEN.getStatusCode(), response.getStatus());
 
+        revokeGrant();
         driver.navigate().to("http://localhost:8081/test-app/logout");
         driver.navigate().to("http://localhost:8081/test-app");
 
         assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/auth"));
     }
 
-    @Test
-    public void testTokenStorageAndRetrievalByOAuthClient() {
-        IdentityProviderModel identityProviderModel = getIdentityProviderModel();
-
-        identityProviderModel.setStoreToken(true);
-        identityProviderModel.setUpdateProfileFirstLogin(false);
-
-        driver.navigate().to("http://localhost:8081/test-app");
-
-        // choose the identity provider
-        this.loginPage.clickSocial(getProviderId());
-
-        assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8082/auth/"));
-
-        // log in to identity provider
-        this.loginPage.login("test-user", "password");
-
-        doAfterProviderAuthentication();
-
-        changePasswordPage.realm("realm-with-broker");
-        changePasswordPage.open();
-        changePasswordPage.changePassword("password", "password");
-
-        driver.navigate().to("http://localhost:8081/test-app/logout");
-
-        oauth.realm("realm-with-broker");
-        oauth.redirectUri("http://localhost:8081/third-party");
-        oauth.clientId("third-party");
-        oauth.doLoginGrant("test-user@localhost", "password");
-
-        grantPage.assertCurrent();
-        grantPage.accept();
-
-        assertTrue(oauth.getCurrentQuery().containsKey(OAuth2Constants.CODE));
-
-        ClientModel clientModel = getRealm().getClientByClientId("third-party");
-        assertEquals(0, clientModel.getIdentityProviders().size());
-
-        configureRetrieveToken(clientModel, getProviderId(), true);
-
-        AccessTokenResponse accessToken = oauth.doAccessTokenRequest(oauth.getCurrentQuery().get(OAuth2Constants.CODE), "password");
-
-        doTokenRequest(accessToken.getAccessToken());
-    }
-
-    public void doTokenRequest(String token) {
-        try {
-            HttpClient client = new DefaultHttpClient();
-            HttpGet get = new HttpGet(Urls.identityProviderRetrieveToken(BASE_URI, getProviderId(), getRealm().getName()));
-
-            get.setHeader("Authorization", "Bearer " + token);
-
-            HttpResponse response = client.execute(get);
-            assertEquals(200, response.getStatusLine().getStatusCode());
-
-            assertNotNull(IOUtils.toString(response.getEntity().getContent()));
-        } catch (Exception e) {
-            fail(e.getMessage());
-        }
-    }
-
-    private void configureRetrieveToken(ClientModel clientModel, String providerId, boolean retrieveToken) {
-        List<ClientIdentityProviderMappingModel> providerMappingModels = clientModel.getIdentityProviders();
-        ClientIdentityProviderMappingModel providerMappingModel = null;
-
-        // Check if provider is already linked with this client
-        for (ClientIdentityProviderMappingModel current : providerMappingModels) {
-            if (current.getIdentityProvider().equals(providerId)) {
-                providerMappingModel = current;
-                break;
-            }
-        }
-
-        // Link provider with client if not linked yet
-        if (providerMappingModel == null) {
-            providerMappingModel = new ClientIdentityProviderMappingModel();
-            providerMappingModel.setIdentityProvider(providerId);
-            providerMappingModels.add(providerMappingModel);
-        }
-
-        providerMappingModel.setRetrieveToken(retrieveToken);
-
-        clientModel.updateIdentityProviders(providerMappingModels);
-
-        brokerServerRule.stopSession(session, true);
-        session = brokerServerRule.startSession();
-    }
-
     protected abstract void doAssertTokenRetrieval(String pageSource);
 
     private UserModel assertSuccessfulAuthentication(IdentityProviderModel identityProviderModel, String username, String expectedEmail) {
@@ -605,19 +573,8 @@ public abstract class AbstractIdentityProviderTest {
     }
 
     private void authenticateWithIdentityProvider(IdentityProviderModel identityProviderModel, String username) {
-        driver.navigate().to("http://localhost:8081/test-app");
-
-        assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/auth"));
-
-        // choose the identity provider
-        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");
+        loginIDP(username);
 
-        doAfterProviderAuthentication();
 
         if (identityProviderModel.isUpdateProfileFirstLogin()) {
             String userEmail = "new@email.com";
@@ -630,6 +587,22 @@ public abstract class AbstractIdentityProviderTest {
         }
     }
 
+    private void loginIDP(String username) {
+        driver.navigate().to("http://localhost:8081/test-app");
+
+        assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/auth"));
+
+        // choose the identity provider
+        this.loginPage.clickSocial(getProviderId());
+
+        String currentUrl = this.driver.getCurrentUrl();
+        assertTrue(currentUrl.startsWith("http://localhost:8082/auth/"));
+        System.out.println(this.driver.getCurrentUrl());
+        // log in to identity provider
+        this.loginPage.login(username, "password");
+        doAfterProviderAuthentication();
+    }
+
     protected UserModel getFederatedUser() {
         UserSessionStatus userSessionStatus = retrieveSessionStatus();
         IDToken idToken = userSessionStatus.getIdToken();
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/IdentityProviderHintTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/IdentityProviderHintTest.java
index 18f3cc5..48ac594 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/IdentityProviderHintTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/IdentityProviderHintTest.java
@@ -66,11 +66,7 @@ public class IdentityProviderHintTest {
         // log in to identity provider
         this.loginPage.login("test-user", "password");
 
-        // grant access to broker-app
-        this.grantPage.assertCurrent();
-        this.grantPage.accept();
-
-        // authenticated and redirected to app
+         // authenticated and redirected to app
         assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/test-app"));
         assertTrue(this.driver.getPageSource().contains("idToken"));
     }
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 a1f8245..4c10d4c 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
@@ -118,32 +118,6 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
         this.realmManager.removeRealm(realm);
     }
 
-    @Test
-    public void testApplicationIdentityProviders() throws Exception {
-        RealmModel realm = installTestRealm();
-
-        ClientModel client = realm.getClientByClientId("test-app-with-allowed-providers");
-        List<ClientIdentityProviderMappingModel> identityProviders = client.getIdentityProviders();
-
-        assertEquals(1, identityProviders.size());
-
-        ClientIdentityProviderMappingModel identityProviderMappingModel = identityProviders.get(0);
-
-        assertEquals("kc-oidc-idp", identityProviderMappingModel.getIdentityProvider());
-        assertEquals(false, identityProviderMappingModel.isRetrieveToken());
-
-        identityProviders.remove(identityProviderMappingModel);
-
-        client.updateIdentityProviders(identityProviders);
-
-        client = realm.getClientById(client.getId());
-        identityProviders = client.getIdentityProviders();
-
-        assertEquals(0, identityProviders.size());
-        this.realmManager.removeRealm(realm);
-    }
-
-
     private void assertIdentityProviderConfig(List<IdentityProviderModel> identityProviders) {
         assertFalse(identityProviders.isEmpty());
 
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/OIDCKeyCloakServerBrokerBasicTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/OIDCKeyCloakServerBrokerBasicTest.java
index 44cd749..e1f4c83 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/OIDCKeyCloakServerBrokerBasicTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/OIDCKeyCloakServerBrokerBasicTest.java
@@ -74,8 +74,8 @@ public class OIDCKeyCloakServerBrokerBasicTest extends AbstractIdentityProviderT
     @Override
     protected void doAfterProviderAuthentication() {
         // grant access to broker-app
-        grantPage.assertCurrent();
-        grantPage.accept();
+        //grantPage.assertCurrent();
+        //grantPage.accept();
     }
 
     @Override
@@ -119,4 +119,14 @@ public class OIDCKeyCloakServerBrokerBasicTest extends AbstractIdentityProviderT
     public void testSuccessfulAuthenticationWithoutUpdateProfile_newUser_emailAsUsername_emailNotProvided() {
         super.testSuccessfulAuthenticationWithoutUpdateProfile_newUser_emailAsUsername_emailNotProvided();
     }
+
+    @Test
+    public void testTokenStorageAndRetrievalByApplication() {
+        super.testTokenStorageAndRetrievalByApplication();
+    }
+
+    @Test
+    public void testAccountManagementLinkIdentity() {
+        super.testAccountManagementLinkIdentity();
+    }
 }
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 9796d3a..46bfa3d 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
@@ -67,8 +67,8 @@ public class SAMLKeyCloakServerBrokerBasicTest extends AbstractIdentityProviderT
 
     @Override
     protected void doAssertFederatedUserNoEmail(UserModel federatedUser) {
-        assertEquals("kc-saml-idp-basic.", federatedUser.getUsername());
-        assertEquals("", federatedUser.getEmail());
+        assertEquals("kc-saml-idp-basic.test-user-noemail", federatedUser.getUsername());
+        //assertEquals("", federatedUser.getEmail());
         assertEquals(null, federatedUser.getFirstName());
         assertEquals(null, federatedUser.getLastName());
     }
@@ -96,13 +96,22 @@ public class SAMLKeyCloakServerBrokerBasicTest extends AbstractIdentityProviderT
 
     @Override
     @Test
-    public void testTokenStorageAndRetrievalByOAuthClient() {
-        super.testTokenStorageAndRetrievalByOAuthClient();
+    public void testSuccessfulAuthentication() {
+        super.testSuccessfulAuthentication();
     }
 
-    @Override
     @Test
-    public void testSuccessfulAuthentication() {
-        super.testSuccessfulAuthentication();
+    public void testAccountManagementLinkIdentity() {
+        super.testAccountManagementLinkIdentity();
+    }
+
+    @Test
+    public void testTokenStorageAndRetrievalByApplication() {
+        super.testTokenStorageAndRetrievalByApplication();
+    }
+
+    @Test
+    public void testSuccessfulAuthenticationWithoutUpdateProfile_newUser_emailAsUsername() {
+        super.testSuccessfulAuthenticationWithoutUpdateProfile_newUser_emailAsUsername();
     }
 }
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 8d7fb71..1f36c9f 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
@@ -67,8 +67,8 @@ public class SAMLKeyCloakServerBrokerWithSignatureTest extends AbstractIdentityP
 
     @Override
     protected void doAssertFederatedUserNoEmail(UserModel federatedUser) {
-        assertEquals("kc-saml-signed-idp.", federatedUser.getUsername());
-        assertEquals("", federatedUser.getEmail());
+        assertEquals("kc-saml-signed-idp.test-user-noemail", federatedUser.getUsername());
+        //assertEquals("", federatedUser.getEmail());
         assertEquals(null, federatedUser.getFirstName());
         assertEquals(null, federatedUser.getLastName());
     }
@@ -93,4 +93,8 @@ public class SAMLKeyCloakServerBrokerWithSignatureTest extends AbstractIdentityP
         super.testSuccessfulAuthentication();
     }
 
+    @Test
+    public void testTokenStorageAndRetrievalByApplication() {
+        super.testTokenStorageAndRetrievalByApplication();
+    }
 }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/util/UserSessionStatusServlet.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/util/UserSessionStatusServlet.java
old mode 100644
new mode 100755
index b135473..ff3bd12
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/util/UserSessionStatusServlet.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/util/UserSessionStatusServlet.java
@@ -27,6 +27,7 @@ import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.core.UriBuilder;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.Serializable;
@@ -39,8 +40,11 @@ public class UserSessionStatusServlet extends HttpServlet {
     @Override
     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
         if (req.getRequestURI().toString().endsWith("logout")) {
-            resp.setStatus(200);
-            req.logout();
+            String redirect = UriBuilder.fromUri("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/logout")
+                    .queryParam("redirect_uri", "http://localhost:8081/test-app").build().toString();
+            resp.sendRedirect(redirect);
+            //resp.setStatus(200);
+            //req.logout();
             return;
         }
 
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 5bdc191..bea52c4 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
@@ -82,7 +82,7 @@ public class ImportTest extends AbstractModelTest {
         Assert.assertEquals(0,  session.users().getFederatedIdentities(user, realm).size());
 
         List<ClientModel> resources = realm.getClients();
-        Assert.assertEquals(6, resources.size());
+        Assert.assertEquals(7, resources.size());
 
         // Test applications imported
         ClientModel application = realm.getClientByClientId("Application");
@@ -93,7 +93,7 @@ public class ImportTest extends AbstractModelTest {
         Assert.assertNotNull(otherApp);
         Assert.assertNull(nonExisting);
         Map<String, ClientModel> clients = realm.getClientNameMap();
-        Assert.assertEquals(6, clients.size());
+        Assert.assertEquals(7, clients.size());
         Assert.assertTrue(clients.values().contains(application));
         Assert.assertTrue(clients.values().contains(otherApp));
         Assert.assertTrue(clients.values().contains(accountApp));
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 8821af5..d3688a8 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
@@ -9,11 +9,11 @@
     "clients" : [
       {
         "clientId": "broker-app",
-        "consentRequired": "true",
+        "consentRequired": "false",
         "enabled": true,
         "secret": "secret",
         "redirectUris": [
-          "http://localhost:8081/auth/realms/realm-with-broker/broker/kc-oidc-idp/endpoint"
+          "http://localhost:8081/auth/realms/realm-with-broker/broker/kc-oidc-idp/endpoint/*"
         ],
         "protocolMappers": [
             {
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 ab29fd1..1fba984 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
@@ -15,7 +15,12 @@
                 "http://localhost:8081/auth/realms/realm-with-broker/broker/kc-saml-idp-basic/endpoint"
             ],
             "attributes": {
-                "saml.authnstatement": "true"
+                "saml.authnstatement": "true",
+                "saml_single_logout_service_url_post": "http://localhost:8081/auth/realms/realm-with-broker/broker/kc-saml-idp-basic/endpoint",
+                "saml_assertion_consumer_url_post": "http://localhost:8081/auth/realms/realm-with-broker/broker/kc-saml-idp-basic/endpoint",
+                "saml_force_name_id_format": "true",
+                "saml_name_id_format": "username"
+
             },
             "protocolMappers": [
                 {
@@ -40,6 +45,18 @@
                         "attribute.name": "mobile",
                         "attribute.nameformat": "Basic"
                     }
+                },
+                {
+                    "name": "email",
+                    "protocol": "saml",
+                    "protocolMapper": "saml-user-property-mapper",
+                    "consentRequired": false,
+                    "config": {
+                        "user.attribute": "email",
+                        "attribute.name": "urn:oid:1.2.840.113549.1.9.1",
+                        "attribute.nameformat": "urn:oasis:names:tc:SAML:2.0:attrname-format:uri",
+                        "friendly.name": "email"
+                    }
                 }
 
             ]
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 3eb18f1..d377254 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
@@ -15,6 +15,10 @@
                 "http://localhost:8081/auth/realms/realm-with-broker/broker/kc-saml-signed-idp/endpoint"
             ],
             "attributes": {
+                "saml_single_logout_service_url_post": "http://localhost:8081/auth/realms/realm-with-broker/broker/kc-saml-signed-idp/endpoint",
+                "saml_assertion_consumer_url_post":    "http://localhost:8081/auth/realms/realm-with-broker/broker/kc-saml-signed-idp/endpoint",
+                "saml_force_name_id_format": "true",
+                "saml_name_id_format": "username",
                 "saml.assertion.signature": "true",
                 "saml.server.signature": "true",
                 "saml.signature.algorithm": "RSA_SHA256",
@@ -46,6 +50,18 @@
                         "attribute.name": "mobile",
                         "attribute.nameformat": "Basic"
                     }
+                },
+                {
+                    "name": "email",
+                    "protocol": "saml",
+                    "protocolMapper": "saml-user-property-mapper",
+                    "consentRequired": false,
+                    "config": {
+                        "user.attribute": "email",
+                        "attribute.name": "urn:oid:1.2.840.113549.1.9.1",
+                        "attribute.nameformat": "urn:oasis:names:tc:SAML:2.0:attrname-format:uri",
+                        "friendly.name": "email"
+                    }
                 }
 
             ]
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 406a6a3..1ac47ba 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
@@ -112,6 +112,7 @@
             "updateProfileFirstLogin" : "true",
             "config": {
                 "singleSignOnServiceUrl": "http://localhost:8082/auth/realms/realm-with-saml-signed-idp/protocol/saml",
+                "singleLogoutServiceUrl": "http://localhost:8082/auth/realms/realm-with-saml-signed-idp/protocol/saml",
                 "nameIDPolicyFormat": "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress",
                 "signingCertificate": "MIIDdzCCAl+gAwIBAgIEbySuqTANBgkqhkiG9w0BAQsFADBsMRAwDgYDVQQGEwdVbmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYDVQQKEwdVbmtub3duMRAwDgYDVQQLEwdVbmtub3duMRAwDgYDVQQDEwdVbmtub3duMB4XDTE1MDEyODIyMTYyMFoXDTE3MTAyNDIyMTYyMFowbDEQMA4GA1UEBhMHVW5rbm93bjEQMA4GA1UECBMHVW5rbm93bjEQMA4GA1UEBxMHVW5rbm93bjEQMA4GA1UEChMHVW5rbm93bjEQMA4GA1UECxMHVW5rbm93bjEQMA4GA1UEAxMHVW5rbm93bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAII/K9NNvXi9IySl7+l2zY/kKrGTtuR4WdCI0xLW/Jn4dLY7v1/HOnV4CC4ecFOzhdNFPtJkmEhP/q62CpmOYOKApXk3tfmm2rwEz9bWprVxgFGKnbrWlz61Z/cjLAlhD3IUj2ZRBquYgSXQPsYfXo1JmSWF5pZ9uh1FVqu9f4wvRqY20ZhUN+39F+1iaBsoqsrbXypCn1HgZkW1/9D9GZug1c3vB4wg1TwZZWRNGtxwoEhdK6dPrNcZ+6PdanVilWrbQFbBjY4wz8/7IMBzssoQ7Usmo8F1Piv0FGfaVeJqBrcAvbiBMpk8pT+27u6p8VyIX6LhGvnxIwM07NByeSUCAwEAAaMhMB8wHQYDVR0OBBYEFFlcNuTYwI9W0tQ224K1gFJlMam0MA0GCSqGSIb3DQEBCwUAA4IBAQB5snl1KWOJALtAjLqD0mLPg1iElmZP82Lq1htLBt3XagwzU9CaeVeCQ7lTp+DXWzPa9nCLhsC3QyrV3/+oqNli8C6NpeqI8FqN2yQW/QMWN1m5jWDbmrWwtQzRUn/rh5KEb5m3zPB+tOC6e/2bV3QeQebxeW7lVMD0tSCviUg1MQf1l2gzuXQo60411YwqrXwk6GMkDOhFDQKDlMchO3oRbQkGbcP8UeiKAXjMeHfzbiBr+cWz8NYZEtxUEDYDjTpKrYCSMJBXpmgVJCZ00BswbksxJwaGqGMPpUKmCV671pf3m8nq3xyiHMDGuGwtbU+GE8kVx85menmp8+964nin",
                 "wantAuthnRequestsSigned": true,
@@ -128,6 +129,7 @@
             "updateProfileFirstLogin" : "true",
             "config": {
                 "singleSignOnServiceUrl": "http://localhost:8082/auth/realms/realm-with-saml-idp-basic/protocol/saml",
+                "singleLogoutServiceUrl": "http://localhost:8082/auth/realms/realm-with-saml-idp-basic/protocol/saml",
                 "nameIDPolicyFormat": "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress",
                 "forceAuthn": true,
                 "postBindingResponse": true,
@@ -155,6 +157,7 @@
             "providerId" : "keycloak-oidc",
             "enabled": true,
             "updateProfileFirstLogin" : "false",
+            "storeToken" : "true",
             "config": {
                 "clientId": "broker-app",
                 "clientSecret": "secret",
@@ -162,6 +165,7 @@
                 "authorizationUrl": "http://localhost:8082/auth/realms/realm-with-oidc-identity-provider/tokens/login",
                 "tokenUrl": "http://localhost:8082/auth/realms/realm-with-oidc-identity-provider/protocol/openid-connect/token",
                 "userInfoUrl": "http://localhost:8082/auth/realms/realm-with-oidc-identity-provider/protocol/openid-connect/userinfo",
+                "logoutUrl": "http://localhost:8082/auth/realms/realm-with-oidc-identity-provider/tokens/logout",
                 "defaultScope": "email profile"
             }
         }
@@ -248,8 +252,8 @@
             "name": "test-app",
             "enabled": true,
             "publicClient": true,
-            "adminUrl": "http://localhost:8081/auth",
-            "baseUrl": "http://localhost:8081/auth",
+            "adminUrl": "http://localhost:8081/test-app",
+            "baseUrl": "http://localhost:8081/test-app",
             "redirectUris": [
                 "/test-app/*"
             ],