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 ce3a27d5c2..5532606270 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 } @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 0fa49935da..b14572ee5d 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 @@ -79,9 +79,9 @@ public interface IdentityProvider extends Provi * @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 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 e5ac7fdcc8..fba8e6431f 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 extends Pro *

Creates an {@link IdentityProvider} based on the configuration from * inputStream.

* - * @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 182099b48e..bad6d199b9 100755 --- a/services/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java +++ b/services/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java @@ -54,6 +54,7 @@ import java.util.regex.Pattern; public abstract class AbstractOAuth2IdentityProvider extends AbstractIdentityProvider { 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 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 +366,10 @@ public class OIDCIdentityProvider extends AbstractOAuth2IdentityProvider 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 5605ea6e0d..3d9a536caf 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 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 308cb85572..3349e8ccd6 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,9 +19,13 @@ package org.keycloak.testsuite.broker; import org.junit.ClassRule; import org.junit.Test; +import org.keycloak.admin.client.Keycloak; +import org.keycloak.models.IdentityProviderModel; 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; @@ -34,6 +38,7 @@ import org.keycloak.util.JsonSerialization; import org.openqa.selenium.NoSuchElementException; import java.io.IOException; +import java.util.List; import javax.ws.rs.core.UriBuilder; @@ -117,6 +122,26 @@ public class OIDCKeyCloakServerBrokerBasicTest extends AbstractKeycloakIdentityP super.testSuccessfulAuthentication(); } + @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 f5888faa7e..058f1011fe 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