diff --git a/core/src/main/java/org/keycloak/TokenVerifier.java b/core/src/main/java/org/keycloak/TokenVerifier.java index d45e0b2878..fa4bd09adf 100755 --- a/core/src/main/java/org/keycloak/TokenVerifier.java +++ b/core/src/main/java/org/keycloak/TokenVerifier.java @@ -338,7 +338,7 @@ public class TokenVerifier { } /** - * @deprecated This method is here only for backward compatibility with previous version of {@code TokenVerifier}. + * * @return This token verifier */ public TokenVerifier tokenType(String tokenType) { diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/LogoutEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/LogoutEndpoint.java index 9ed2c2ac9a..10fd58d20c 100755 --- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/LogoutEndpoint.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/LogoutEndpoint.java @@ -22,7 +22,9 @@ import org.jboss.resteasy.annotations.cache.NoCache; import org.jboss.resteasy.spi.HttpRequest; import org.keycloak.OAuth2Constants; import org.keycloak.OAuthErrorException; +import org.keycloak.TokenVerifier; import org.keycloak.common.ClientConnection; +import org.keycloak.common.VerificationException; import org.keycloak.events.Details; import org.keycloak.events.Errors; import org.keycloak.events.EventBuilder; @@ -120,12 +122,13 @@ public class LogoutEndpoint { if (encodedIdToken != null) { try { idToken = tokenManager.verifyIDTokenSignature(session, encodedIdToken); + TokenVerifier.createWithoutSignature(idToken).tokenType(TokenUtil.TOKEN_TYPE_ID).verify(); userSession = session.sessions().getUserSession(realm, idToken.getSessionState()); if (userSession != null) { checkTokenIssuedAt(idToken, userSession); } - } catch (OAuthErrorException e) { + } catch (OAuthErrorException | VerificationException e) { event.event(EventType.LOGOUT); event.error(Errors.INVALID_TOKEN); return ErrorPage.error(session, null, Response.Status.BAD_REQUEST, Messages.SESSION_NOT_ACTIVE); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/BrokerLinkAndTokenExchangeTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/BrokerLinkAndTokenExchangeTest.java index badf121fa2..f0696cb447 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/BrokerLinkAndTokenExchangeTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/BrokerLinkAndTokenExchangeTest.java @@ -549,11 +549,12 @@ public class BrokerLinkAndTokenExchangeTest extends AbstractServletsAdapterTest .param(OAuth2Constants.SUBJECT_TOKEN, accessToken) .param(OAuth2Constants.SUBJECT_TOKEN_TYPE, OAuth2Constants.JWT_TOKEN_TYPE) .param(OAuth2Constants.SUBJECT_ISSUER, PARENT_IDP) + .param(OAuth2Constants.SCOPE, OAuth2Constants.SCOPE_OPENID) )); Assert.assertEquals(200, response.getStatus()); AccessTokenResponse tokenResponse = response.readEntity(AccessTokenResponse.class); - String exchangedAccessToken = tokenResponse.getToken(); + String idToken = tokenResponse.getIdToken(); JWSInput jws = new JWSInput(tokenResponse.getToken()); AccessToken token = jws.readJsonContent(AccessToken.class); response.close(); @@ -585,7 +586,7 @@ public class BrokerLinkAndTokenExchangeTest extends AbstractServletsAdapterTest // test logout response = childLogoutWebTarget(httpClient) - .queryParam("id_token_hint", exchangedAccessToken) + .queryParam("id_token_hint", idToken) .request() .get(); response.close(); @@ -606,11 +607,12 @@ public class BrokerLinkAndTokenExchangeTest extends AbstractServletsAdapterTest .param(OAuth2Constants.SUBJECT_TOKEN, accessToken) .param(OAuth2Constants.SUBJECT_TOKEN_TYPE, OAuth2Constants.JWT_TOKEN_TYPE) .param(OAuth2Constants.SUBJECT_ISSUER, PARENT_IDP) + .param(OAuth2Constants.SCOPE, OAuth2Constants.SCOPE_OPENID) )); Assert.assertEquals(200, response.getStatus()); AccessTokenResponse tokenResponse = response.readEntity(AccessTokenResponse.class); - String exchangedAccessToken = tokenResponse.getToken(); + String idToken = tokenResponse.getIdToken(); JWSInput jws = new JWSInput(tokenResponse.getToken()); AccessToken token = jws.readJsonContent(AccessToken.class); response.close(); @@ -625,7 +627,7 @@ public class BrokerLinkAndTokenExchangeTest extends AbstractServletsAdapterTest // test logout response = childLogoutWebTarget(httpClient) - .queryParam("id_token_hint", exchangedAccessToken) + .queryParam("id_token_hint", idToken) .request() .get(); response.close(); @@ -645,11 +647,12 @@ public class BrokerLinkAndTokenExchangeTest extends AbstractServletsAdapterTest .param(OAuth2Constants.GRANT_TYPE, OAuth2Constants.TOKEN_EXCHANGE_GRANT_TYPE) .param(OAuth2Constants.SUBJECT_TOKEN, accessToken) .param(OAuth2Constants.SUBJECT_TOKEN_TYPE, OAuth2Constants.JWT_TOKEN_TYPE) + .param(OAuth2Constants.SCOPE, OAuth2Constants.SCOPE_OPENID) )); Assert.assertEquals(200, response.getStatus()); AccessTokenResponse tokenResponse = response.readEntity(AccessTokenResponse.class); - String exchangedAccessToken = tokenResponse.getToken(); + String idToken = tokenResponse.getIdToken(); JWSInput jws = new JWSInput(tokenResponse.getToken()); AccessToken token = jws.readJsonContent(AccessToken.class); response.close(); @@ -664,7 +667,7 @@ public class BrokerLinkAndTokenExchangeTest extends AbstractServletsAdapterTest // test logout response = childLogoutWebTarget(httpClient) - .queryParam("id_token_hint", exchangedAccessToken) + .queryParam("id_token_hint", idToken) .request() .get(); response.close(); @@ -733,21 +736,22 @@ public class BrokerLinkAndTokenExchangeTest extends AbstractServletsAdapterTest .param(OAuth2Constants.SUBJECT_TOKEN, accessToken) .param(OAuth2Constants.SUBJECT_TOKEN_TYPE, OAuth2Constants.JWT_TOKEN_TYPE) .param(OAuth2Constants.SUBJECT_ISSUER, PARENT_IDP) + .param(OAuth2Constants.SCOPE, OAuth2Constants.SCOPE_OPENID) )); Assert.assertEquals(statusCode, response.getStatus()); if (statusCode != Response.Status.NOT_IMPLEMENTED.getStatusCode()) { AccessTokenResponse tokenResponse = response.readEntity(AccessTokenResponse.class); - String exchangedAccessToken = tokenResponse.getToken(); - Assert.assertNotNull(exchangedAccessToken); + String idToken = tokenResponse.getIdToken(); + Assert.assertNotNull(idToken); response.close(); Assert.assertEquals(1, adminClient.realm(CHILD_IDP).getClientSessionStats().size()); // test logout response = childLogoutWebTarget(httpClient) - .queryParam("id_token_hint", exchangedAccessToken) + .queryParam("id_token_hint", idToken) .request() .get(); response.close(); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/AbstractBaseBrokerTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/AbstractBaseBrokerTest.java index a8eb0028ad..b4896844e4 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/AbstractBaseBrokerTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/AbstractBaseBrokerTest.java @@ -55,6 +55,7 @@ import org.keycloak.testsuite.util.MailServer; import org.keycloak.testsuite.util.UserBuilder; import org.openqa.selenium.TimeoutException; +import javax.ws.rs.core.Response; import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriBuilderException; import java.net.URI; @@ -162,6 +163,28 @@ public abstract class AbstractBaseBrokerTest extends AbstractKeycloakTest { consumerRealm.update(master); } + protected void addClientsToProviderAndConsumer() { + List clients = bc.createProviderClients(suiteContext); + final RealmResource providerRealm = adminClient.realm(bc.providerRealmName()); + for (ClientRepresentation client : clients) { + log.debug("adding client " + client.getClientId() + " to realm " + bc.providerRealmName()); + + final Response resp = providerRealm.clients().create(client); + resp.close(); + } + + clients = bc.createConsumerClients(suiteContext); + if (clients != null) { + RealmResource consumerRealm = adminClient.realm(bc.consumerRealmName()); + for (ClientRepresentation client : clients) { + log.debug("adding client " + client.getClientId() + " to realm " + bc.consumerRealmName()); + + Response resp = consumerRealm.clients().create(client); + resp.close(); + } + } + } + @Before public void beforeBrokerTest() { importRealm(bc.createConsumerRealm()); @@ -195,24 +218,24 @@ public abstract class AbstractBaseBrokerTest extends AbstractKeycloakTest { protected void logInAsUserInIDP() { driver.navigate().to(getAccountUrl(bc.consumerRealmName())); + logInWithBroker(bc); + } + protected void logInWithBroker(BrokerConfiguration bc) { log.debug("Clicking social " + bc.getIDPAlias()); loginPage.clickSocial(bc.getIDPAlias()); - waitForPage(driver, "log in to", true); - - Assert.assertTrue("Driver should be on the provider realm page right now", - driver.getCurrentUrl().contains("/auth/realms/" + bc.providerRealmName() + "/")); - log.debug("Logging in"); loginPage.login(bc.getUserLogin(), bc.getUserPassword()); } - /** Logs in the IDP and updates account information */ protected void logInAsUserInIDPForFirstTime() { logInAsUserInIDP(); + updateAccountInformation(); + } + protected void updateAccountInformation() { waitForPage(driver, "update account information", false); Assert.assertTrue(updateAccountInformationPage.isCurrent()); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/AbstractInitializedBaseBrokerTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/AbstractInitializedBaseBrokerTest.java index 51e3cbc663..2a75f507f4 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/AbstractInitializedBaseBrokerTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/AbstractInitializedBaseBrokerTest.java @@ -23,14 +23,11 @@ import org.keycloak.admin.client.resource.IdentityProviderResource; import org.keycloak.admin.client.resource.RealmResource; import org.keycloak.models.utils.DefaultAuthenticationFlows; import org.keycloak.representations.idm.AuthenticationExecutionInfoRepresentation; -import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.representations.idm.UserRepresentation; -import java.util.List; import java.util.function.BiConsumer; import static org.keycloak.testsuite.admin.ApiUtil.createUserWithAdminClient; import static org.keycloak.testsuite.admin.ApiUtil.resetUserPassword; -import static org.keycloak.testsuite.broker.BrokerTestTools.waitForPage; /** * @author Stan Silvert ssilvert@redhat.com (C) 2019 Red Hat Inc. @@ -61,38 +58,11 @@ public abstract class AbstractInitializedBaseBrokerTest extends AbstractBaseBrok realm.identityProviders().create(bc.setUpIdentityProvider(suiteContext)).close(); identityProviderResource = realm.identityProviders().get(bc.getIDPAlias()); - // addClients - List clients = bc.createProviderClients(suiteContext); - if (clients != null) { - RealmResource providerRealm = adminClient.realm(bc.providerRealmName()); - for (ClientRepresentation client : clients) { - log.debug("adding client " + client.getClientId()+ " to realm " + bc.providerRealmName()); - - providerRealm.clients().create(client).close(); - } - } - - clients = bc.createConsumerClients(suiteContext); - if (clients != null) { - RealmResource consumerRealm = adminClient.realm(bc.consumerRealmName()); - for (ClientRepresentation client : clients) { - log.debug("adding client " + client.getClientId() + " to realm " + bc.consumerRealmName()); - - consumerRealm.clients().create(client).close(); - } - } + addClientsToProviderAndConsumer(); testContext.setInitialized(true); } - protected void logInWithBroker(BrokerConfiguration bc) { - log.debug("Clicking social " + bc.getIDPAlias()); - loginPage.clickSocial(bc.getIDPAlias()); - waitForPage(driver, "log in to", true); - log.debug("Logging in"); - loginPage.login(bc.getUserLogin(), bc.getUserPassword()); - } - protected void updateExecutions(BiConsumer action) { AuthenticationManagementResource flows = adminClient.realm(bc.consumerRealmName()).flows(); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/AbstractUserAttributeMapperTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/AbstractUserAttributeMapperTest.java index 11fb3fdb0f..244fe4c3a2 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/AbstractUserAttributeMapperTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/AbstractUserAttributeMapperTest.java @@ -3,7 +3,6 @@ package org.keycloak.testsuite.broker; import org.keycloak.admin.client.resource.IdentityProviderResource; import org.keycloak.admin.client.resource.RealmResource; import org.keycloak.admin.client.resource.UsersResource; -import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.representations.idm.IdentityProviderMapperRepresentation; import org.keycloak.representations.idm.IdentityProviderRepresentation; import org.keycloak.representations.idm.UserRepresentation; @@ -63,27 +62,7 @@ public abstract class AbstractUserAttributeMapperTest extends AbstractBaseBroker @Before public void addClients() { - List clients = bc.createProviderClients(suiteContext); - if (clients != null) { - RealmResource providerRealm = adminClient.realm(bc.providerRealmName()); - for (ClientRepresentation client : clients) { - log.debug("adding client " + client.getName() + " to realm " + bc.providerRealmName()); - - Response resp = providerRealm.clients().create(client); - resp.close(); - } - } - - clients = bc.createConsumerClients(suiteContext); - if (clients != null) { - RealmResource consumerRealm = adminClient.realm(bc.consumerRealmName()); - for (ClientRepresentation client : clients) { - log.debug("adding client " + client.getName() + " to realm " + bc.consumerRealmName()); - - Response resp = consumerRealm.clients().create(client); - resp.close(); - } - } + addClientsToProviderAndConsumer(); } protected void createUserInProviderRealm(Map> attributes) { diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOIDCBrokerWithSignatureTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOIDCBrokerWithSignatureTest.java index 34292ee638..b111490d34 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOIDCBrokerWithSignatureTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOIDCBrokerWithSignatureTest.java @@ -17,8 +17,6 @@ package org.keycloak.testsuite.broker; -import java.util.List; - import javax.ws.rs.core.Response; import javax.ws.rs.core.UriBuilder; @@ -32,7 +30,6 @@ import org.keycloak.crypto.Algorithm; import org.keycloak.keys.KeyProvider; import org.keycloak.keys.PublicKeyStorageUtils; import org.keycloak.protocol.oidc.OIDCLoginProtocolService; -import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.representations.idm.ComponentRepresentation; import org.keycloak.representations.idm.IdentityProviderRepresentation; import org.keycloak.representations.idm.KeysMetadataRepresentation; @@ -86,27 +83,7 @@ public class KcOIDCBrokerWithSignatureTest extends AbstractBaseBrokerTest { @Before public void addClients() { - List clients = bc.createProviderClients(suiteContext); - if (clients != null) { - RealmResource providerRealm = adminClient.realm(bc.providerRealmName()); - for (ClientRepresentation client : clients) { - log.debug("adding client " + client.getClientId() + " to realm " + bc.providerRealmName()); - - Response resp = providerRealm.clients().create(client); - resp.close(); - } - } - - clients = bc.createConsumerClients(suiteContext); - if (clients != null) { - RealmResource consumerRealm = adminClient.realm(bc.consumerRealmName()); - for (ClientRepresentation client : clients) { - log.debug("adding client " + client.getClientId() + " to realm " + bc.consumerRealmName()); - - Response resp = consumerRealm.clients().create(client); - resp.close(); - } - } + addClientsToProviderAndConsumer(); } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerLogoutTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerLogoutTest.java index addc59a20c..f020143ab4 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerLogoutTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerLogoutTest.java @@ -1,22 +1,29 @@ package org.keycloak.testsuite.broker; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.keycloak.OAuth2Constants; import org.keycloak.admin.client.resource.RealmResource; -import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.services.managers.AuthenticationManager; -import org.openqa.selenium.Cookie; - -import javax.ws.rs.core.Response; -import java.util.List; +import org.keycloak.services.util.CookieHelper; +import org.keycloak.testsuite.AssertEvents; +import org.keycloak.testsuite.util.OAuthClient; +import static org.junit.Assert.assertEquals; import static org.keycloak.testsuite.admin.ApiUtil.createUserWithAdminClient; import static org.keycloak.testsuite.admin.ApiUtil.resetUserPassword; +import static org.keycloak.testsuite.broker.BrokerTestConstants.REALM_CONS_NAME; import static org.keycloak.testsuite.broker.BrokerTestConstants.REALM_PROV_NAME; +import static org.keycloak.testsuite.broker.BrokerTestTools.getAuthRoot; import static org.keycloak.testsuite.broker.BrokerTestTools.waitForPage; public class KcOidcBrokerLogoutTest extends AbstractBaseBrokerTest { + + @Rule + public AssertEvents events = new AssertEvents(this); + @Override protected BrokerConfiguration getBrokerConfiguration() { return KcOidcBrokerConfiguration.INSTANCE; @@ -48,14 +55,7 @@ public class KcOidcBrokerLogoutTest extends AbstractBaseBrokerTest { @Before public void addClients() { - final List clients = bc.createProviderClients(suiteContext); - final RealmResource providerRealm = adminClient.realm(bc.providerRealmName()); - for (final ClientRepresentation client : clients) { - log.debug("adding client " + client.getClientId() + " to realm " + bc.providerRealmName()); - - final Response resp = providerRealm.clients().create(client); - resp.close(); - } + addClientsToProviderAndConsumer(); } @Test @@ -91,15 +91,25 @@ public class KcOidcBrokerLogoutTest extends AbstractBaseBrokerTest { @Test public void logoutAfterBrowserRestart() { - logInAsUserInIDPForFirstTime(); - assertLoggedInAccountManagement(); + driver.navigate().to(getLoginUrl(bc.consumerRealmName(), "broker-app")); + logInWithBroker(bc); + updateAccountInformation(); - Cookie identityCookie = driver.manage().getCookieNamed(AuthenticationManager.KEYCLOAK_IDENTITY_COOKIE); - String idToken = identityCookie.getValue(); + // Exchange code from "broker-app" client of "consumer" realm for the tokens + String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE); + OAuthClient.AccessTokenResponse response = oauth.realm(bc.consumerRealmName()) + .clientId("broker-app") + .redirectUri(getAuthRoot(suiteContext) + "/auth/realms/" + REALM_CONS_NAME + "/app") + .doAccessTokenRequest(code, "broker-app-secret"); + assertEquals(200, response.getStatusCode()); + + String idToken = response.getIdToken(); // simulate browser restart by deleting an identity cookie - log.debugf("Deleting %s cookie", AuthenticationManager.KEYCLOAK_IDENTITY_COOKIE); + log.debugf("Deleting %s and %s cookies", AuthenticationManager.KEYCLOAK_IDENTITY_COOKIE, + AuthenticationManager.KEYCLOAK_IDENTITY_COOKIE + CookieHelper.LEGACY_COOKIE); driver.manage().deleteCookieNamed(AuthenticationManager.KEYCLOAK_IDENTITY_COOKIE); + driver.manage().deleteCookieNamed(AuthenticationManager.KEYCLOAK_IDENTITY_COOKIE + CookieHelper.LEGACY_COOKIE); logoutFromRealm(bc.consumerRealmName(), null, idToken); driver.navigate().to(getAccountUrl(REALM_PROV_NAME)); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/OidcAdvancedClaimToRoleMapperTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/OidcAdvancedClaimToRoleMapperTest.java index 42e827a5b2..fbf5e36925 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/OidcAdvancedClaimToRoleMapperTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/OidcAdvancedClaimToRoleMapperTest.java @@ -71,27 +71,7 @@ public class OidcAdvancedClaimToRoleMapperTest extends AbstractBaseBrokerTest { @Before public void addClients() { - List clients = bc.createProviderClients(suiteContext); - if (clients != null) { - RealmResource providerRealm = adminClient.realm(bc.providerRealmName()); - for (ClientRepresentation client : clients) { - log.debug("adding client " + client.getName() + " to realm " + bc.providerRealmName()); - - Response resp = providerRealm.clients().create(client); - resp.close(); - } - } - - clients = bc.createConsumerClients(suiteContext); - if (clients != null) { - RealmResource consumerRealm = adminClient.realm(bc.consumerRealmName()); - for (ClientRepresentation client : clients) { - log.debug("adding client " + client.getName() + " to realm " + bc.consumerRealmName()); - - Response resp = consumerRealm.clients().create(client); - resp.close(); - } - } + addClientsToProviderAndConsumer(); } @Test diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/LogoutTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/LogoutTest.java index 3cd162a3d1..14e1293c9e 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/LogoutTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/LogoutTest.java @@ -22,7 +22,9 @@ import org.junit.Rule; import org.junit.Test; import org.keycloak.OAuth2Constants; +import org.keycloak.OAuthErrorException; import org.keycloak.common.util.Time; +import org.keycloak.events.Details; import org.keycloak.jose.jws.JWSHeader; import org.keycloak.jose.jws.JWSInput; import org.keycloak.protocol.oidc.OIDCLoginProtocol; @@ -46,6 +48,7 @@ import org.apache.http.impl.client.HttpClientBuilder; import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; import static org.keycloak.testsuite.admin.AbstractAdminTest.loadJson; +import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlEquals; /** * @author Stian Thorgersen @@ -110,6 +113,39 @@ public class LogoutTest extends AbstractKeycloakTest { } } + @Test + public void logoutIDTokenHint() { + oauth.doLogin("test-user@localhost", "password"); + + String sessionId = events.expectLogin().assertEvent().getSessionId(); + + String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE); + OAuthClient.AccessTokenResponse tokenResponse = oauth.doAccessTokenRequest(code, "password"); + String idToken = tokenResponse.getIdToken(); + + events.clear(); + + driver.navigate().to(oauth.getLogoutUrl().redirectUri(oauth.APP_AUTH_ROOT).idTokenHint(idToken).build()); + events.expectLogout(sessionId).detail(Details.REDIRECT_URI, oauth.APP_AUTH_ROOT).assertEvent(); + + assertCurrentUrlEquals(oauth.APP_AUTH_ROOT); + } + + @Test + public void browserLogoutWithAccessToken() { + oauth.doLogin("test-user@localhost", "password"); + + String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE); + OAuthClient.AccessTokenResponse tokenResponse = oauth.doAccessTokenRequest(code, "password"); + String accessToken = tokenResponse.getAccessToken(); + + events.clear(); + + driver.navigate().to(oauth.getLogoutUrl().redirectUri(oauth.APP_AUTH_ROOT).idTokenHint(accessToken).build()); + + events.expectLogoutError(OAuthErrorException.INVALID_TOKEN).assertEvent(); + } + @Test public void postLogoutWithRefreshTokenAfterUserSessionLogoutAndLoginAgain() throws Exception { // Login