keycloak-aplcache

Details

diff --git a/server-spi/src/main/java/org/keycloak/broker/provider/AbstractIdentityProvider.java b/server-spi/src/main/java/org/keycloak/broker/provider/AbstractIdentityProvider.java
index ce3a27d..5532606 100755
--- a/server-spi/src/main/java/org/keycloak/broker/provider/AbstractIdentityProvider.java
+++ b/server-spi/src/main/java/org/keycloak/broker/provider/AbstractIdentityProvider.java
@@ -63,12 +63,12 @@ public abstract class AbstractIdentityProvider<C extends IdentityProviderModel> 
     }
 
     @Override
-    public Response keycloakInitiatedBrowserLogout(UserSessionModel userSession, UriInfo uriInfo, RealmModel realm) {
+    public Response keycloakInitiatedBrowserLogout(KeycloakSession session, UserSessionModel userSession, UriInfo uriInfo, RealmModel realm) {
         return null;
     }
 
     @Override
-    public void backchannelLogout(UserSessionModel userSession, UriInfo uriInfo, RealmModel realm) {
+    public void backchannelLogout(KeycloakSession session, UserSessionModel userSession, UriInfo uriInfo, RealmModel realm) {
 
     }
 
diff --git a/server-spi/src/main/java/org/keycloak/broker/provider/IdentityProvider.java b/server-spi/src/main/java/org/keycloak/broker/provider/IdentityProvider.java
index 0fa4993..9fbfae2 100755
--- a/server-spi/src/main/java/org/keycloak/broker/provider/IdentityProvider.java
+++ b/server-spi/src/main/java/org/keycloak/broker/provider/IdentityProvider.java
@@ -73,15 +73,15 @@ public interface IdentityProvider<C extends IdentityProviderModel> extends Provi
     Response performLogin(AuthenticationRequest request);
 
     /**
-     * <p>Returns a {@link javax.ws.rs.core.Response} containing the token previously stored during the authentication process for a
+     * <p>Returns a {@link Response} containing the token previously stored during the authentication process for a
      * specific user.</p>
      *
      * @param identity
      * @return
      */
-    Response retrieveToken(FederatedIdentityModel identity);
+    Response retrieveToken(KeycloakSession session, FederatedIdentityModel identity);
 
-    void backchannelLogout(UserSessionModel userSession, UriInfo uriInfo, RealmModel realm);
+    void backchannelLogout(KeycloakSession session, UserSessionModel userSession, UriInfo uriInfo, RealmModel realm);
 
     /**
      * Called when a Keycloak application initiates a logout through the browser.  This is expected to do a logout
@@ -92,7 +92,7 @@ public interface IdentityProvider<C extends IdentityProviderModel> extends Provi
      * @param realm
      * @return null if this is not supported by this provider
      */
-    Response keycloakInitiatedBrowserLogout(UserSessionModel userSession, UriInfo uriInfo, RealmModel realm);
+    Response keycloakInitiatedBrowserLogout(KeycloakSession session, UserSessionModel userSession, UriInfo uriInfo, RealmModel realm);
 
     /**
      * Export a representation of the IdentityProvider in a specific format.  For example, a SAML EntityDescriptor
diff --git a/server-spi/src/main/java/org/keycloak/broker/provider/IdentityProviderFactory.java b/server-spi/src/main/java/org/keycloak/broker/provider/IdentityProviderFactory.java
index e5ac7fd..fba8e64 100755
--- a/server-spi/src/main/java/org/keycloak/broker/provider/IdentityProviderFactory.java
+++ b/server-spi/src/main/java/org/keycloak/broker/provider/IdentityProviderFactory.java
@@ -47,7 +47,6 @@ public interface IdentityProviderFactory<T extends IdentityProvider> extends Pro
      * <p>Creates an {@link IdentityProvider} based on the configuration from
      * <code>inputStream</code>.</p>
      *
-     * @param model The model containing the common abd basic configuration for an identity provider.
      * @param inputStream The input stream from where configuration will be loaded from..
      * @return
      */
diff --git a/services/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java b/services/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java
index 182099b..322c332 100755
--- a/services/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java
+++ b/services/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java
@@ -19,14 +19,13 @@ package org.keycloak.broker.oidc;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import org.jboss.logging.Logger;
-import org.keycloak.common.ClientConnection;
 import org.keycloak.OAuth2Constants;
-import org.keycloak.broker.provider.util.SimpleHttp;
 import org.keycloak.broker.provider.AbstractIdentityProvider;
 import org.keycloak.broker.provider.AuthenticationRequest;
 import org.keycloak.broker.provider.BrokeredIdentityContext;
 import org.keycloak.broker.provider.IdentityBrokerException;
-import org.keycloak.truststore.JSSETruststoreConfigurator;
+import org.keycloak.broker.provider.util.SimpleHttp;
+import org.keycloak.common.ClientConnection;
 import org.keycloak.events.Errors;
 import org.keycloak.events.EventBuilder;
 import org.keycloak.events.EventType;
@@ -35,6 +34,7 @@ import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.services.ErrorPage;
 import org.keycloak.services.messages.Messages;
+import org.keycloak.truststore.JSSETruststoreConfigurator;
 
 import javax.ws.rs.GET;
 import javax.ws.rs.QueryParam;
@@ -54,6 +54,7 @@ import java.util.regex.Pattern;
 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_REFRESH_TOKEN = "refresh_token";
     public static final String OAUTH2_GRANT_TYPE_AUTHORIZATION_CODE = "authorization_code";
     public static final String FEDERATED_ACCESS_TOKEN = "FEDERATED_ACCESS_TOKEN";
     public static final String FEDERATED_REFRESH_TOKEN = "FEDERATED_REFRESH_TOKEN";
@@ -97,7 +98,7 @@ public abstract class AbstractOAuth2IdentityProvider<C extends OAuth2IdentityPro
     }
 
     @Override
-    public Response retrieveToken(FederatedIdentityModel identity) {
+    public Response retrieveToken(KeycloakSession session, FederatedIdentityModel identity) {
         return Response.ok(identity.getToken()).build();
     }
 
diff --git a/services/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProvider.java b/services/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProvider.java
index be5edaa..d513e72 100755
--- a/services/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProvider.java
+++ b/services/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProvider.java
@@ -20,10 +20,12 @@ import com.fasterxml.jackson.databind.JsonNode;
 import org.jboss.logging.Logger;
 import org.keycloak.broker.oidc.mappers.AbstractJsonUserAttributeMapper;
 import org.keycloak.broker.oidc.util.JsonSimpleHttp;
-import org.keycloak.broker.provider.util.SimpleHttp;
 import org.keycloak.broker.provider.AuthenticationRequest;
 import org.keycloak.broker.provider.BrokeredIdentityContext;
 import org.keycloak.broker.provider.IdentityBrokerException;
+import org.keycloak.broker.provider.util.SimpleHttp;
+import org.keycloak.common.util.PemUtils;
+import org.keycloak.common.util.Time;
 import org.keycloak.events.Errors;
 import org.keycloak.events.EventBuilder;
 import org.keycloak.events.EventType;
@@ -31,6 +33,7 @@ import org.keycloak.jose.jws.JWSInput;
 import org.keycloak.jose.jws.JWSInputException;
 import org.keycloak.jose.jws.crypto.RSAProvider;
 import org.keycloak.models.ClientSessionModel;
+import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserSessionModel;
 import org.keycloak.representations.AccessTokenResponse;
@@ -41,8 +44,8 @@ import org.keycloak.services.managers.AuthenticationManager;
 import org.keycloak.services.messages.Messages;
 import org.keycloak.services.resources.IdentityBrokerService;
 import org.keycloak.services.resources.RealmsResource;
+import org.keycloak.truststore.JSSETruststoreConfigurator;
 import org.keycloak.util.JsonSerialization;
-import org.keycloak.common.util.PemUtils;
 
 import javax.ws.rs.GET;
 import javax.ws.rs.Path;
@@ -51,7 +54,6 @@ import javax.ws.rs.core.Context;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriBuilder;
 import javax.ws.rs.core.UriInfo;
-
 import java.io.IOException;
 import java.security.PublicKey;
 
@@ -130,9 +132,9 @@ public class OIDCIdentityProvider extends AbstractOAuth2IdentityProvider<OIDCIde
     }
 
     @Override
-    public void backchannelLogout(UserSessionModel userSession, UriInfo uriInfo, RealmModel realm) {
+    public void backchannelLogout(KeycloakSession session, UserSessionModel userSession, UriInfo uriInfo, RealmModel realm) {
         if (getConfig().getLogoutUrl() == null || getConfig().getLogoutUrl().trim().equals("") || !getConfig().isBackchannelSupported()) return;
-        String idToken = userSession.getNote(FEDERATED_ID_TOKEN);
+        String idToken = getIDTokenForLogout(session, userSession);
         if (idToken == null) return;
         backchannelLogout(userSession, idToken);
     }
@@ -156,9 +158,9 @@ public class OIDCIdentityProvider extends AbstractOAuth2IdentityProvider<OIDCIde
 
 
     @Override
-    public Response keycloakInitiatedBrowserLogout(UserSessionModel userSession, UriInfo uriInfo, RealmModel realm) {
+    public Response keycloakInitiatedBrowserLogout(KeycloakSession session, UserSessionModel userSession, UriInfo uriInfo, RealmModel realm) {
         if (getConfig().getLogoutUrl() == null || getConfig().getLogoutUrl().trim().equals("")) return null;
-        String idToken = userSession.getNote(FEDERATED_ID_TOKEN);
+        String idToken = getIDTokenForLogout(session, userSession);
         if (idToken != null && getConfig().isBackchannelSupported()) {
             backchannelLogout(userSession, idToken);
             return null;
@@ -177,6 +179,47 @@ public class OIDCIdentityProvider extends AbstractOAuth2IdentityProvider<OIDCIde
         }
     }
 
+    /**
+     * Returns access token response as a string from a refresh token invocation on the remote OIDC broker
+     *
+     * @param session
+     * @param userSession
+     * @return
+     */
+    public String refreshToken(KeycloakSession session, UserSessionModel userSession) {
+        String refreshToken = userSession.getNote(FEDERATED_REFRESH_TOKEN);
+        JSSETruststoreConfigurator configurator = new JSSETruststoreConfigurator(session);
+        try {
+            return SimpleHttp.doPost(getConfig().getTokenUrl())
+                    .param("refresh_token", refreshToken)
+                    .param(OAUTH2_PARAMETER_GRANT_TYPE, OAUTH2_GRANT_TYPE_REFRESH_TOKEN)
+                    .param(OAUTH2_PARAMETER_CLIENT_ID, getConfig().getClientId())
+                    .param(OAUTH2_PARAMETER_CLIENT_SECRET, getConfig().getClientSecret())
+                    .sslFactory(configurator.getSSLSocketFactory())
+                    .hostnameVerifier(configurator.getHostnameVerifier()).asString();
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private String getIDTokenForLogout(KeycloakSession session, UserSessionModel userSession) {
+        long exp = Long.parseLong(userSession.getNote(FEDERATED_TOKEN_EXPIRATION));
+        int currentTime = Time.currentTime();
+        if (exp > 0 && currentTime > exp) {
+            String response = refreshToken(session, userSession);
+            AccessTokenResponse tokenResponse = null;
+            try {
+                tokenResponse = JsonSerialization.readValue(response, AccessTokenResponse.class);
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+            return tokenResponse.getIdToken();
+        } else {
+            return userSession.getNote(FEDERATED_ID_TOKEN);
+
+        }
+    }
+
     @Override
     protected UriBuilder createAuthorizationUrl(AuthenticationRequest request) {
         UriBuilder authorizationUrl = super.createAuthorizationUrl(request);
@@ -322,6 +365,10 @@ public class OIDCIdentityProvider extends AbstractOAuth2IdentityProvider<OIDCIde
     @Override
     public void attachUserSession(UserSessionModel userSession, ClientSessionModel clientSession, BrokeredIdentityContext context) {
         AccessTokenResponse tokenResponse = (AccessTokenResponse)context.getContextData().get(FEDERATED_ACCESS_TOKEN_RESPONSE);
+        int currentTime = Time.currentTime();
+        long expiration = tokenResponse.getExpiresIn() > 0 ? tokenResponse.getExpiresIn() + currentTime : 0;
+        userSession.setNote(FEDERATED_TOKEN_EXPIRATION, Long.toString(expiration));
+        userSession.setNote(FEDERATED_REFRESH_TOKEN, tokenResponse.getRefreshToken());
         userSession.setNote(FEDERATED_ACCESS_TOKEN, tokenResponse.getToken());
         userSession.setNote(FEDERATED_ID_TOKEN, tokenResponse.getIdToken());
     }
diff --git a/services/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java b/services/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java
index 5605ea6..3d9a536 100755
--- a/services/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java
+++ b/services/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java
@@ -31,6 +31,7 @@ import org.keycloak.dom.saml.v2.protocol.ResponseType;
 import org.keycloak.events.EventBuilder;
 import org.keycloak.models.ClientSessionModel;
 import org.keycloak.models.FederatedIdentityModel;
+import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserSessionModel;
 import org.keycloak.protocol.saml.JaxrsSAML2BindingBuilder;
@@ -145,12 +146,12 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
     }
 
     @Override
-    public Response retrieveToken(FederatedIdentityModel identity) {
+    public Response retrieveToken(KeycloakSession session, FederatedIdentityModel identity) {
         return Response.ok(identity.getToken()).build();
     }
 
     @Override
-    public void backchannelLogout(UserSessionModel userSession, UriInfo uriInfo, RealmModel realm) {
+    public void backchannelLogout(KeycloakSession session, UserSessionModel userSession, UriInfo uriInfo, RealmModel realm) {
         String singleLogoutServiceUrl = getConfig().getSingleLogoutServiceUrl();
         if (singleLogoutServiceUrl == null || singleLogoutServiceUrl.trim().equals("") || !getConfig().isBackchannelSupported()) return;
         SAML2LogoutRequestBuilder logoutBuilder = buildLogoutRequest(userSession, uriInfo, realm, singleLogoutServiceUrl);
@@ -170,12 +171,12 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
     }
 
     @Override
-    public Response keycloakInitiatedBrowserLogout(UserSessionModel userSession, UriInfo uriInfo, RealmModel realm) {
+    public Response keycloakInitiatedBrowserLogout(KeycloakSession session, UserSessionModel userSession, UriInfo uriInfo, RealmModel realm) {
         String singleLogoutServiceUrl = getConfig().getSingleLogoutServiceUrl();
         if (singleLogoutServiceUrl == null || singleLogoutServiceUrl.trim().equals("")) return null;
 
         if (getConfig().isBackchannelSupported()) {
-            backchannelLogout(userSession, uriInfo, realm);
+            backchannelLogout(session, userSession, uriInfo, realm);
             return null;
        } else {
             try {
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 b169f7c..91389f8 100755
--- a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
@@ -18,21 +18,31 @@ package org.keycloak.services.managers;
 
 import org.jboss.resteasy.specimpl.MultivaluedMapImpl;
 import org.jboss.resteasy.spi.HttpRequest;
-import org.keycloak.common.ClientConnection;
 import org.keycloak.RSATokenVerifier;
-import org.keycloak.common.VerificationException;
 import org.keycloak.authentication.RequiredActionContext;
 import org.keycloak.authentication.RequiredActionContextResult;
 import org.keycloak.authentication.RequiredActionFactory;
 import org.keycloak.authentication.RequiredActionProvider;
 import org.keycloak.broker.provider.IdentityProvider;
+import org.keycloak.common.ClientConnection;
+import org.keycloak.common.VerificationException;
+import org.keycloak.common.util.Time;
 import org.keycloak.events.Details;
 import org.keycloak.events.Errors;
 import org.keycloak.events.EventBuilder;
 import org.keycloak.events.EventType;
-import org.keycloak.jose.jws.JWSBuilder;
 import org.keycloak.forms.login.LoginFormsProvider;
-import org.keycloak.models.*;
+import org.keycloak.jose.jws.JWSBuilder;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.ClientSessionModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.ProtocolMapperModel;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RequiredActionProviderModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserConsentModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.UserSessionModel;
 import org.keycloak.models.utils.KeycloakModelUtils;
 import org.keycloak.protocol.LoginProtocol;
 import org.keycloak.protocol.LoginProtocol.Error;
@@ -44,9 +54,13 @@ import org.keycloak.services.messages.Messages;
 import org.keycloak.services.resources.IdentityBrokerService;
 import org.keycloak.services.resources.RealmsResource;
 import org.keycloak.services.util.CookieHelper;
-import org.keycloak.common.util.Time;
 
-import javax.ws.rs.core.*;
+import javax.ws.rs.core.Cookie;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.NewCookie;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
 import java.net.URI;
 import java.util.LinkedList;
 import java.util.List;
@@ -125,7 +139,7 @@ public class AuthenticationManager {
             if (brokerId != null) {
                 IdentityProvider identityProvider = IdentityBrokerService.getIdentityProvider(session, realm, brokerId);
                 try {
-                    identityProvider.backchannelLogout(userSession, uriInfo, realm);
+                    identityProvider.backchannelLogout(session, userSession, uriInfo, realm);
                 } catch (Exception e) {
                 }
             }
@@ -221,7 +235,7 @@ public class AuthenticationManager {
         String brokerId = userSession.getNote(Details.IDENTITY_PROVIDER);
         if (brokerId != null) {
             IdentityProvider identityProvider = IdentityBrokerService.getIdentityProvider(session, realm, brokerId);
-            Response response = identityProvider.keycloakInitiatedBrowserLogout(userSession, uriInfo, realm);
+            Response response = identityProvider.keycloakInitiatedBrowserLogout(session, userSession, uriInfo, realm);
             if (response != null) return response;
         }
         return finishBrowserLogout(session, realm, userSession, uriInfo, connection, headers);
@@ -363,9 +377,9 @@ public class AuthenticationManager {
 
 
     public static Response redirectAfterSuccessfulFlow(KeycloakSession session, RealmModel realm, UserSessionModel userSession,
-                                                ClientSessionModel clientSession,
-                                                HttpRequest request, UriInfo uriInfo, ClientConnection clientConnection,
-                                                EventBuilder event) {
+                                                       ClientSessionModel clientSession,
+                                                       HttpRequest request, UriInfo uriInfo, ClientConnection clientConnection,
+                                                       EventBuilder event) {
         LoginProtocol protocol = session.getProvider(LoginProtocol.class, clientSession.getAuthMethod());
         protocol.setRealm(realm)
                 .setHttpHeaders(request.getHttpHeaders())
@@ -406,8 +420,8 @@ public class AuthenticationManager {
 
     }
     public static Response nextActionAfterAuthentication(KeycloakSession session, UserSessionModel userSession, ClientSessionModel clientSession,
-                                                  ClientConnection clientConnection,
-                                                  HttpRequest request, UriInfo uriInfo, EventBuilder event) {
+                                                         ClientConnection clientConnection,
+                                                         HttpRequest request, UriInfo uriInfo, EventBuilder event) {
         Response requiredAction = actionRequired(session, userSession, clientSession, clientConnection, request, uriInfo, event);
         if (requiredAction != null) return requiredAction;
         return finishedRequiredActions(session, userSession, clientSession, clientConnection, request, uriInfo, event);
@@ -472,8 +486,8 @@ public class AuthenticationManager {
 
 
     public static Response actionRequired(final KeycloakSession session, final UserSessionModel userSession, final ClientSessionModel clientSession,
-                                                         final ClientConnection clientConnection,
-                                                         final HttpRequest request, final UriInfo uriInfo, final EventBuilder event) {
+                                          final ClientConnection clientConnection,
+                                          final HttpRequest request, final UriInfo uriInfo, final EventBuilder event) {
         final RealmModel realm = clientSession.getRealm();
         final UserModel user = userSession.getUser();
         final ClientModel client = clientSession.getClient();
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 a1539ca..27d47b5 100755
--- a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
+++ b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
@@ -16,21 +16,22 @@
  */
 package org.keycloak.services.resources;
 
-import org.jboss.resteasy.annotations.cache.NoCache;
 import org.jboss.resteasy.spi.HttpRequest;
 import org.jboss.resteasy.spi.ResteasyProviderFactory;
 import org.keycloak.OAuth2Constants;
+import org.keycloak.authentication.AuthenticationProcessor;
 import org.keycloak.authentication.authenticators.broker.AbstractIdpAuthenticator;
 import org.keycloak.authentication.authenticators.broker.util.PostBrokerLoginConstants;
 import org.keycloak.authentication.authenticators.broker.util.SerializedBrokeredIdentityContext;
-import org.keycloak.common.ClientConnection;
-import org.keycloak.authentication.AuthenticationProcessor;
 import org.keycloak.broker.provider.AuthenticationRequest;
 import org.keycloak.broker.provider.BrokeredIdentityContext;
 import org.keycloak.broker.provider.IdentityBrokerException;
 import org.keycloak.broker.provider.IdentityProvider;
 import org.keycloak.broker.provider.IdentityProviderFactory;
 import org.keycloak.broker.provider.IdentityProviderMapper;
+import org.keycloak.broker.social.SocialIdentityProvider;
+import org.keycloak.common.ClientConnection;
+import org.keycloak.common.util.ObjectUtil;
 import org.keycloak.common.util.Time;
 import org.keycloak.events.Details;
 import org.keycloak.events.EventBuilder;
@@ -53,28 +54,30 @@ import org.keycloak.models.utils.FormMessage;
 import org.keycloak.protocol.oidc.TokenManager;
 import org.keycloak.provider.ProviderFactory;
 import org.keycloak.representations.AccessToken;
+import org.keycloak.services.ErrorPage;
+import org.keycloak.services.ErrorResponse;
+import org.keycloak.services.ServicesLogger;
+import org.keycloak.services.Urls;
 import org.keycloak.services.managers.AppAuthManager;
 import org.keycloak.services.managers.AuthenticationManager.AuthResult;
 import org.keycloak.services.managers.ClientSessionCode;
 import org.keycloak.services.messages.Messages;
-import org.keycloak.services.ErrorResponse;
-import org.keycloak.services.ErrorPage;
-import org.keycloak.services.ServicesLogger;
-import org.keycloak.services.Urls;
 import org.keycloak.services.util.CacheControlUtil;
 import org.keycloak.services.validation.Validation;
-import org.keycloak.broker.social.SocialIdentityProvider;
-import org.keycloak.common.util.ObjectUtil;
 import org.keycloak.util.JsonSerialization;
 
-import javax.ws.rs.*;
+import javax.ws.rs.GET;
+import javax.ws.rs.OPTIONS;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+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.Response.Status;
 import javax.ws.rs.core.UriBuilder;
 import javax.ws.rs.core.UriInfo;
-
 import java.io.IOException;
 import java.net.URI;
 import java.util.ArrayList;
@@ -227,7 +230,7 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
 
                     this.event.success();
 
-                    return corsResponse(identityProvider.retrieveToken(identity), clientModel);
+                    return corsResponse(identityProvider.retrieveToken(session, identity), clientModel);
                 }
 
                 return corsResponse(badRequest("Identity Provider [" + providerId + "] does not support this operation."), clientModel);
diff --git a/services/src/main/java/org/keycloak/social/twitter/TwitterIdentityProvider.java b/services/src/main/java/org/keycloak/social/twitter/TwitterIdentityProvider.java
index a48a9c8..b0c29b0 100755
--- a/services/src/main/java/org/keycloak/social/twitter/TwitterIdentityProvider.java
+++ b/services/src/main/java/org/keycloak/social/twitter/TwitterIdentityProvider.java
@@ -17,12 +17,13 @@
 package org.keycloak.social.twitter;
 
 import org.jboss.logging.Logger;
-import org.keycloak.common.ClientConnection;
 import org.keycloak.broker.oidc.OAuth2IdentityProviderConfig;
 import org.keycloak.broker.provider.AbstractIdentityProvider;
 import org.keycloak.broker.provider.AuthenticationRequest;
 import org.keycloak.broker.provider.BrokeredIdentityContext;
 import org.keycloak.broker.provider.IdentityBrokerException;
+import org.keycloak.broker.social.SocialIdentityProvider;
+import org.keycloak.common.ClientConnection;
 import org.keycloak.events.EventBuilder;
 import org.keycloak.events.EventType;
 import org.keycloak.models.ClientModel;
@@ -30,10 +31,9 @@ import org.keycloak.models.ClientSessionModel;
 import org.keycloak.models.FederatedIdentityModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
+import org.keycloak.services.ErrorPage;
 import org.keycloak.services.managers.ClientSessionCode;
 import org.keycloak.services.messages.Messages;
-import org.keycloak.services.ErrorPage;
-import org.keycloak.broker.social.SocialIdentityProvider;
 import twitter4j.Twitter;
 import twitter4j.TwitterFactory;
 import twitter4j.auth.AccessToken;
@@ -185,7 +185,7 @@ public class TwitterIdentityProvider extends AbstractIdentityProvider<OAuth2Iden
     }
 
     @Override
-    public Response retrieveToken(FederatedIdentityModel identity) {
+    public Response retrieveToken(KeycloakSession session, FederatedIdentityModel identity) {
         return Response.ok(identity.getToken()).type(MediaType.APPLICATION_JSON).build();
     }
 }
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 51a9044..b45213a 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
@@ -22,6 +22,7 @@ import org.junit.Before;
 import org.junit.ClassRule;
 import org.junit.Rule;
 import org.keycloak.authentication.authenticators.broker.IdpReviewProfileAuthenticatorFactory;
+import org.keycloak.common.util.Time;
 import org.keycloak.models.AuthenticatorConfigModel;
 import org.keycloak.models.FederatedIdentityModel;
 import org.keycloak.models.IdentityProviderModel;
@@ -54,17 +55,12 @@ import javax.mail.MessagingException;
 import javax.mail.Multipart;
 import javax.mail.internet.MimeMessage;
 import javax.ws.rs.core.UriBuilder;
-
 import java.io.IOException;
 import java.net.URI;
 import java.util.List;
 import java.util.Set;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
+import static org.junit.Assert.*;
 
 /**
  * @author pedroigor
@@ -115,6 +111,8 @@ public abstract class AbstractIdentityProviderTest {
 
     protected KeycloakSession session;
 
+    protected int logoutTimeOffset = 0;
+
     @Before
     public void onBefore() {
         this.session = brokerServerRule.startSession();
@@ -160,11 +158,26 @@ public abstract class AbstractIdentityProviderTest {
         assertEquals(getProviderId(), federatedIdentityModel.getIdentityProvider());
         assertEquals(federatedUser.getUsername(), federatedIdentityModel.getUserName());
 
-        driver.navigate().to("http://localhost:8081/test-app/logout");
+        // test access token timeot on logout
+        if (logoutTimeOffset > 0) {
+            Time.setOffset(logoutTimeOffset);
+        }
+        try {
+            driver.navigate().to("http://localhost:8081/test-app/logout");
+        } finally {
+            Time.setOffset(0);
+        }
+
+        String afterLogoutUrl = driver.getCurrentUrl();
+        String afterLogoutPageSource = driver.getPageSource();
+        System.out.println("afterLogoutUrl: " + afterLogoutUrl);
+        //System.out.println("after logout page source: " + afterLogoutPageSource);
+
         driver.navigate().to("http://localhost:8081/test-app");
 
         assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/auth"));
         return federatedUser;
+
     }
 
 
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 308cb85..ad3e9ff 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
@@ -19,23 +19,25 @@ package org.keycloak.testsuite.broker;
 
 import org.junit.ClassRule;
 import org.junit.Test;
+import org.keycloak.admin.client.Keycloak;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.representations.AccessTokenResponse;
+import org.keycloak.representations.idm.IdentityProviderRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.services.Urls;
 import org.keycloak.services.managers.RealmManager;
 import org.keycloak.testsuite.Constants;
+import org.keycloak.testsuite.KeycloakServer;
 import org.keycloak.testsuite.pages.AccountApplicationsPage;
 import org.keycloak.testsuite.pages.OAuthGrantPage;
 import org.keycloak.testsuite.rule.AbstractKeycloakRule;
 import org.keycloak.testsuite.rule.WebResource;
-import org.keycloak.testsuite.KeycloakServer;
 import org.keycloak.util.JsonSerialization;
 import org.openqa.selenium.NoSuchElementException;
 
-import java.io.IOException;
-
 import javax.ws.rs.core.UriBuilder;
+import java.io.IOException;
 
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.fail;
@@ -118,6 +120,26 @@ public class OIDCKeyCloakServerBrokerBasicTest extends AbstractKeycloakIdentityP
     }
 
     @Test
+    public void testLogoutWorksWithTokenTimeout() {
+        Keycloak keycloak = Keycloak.getInstance("http://localhost:8081/auth", "master", "admin", "admin", org.keycloak.models.Constants.ADMIN_CLI_CLIENT_ID);
+        RealmRepresentation realm = keycloak.realm("realm-with-oidc-identity-provider").toRepresentation();
+        assertNotNull(realm);
+        int oldLifespan = realm.getAccessTokenLifespan();
+        realm.setAccessTokenLifespan(1);
+        keycloak.realm("realm-with-oidc-identity-provider").update(realm);
+        IdentityProviderRepresentation idp =  keycloak.realm("realm-with-broker").identityProviders().get("kc-oidc-idp").toRepresentation();
+        idp.getConfig().put("backchannelSupported", "false");
+        keycloak.realm("realm-with-broker").identityProviders().get("kc-oidc-idp").update(idp);
+        logoutTimeOffset = 2;
+        super.testSuccessfulAuthentication();
+        logoutTimeOffset = 0;
+        realm.setAccessTokenLifespan(oldLifespan);
+        keycloak.realm("realm-with-oidc-identity-provider").update(realm);
+        idp.getConfig().put("backchannelSupported", "true");
+        keycloak.realm("realm-with-broker").identityProviders().get("kc-oidc-idp").update(idp);
+    }
+
+    @Test
     public void testSuccessfulAuthenticationWithoutUpdateProfile() {
         super.testSuccessfulAuthenticationWithoutUpdateProfile();
     }
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
index f5888fa..058f101 100755
--- 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
@@ -20,6 +20,7 @@ import org.keycloak.broker.provider.AbstractIdentityProvider;
 import org.keycloak.broker.provider.AuthenticationRequest;
 import org.keycloak.models.FederatedIdentityModel;
 import org.keycloak.models.IdentityProviderModel;
+import org.keycloak.models.KeycloakSession;
 
 import javax.ws.rs.core.Response;
 
@@ -38,7 +39,7 @@ public class CustomIdentityProvider extends AbstractIdentityProvider<IdentityPro
     }
 
     @Override
-    public Response retrieveToken(FederatedIdentityModel identity) {
+    public Response retrieveToken(KeycloakSession session, FederatedIdentityModel identity) {
         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
index c74a33b..869c226 100755
--- 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
@@ -18,9 +18,10 @@ package org.keycloak.testsuite.broker.provider.social;
 
 import org.keycloak.broker.provider.AbstractIdentityProvider;
 import org.keycloak.broker.provider.AuthenticationRequest;
+import org.keycloak.broker.social.SocialIdentityProvider;
 import org.keycloak.models.FederatedIdentityModel;
 import org.keycloak.models.IdentityProviderModel;
-import org.keycloak.broker.social.SocialIdentityProvider;
+import org.keycloak.models.KeycloakSession;
 
 import javax.ws.rs.core.Response;
 
@@ -39,7 +40,7 @@ public class CustomSocialProvider extends AbstractIdentityProvider<IdentityProvi
     }
 
     @Override
-    public Response retrieveToken(FederatedIdentityModel identity) {
+    public Response retrieveToken(KeycloakSession session, FederatedIdentityModel identity) {
         return null;
     }
 }