mirror of
https://github.com/keycloak/keycloak.git
synced 2026-01-10 15:32:05 -03:30
parent
8f54f03f17
commit
f90fbb9c71
@ -494,6 +494,9 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
|
||||
case REGISTER:
|
||||
b = UriBuilder.fromUri(Urls.realmRegisterPage(baseUri, realm.getName()));
|
||||
break;
|
||||
case LOGOUT_CONFIRM:
|
||||
b = UriBuilder.fromUri(Urls.logoutConfirm(baseUri, realm.getName()));
|
||||
break;
|
||||
default:
|
||||
b = UriBuilder.fromUri(baseUri).path(uriInfo.getPath());
|
||||
break;
|
||||
|
||||
@ -38,6 +38,7 @@ import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.models.utils.SystemClientUtil;
|
||||
import org.keycloak.protocol.oidc.BackchannelLogoutResponse;
|
||||
@ -65,6 +66,7 @@ import org.keycloak.services.messages.Messages;
|
||||
import org.keycloak.services.resources.Cors;
|
||||
import org.keycloak.services.resources.LogoutSessionCodeChecks;
|
||||
import org.keycloak.services.resources.SessionCodeChecks;
|
||||
import org.keycloak.services.util.LocaleUtil;
|
||||
import org.keycloak.services.util.MtlsHoKTokenUtil;
|
||||
import org.keycloak.sessions.AuthenticationSessionModel;
|
||||
import org.keycloak.sessions.RootAuthenticationSessionModel;
|
||||
@ -258,9 +260,12 @@ public class LogoutEndpoint {
|
||||
LoginFormsProvider loginForm = session.getProvider(LoginFormsProvider.class)
|
||||
.setAuthenticationSession(logoutSession);
|
||||
|
||||
UserSessionModel userSession = null;
|
||||
|
||||
// Check if we have session in the browser. If yes and it is different session than referenced by id_token_hint, the confirmation should be displayed
|
||||
AuthenticationManager.AuthResult authResult = AuthenticationManager.authenticateIdentityCookie(session, realm, false);
|
||||
if (authResult != null) {
|
||||
userSession = authResult.getSession();
|
||||
if (idToken != null && idToken.getSessionState() != null && !idToken.getSessionState().equals(authResult.getSession().getId())) {
|
||||
forcedConfirmation = true;
|
||||
}
|
||||
@ -272,6 +277,17 @@ public class LogoutEndpoint {
|
||||
}
|
||||
}
|
||||
|
||||
if (userSession == null && idToken != null && idToken.getSessionState() != null) {
|
||||
userSession = session.sessions().getUserSession(realm, idToken.getSessionState());
|
||||
}
|
||||
|
||||
// Try to figure user because of localization
|
||||
if (userSession != null) {
|
||||
UserModel user = userSession.getUser();
|
||||
logoutSession.setAuthenticatedUser(user);
|
||||
loginForm.setUser(user);
|
||||
}
|
||||
|
||||
// Logout confirmation screen will be displayed to the user in this case
|
||||
if (confirmationNeeded || forcedConfirmation) {
|
||||
return displayLogoutConfirmationScreen(loginForm, logoutSession);
|
||||
@ -297,6 +313,7 @@ public class LogoutEndpoint {
|
||||
* @return response
|
||||
*/
|
||||
@POST
|
||||
@NoCache
|
||||
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
public Response logout() {
|
||||
MultivaluedMap<String, String> form = request.getDecodedFormParameters();
|
||||
@ -315,6 +332,7 @@ public class LogoutEndpoint {
|
||||
|
||||
@Path("/logout-confirm")
|
||||
@POST
|
||||
@NoCache
|
||||
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
public Response logoutConfirmAction() {
|
||||
MultivaluedMap<String, String> formData = request.getDecodedFormParameters();
|
||||
@ -327,7 +345,7 @@ public class LogoutEndpoint {
|
||||
|
||||
SessionCodeChecks checks = new LogoutSessionCodeChecks(realm, session.getContext().getUri(), request, clientConnection, session, event, code, clientId, tabId);
|
||||
checks.initialVerify();
|
||||
if (!checks.verifyActiveAndValidAction(AuthenticationSessionModel.Action.LOGGING_OUT.name(), ClientSessionCode.ActionType.USER) || !formData.containsKey("confirmLogout")) {
|
||||
if (!checks.verifyActiveAndValidAction(AuthenticationSessionModel.Action.LOGGING_OUT.name(), ClientSessionCode.ActionType.USER) || !checks.isActionRequest() || !formData.containsKey("confirmLogout")) {
|
||||
AuthenticationSessionModel logoutSession = checks.getAuthenticationSession();
|
||||
logger.debugf("Failed verification during logout. logoutSessionId=%s, clientId=%s, tabId=%s",
|
||||
logoutSession != null ? logoutSession.getParentSession().getId() : "unknown", clientId, tabId);
|
||||
@ -347,6 +365,48 @@ public class LogoutEndpoint {
|
||||
}
|
||||
|
||||
|
||||
// Typically shown when user changes localization on the logout confirmation screen
|
||||
@Path("/logout-confirm")
|
||||
@NoCache
|
||||
@GET
|
||||
public Response logoutConfirmGet() {
|
||||
event.event(EventType.LOGOUT);
|
||||
|
||||
String clientId = session.getContext().getUri().getQueryParameters().getFirst(Constants.CLIENT_ID);
|
||||
String tabId = session.getContext().getUri().getQueryParameters().getFirst(Constants.TAB_ID);
|
||||
|
||||
logger.tracef("Changing localization by user during logout. clientId=%s, tabId=%s, kc_locale: %s", clientId, tabId, session.getContext().getUri().getQueryParameters().getFirst(LocaleSelectorProvider.KC_LOCALE_PARAM));
|
||||
|
||||
SessionCodeChecks checks = new LogoutSessionCodeChecks(realm, session.getContext().getUri(), request, clientConnection, session, event, null, clientId, tabId);
|
||||
AuthenticationSessionModel logoutSession = checks.initialVerifyAuthSession();
|
||||
if (logoutSession == null) {
|
||||
logger.debugf("Failed verification when changing locale logout. clientId=%s, tabId=%s", clientId, tabId);
|
||||
|
||||
LoginFormsProvider loginForm = session.getProvider(LoginFormsProvider.class);
|
||||
if (clientId == null || clientId.equals(SystemClientUtil.getSystemClient(realm).getClientId())) {
|
||||
// Cleanup system client URL to avoid links to account management
|
||||
loginForm.setAttribute(Constants.SKIP_LINK, true);
|
||||
}
|
||||
|
||||
AuthenticationManager.AuthResult authResult = AuthenticationManager.authenticateIdentityCookie(session, realm, false);
|
||||
if (authResult != null) {
|
||||
return ErrorPage.error(session, logoutSession, Response.Status.BAD_REQUEST, Messages.FAILED_LOGOUT);
|
||||
} else {
|
||||
// Probably changing locale on logout screen after logout was already performed. If there is no session in the browser, we can just display that logout was already finished
|
||||
return loginForm.setSuccess(Messages.SUCCESS_LOGOUT).createInfoPage();
|
||||
}
|
||||
}
|
||||
|
||||
LocaleUtil.processLocaleParam(session, realm, logoutSession);
|
||||
|
||||
LoginFormsProvider loginForm = session.getProvider(LoginFormsProvider.class)
|
||||
.setAuthenticationSession(logoutSession)
|
||||
.setUser(logoutSession.getAuthenticatedUser());
|
||||
|
||||
return displayLogoutConfirmationScreen(loginForm, logoutSession);
|
||||
}
|
||||
|
||||
|
||||
// Method triggered after user eventually confirmed that he wants to logout and all other checks were done
|
||||
private Response doBrowserLogout(AuthenticationSessionModel logoutSession) {
|
||||
UserSessionModel userSession = null;
|
||||
|
||||
@ -374,10 +374,10 @@ public class AuthenticationManager {
|
||||
} else {
|
||||
logoutAuthSession = rootLogoutSession.createAuthenticationSession(client);
|
||||
logoutAuthSession.setAction(AuthenticationSessionModel.Action.LOGGING_OUT.name());
|
||||
session.getContext().setClient(client);
|
||||
logger.tracef("Creating logout session for client '%s'. Authentication session id: %s", client.getClientId(), rootLogoutSession.getId());
|
||||
}
|
||||
session.getContext().setAuthenticationSession(logoutAuthSession);
|
||||
session.getContext().setClient(client);
|
||||
|
||||
return logoutAuthSession;
|
||||
}
|
||||
|
||||
@ -83,6 +83,7 @@ import org.keycloak.services.resource.RealmResourceProvider;
|
||||
import org.keycloak.services.util.AuthenticationFlowURLHelper;
|
||||
import org.keycloak.services.util.BrowserHistoryHelper;
|
||||
import org.keycloak.services.util.CacheControlUtil;
|
||||
import org.keycloak.services.util.LocaleUtil;
|
||||
import org.keycloak.sessions.AuthenticationSessionCompoundId;
|
||||
import org.keycloak.sessions.AuthenticationSessionModel;
|
||||
import org.keycloak.sessions.RootAuthenticationSessionModel;
|
||||
@ -277,15 +278,7 @@ public class LoginActionsService {
|
||||
}
|
||||
|
||||
protected void processLocaleParam(AuthenticationSessionModel authSession) {
|
||||
if (authSession != null && realm.isInternationalizationEnabled()) {
|
||||
String locale = session.getContext().getUri().getQueryParameters().getFirst(LocaleSelectorProvider.KC_LOCALE_PARAM);
|
||||
if (locale != null) {
|
||||
authSession.setAuthNote(LocaleSelectorProvider.USER_REQUEST_LOCALE, locale);
|
||||
|
||||
LocaleUpdaterProvider localeUpdater = session.getProvider(LocaleUpdaterProvider.class);
|
||||
localeUpdater.updateLocaleCookie(locale);
|
||||
}
|
||||
}
|
||||
LocaleUtil.processLocaleParam(session, realm, authSession);
|
||||
}
|
||||
|
||||
protected Response processAuthentication(boolean action, String execution, AuthenticationSessionModel authSession, String errorMessage) {
|
||||
|
||||
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2022 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.keycloak.services.util;
|
||||
|
||||
import org.keycloak.locale.LocaleSelectorProvider;
|
||||
import org.keycloak.locale.LocaleUpdaterProvider;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.sessions.AuthenticationSessionModel;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class LocaleUtil {
|
||||
|
||||
public static void processLocaleParam(KeycloakSession session, RealmModel realm, AuthenticationSessionModel authSession) {
|
||||
if (authSession != null && realm.isInternationalizationEnabled()) {
|
||||
String locale = session.getContext().getUri().getQueryParameters().getFirst(LocaleSelectorProvider.KC_LOCALE_PARAM);
|
||||
if (locale != null) {
|
||||
authSession.setAuthNote(LocaleSelectorProvider.USER_REQUEST_LOCALE, locale);
|
||||
|
||||
LocaleUpdaterProvider localeUpdater = session.getProvider(LocaleUpdaterProvider.class);
|
||||
localeUpdater.updateLocaleCookie(locale);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -21,6 +21,7 @@ import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.hamcrest.MatcherAssert;
|
||||
import org.jboss.arquillian.graphene.page.Page;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
@ -35,6 +36,7 @@ import org.keycloak.events.Details;
|
||||
import org.keycloak.events.Errors;
|
||||
import org.keycloak.jose.jws.JWSInput;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.protocol.oidc.OIDCConfigAttributes;
|
||||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||
import org.keycloak.representations.IDToken;
|
||||
@ -59,13 +61,14 @@ import java.util.Map;
|
||||
import javax.ws.rs.NotFoundException;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
|
||||
import static org.hamcrest.Matchers.endsWith;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlEquals;
|
||||
@ -76,6 +79,7 @@ import org.keycloak.testsuite.pages.OAuthGrantPage;
|
||||
import org.keycloak.testsuite.pages.PageUtils;
|
||||
import org.keycloak.testsuite.updaters.ClientAttributeUpdater;
|
||||
import org.keycloak.testsuite.updaters.RealmAttributeUpdater;
|
||||
import org.keycloak.testsuite.updaters.UserAttributeUpdater;
|
||||
import org.keycloak.testsuite.util.InfinispanTestTimeServiceRule;
|
||||
import org.keycloak.testsuite.util.Matchers;
|
||||
import org.keycloak.testsuite.util.OAuthClient;
|
||||
@ -144,7 +148,7 @@ public class RPInitiatedLogoutTest extends AbstractTestRealmKeycloakTest {
|
||||
driver.navigate().to(logoutUrl);
|
||||
|
||||
events.expectLogout(sessionId).detail(Details.REDIRECT_URI, redirectUri).assertEvent();
|
||||
Assert.assertThat(false, is(isSessionActive(sessionId)));
|
||||
MatcherAssert.assertThat(false, is(isSessionActive(sessionId)));
|
||||
|
||||
assertCurrentUrlEquals(redirectUri);
|
||||
|
||||
@ -157,7 +161,7 @@ public class RPInitiatedLogoutTest extends AbstractTestRealmKeycloakTest {
|
||||
logoutUrl = oauth.getLogoutUrl().postLogoutRedirectUri(redirectUri).idTokenHint(idTokenString).state("something").build();
|
||||
driver.navigate().to(logoutUrl);
|
||||
events.expectLogout(sessionId2).detail(Details.REDIRECT_URI, redirectUri).assertEvent();
|
||||
Assert.assertThat(false, is(isSessionActive(sessionId2)));
|
||||
MatcherAssert.assertThat(false, is(isSessionActive(sessionId2)));
|
||||
assertCurrentUrlEquals(redirectUri + "&state=something");
|
||||
}
|
||||
|
||||
@ -175,7 +179,7 @@ public class RPInitiatedLogoutTest extends AbstractTestRealmKeycloakTest {
|
||||
driver.navigate().to(logoutUrl);
|
||||
|
||||
events.expectLogout(sessionId).detail(Details.REDIRECT_URI, redirectUri).assertEvent();
|
||||
Assert.assertThat(false, is(isSessionActive(sessionId)));
|
||||
MatcherAssert.assertThat(false, is(isSessionActive(sessionId)));
|
||||
|
||||
assertCurrentUrlEquals(redirectUri);
|
||||
|
||||
@ -192,7 +196,7 @@ public class RPInitiatedLogoutTest extends AbstractTestRealmKeycloakTest {
|
||||
logoutConfirmPage.assertCurrent();
|
||||
logoutConfirmPage.confirmLogout();
|
||||
events.expectLogout(sessionId2).detail(Details.REDIRECT_URI, redirectUri).assertEvent();
|
||||
Assert.assertThat(false, is(isSessionActive(sessionId2)));
|
||||
MatcherAssert.assertThat(false, is(isSessionActive(sessionId2)));
|
||||
assertCurrentUrlEquals(redirectUri + "&state=something");
|
||||
}
|
||||
|
||||
@ -215,7 +219,7 @@ public class RPInitiatedLogoutTest extends AbstractTestRealmKeycloakTest {
|
||||
// should not throw an internal server error. But no logout event is sent as nothing was logged-out
|
||||
appPage.assertCurrent();
|
||||
events.assertEmpty();
|
||||
Assert.assertThat(false, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
MatcherAssert.assertThat(false, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
|
||||
// check if the back channel logout succeeded
|
||||
driver.navigate().to(oauth.getLoginFormUrl());
|
||||
@ -266,7 +270,7 @@ public class RPInitiatedLogoutTest extends AbstractTestRealmKeycloakTest {
|
||||
String idTokenString = tokenResponse.getIdToken();
|
||||
|
||||
adminClient.realm("test").logoutAll();
|
||||
Assert.assertThat(false, is(isSessionActive(sessionId)));
|
||||
MatcherAssert.assertThat(false, is(isSessionActive(sessionId)));
|
||||
|
||||
// Try logout even if user already logged-out by admin. Should redirect back to the application, but no logout-event should be triggered
|
||||
String logoutUrl = oauth.getLogoutUrl().postLogoutRedirectUri(APP_REDIRECT_URI).idTokenHint(idTokenString).build();
|
||||
@ -283,7 +287,7 @@ public class RPInitiatedLogoutTest extends AbstractTestRealmKeycloakTest {
|
||||
|
||||
driver.navigate().to(logoutUrl);
|
||||
events.expectLogout(sessionId2).detail(Details.REDIRECT_URI, APP_REDIRECT_URI).assertEvent();
|
||||
Assert.assertThat(false, is(isSessionActive(sessionId2)));
|
||||
MatcherAssert.assertThat(false, is(isSessionActive(sessionId2)));
|
||||
}
|
||||
|
||||
|
||||
@ -310,7 +314,7 @@ public class RPInitiatedLogoutTest extends AbstractTestRealmKeycloakTest {
|
||||
events.expectLogoutError(OAuthErrorException.INVALID_TOKEN).assertEvent();
|
||||
|
||||
// Session still authenticated
|
||||
Assert.assertThat(true, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
MatcherAssert.assertThat(true, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -333,7 +337,7 @@ public class RPInitiatedLogoutTest extends AbstractTestRealmKeycloakTest {
|
||||
}
|
||||
events.assertEmpty();
|
||||
|
||||
Assert.assertThat(false, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
MatcherAssert.assertThat(false, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -356,7 +360,7 @@ public class RPInitiatedLogoutTest extends AbstractTestRealmKeycloakTest {
|
||||
}
|
||||
events.assertEmpty();
|
||||
|
||||
Assert.assertThat(false, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
MatcherAssert.assertThat(false, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
}
|
||||
|
||||
|
||||
@ -379,7 +383,7 @@ public class RPInitiatedLogoutTest extends AbstractTestRealmKeycloakTest {
|
||||
events.expectLogoutError(OAuthErrorException.INVALID_REQUEST).assertEvent();
|
||||
|
||||
// Assert user still authenticated
|
||||
Assert.assertThat(true, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
MatcherAssert.assertThat(true, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
}
|
||||
|
||||
|
||||
@ -395,7 +399,7 @@ public class RPInitiatedLogoutTest extends AbstractTestRealmKeycloakTest {
|
||||
events.expectLogoutError(OAuthErrorException.INVALID_REQUEST).assertEvent();
|
||||
|
||||
// Assert user still authenticated
|
||||
Assert.assertThat(true, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
MatcherAssert.assertThat(true, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
}
|
||||
|
||||
|
||||
@ -416,7 +420,7 @@ public class RPInitiatedLogoutTest extends AbstractTestRealmKeycloakTest {
|
||||
events.expectLogoutError(OAuthErrorException.INVALID_REDIRECT_URI).detail(Details.REDIRECT_URI, rootUrlClientRedirectUri).assertEvent();
|
||||
|
||||
// Session still authenticated
|
||||
Assert.assertThat(true, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
MatcherAssert.assertThat(true, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
}
|
||||
|
||||
|
||||
@ -438,7 +442,7 @@ public class RPInitiatedLogoutTest extends AbstractTestRealmKeycloakTest {
|
||||
events.expectLogoutError(OAuthErrorException.INVALID_TOKEN).removeDetail(Details.REDIRECT_URI).assertEvent();
|
||||
|
||||
// Session still authenticated
|
||||
Assert.assertThat(true, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
MatcherAssert.assertThat(true, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
}
|
||||
|
||||
|
||||
@ -451,7 +455,7 @@ public class RPInitiatedLogoutTest extends AbstractTestRealmKeycloakTest {
|
||||
|
||||
// Assert logout confirmation page. Session still exists
|
||||
logoutConfirmPage.assertCurrent();
|
||||
Assert.assertThat(true, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
MatcherAssert.assertThat(true, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
events.assertEmpty();
|
||||
logoutConfirmPage.confirmLogout();
|
||||
|
||||
@ -467,7 +471,7 @@ public class RPInitiatedLogoutTest extends AbstractTestRealmKeycloakTest {
|
||||
}
|
||||
|
||||
events.expectLogout(tokenResponse.getSessionState()).removeDetail(Details.REDIRECT_URI).assertEvent();
|
||||
Assert.assertThat(false, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
MatcherAssert.assertThat(false, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
}
|
||||
|
||||
|
||||
@ -483,11 +487,11 @@ public class RPInitiatedLogoutTest extends AbstractTestRealmKeycloakTest {
|
||||
Assert.assertEquals("You are logged out", infoPage.getInfo());
|
||||
|
||||
events.expectLogout(tokenResponse.getSessionState()).removeDetail(Details.REDIRECT_URI).assertEvent();
|
||||
Assert.assertThat(false, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
MatcherAssert.assertThat(false, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
|
||||
infoPage.clickBackToApplicationLink();
|
||||
WaitUtils.waitForPageToLoad();
|
||||
Assert.assertThat(driver.getCurrentUrl(), endsWith("/app/auth"));
|
||||
MatcherAssert.assertThat(driver.getCurrentUrl(), endsWith("/app/auth"));
|
||||
}
|
||||
|
||||
|
||||
@ -500,7 +504,7 @@ public class RPInitiatedLogoutTest extends AbstractTestRealmKeycloakTest {
|
||||
|
||||
// Assert logout confirmation page. Session still exists
|
||||
logoutConfirmPage.assertCurrent();
|
||||
Assert.assertThat(true, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
MatcherAssert.assertThat(true, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
events.assertEmpty();
|
||||
|
||||
// Set time offset to expire "action" inside logoutSession
|
||||
@ -511,7 +515,7 @@ public class RPInitiatedLogoutTest extends AbstractTestRealmKeycloakTest {
|
||||
Assert.assertEquals("Logout failed", errorPage.getError());
|
||||
|
||||
events.expectLogoutError(Errors.EXPIRED_CODE).assertEvent();
|
||||
Assert.assertThat(true, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
MatcherAssert.assertThat(true, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
|
||||
// Link not present
|
||||
try {
|
||||
@ -532,7 +536,7 @@ public class RPInitiatedLogoutTest extends AbstractTestRealmKeycloakTest {
|
||||
|
||||
// Assert logout confirmation page. Session still exists
|
||||
logoutConfirmPage.assertCurrent();
|
||||
Assert.assertThat(true, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
MatcherAssert.assertThat(true, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
events.assertEmpty();
|
||||
|
||||
// Set time offset to expire "action" inside logoutSession
|
||||
@ -558,7 +562,7 @@ public class RPInitiatedLogoutTest extends AbstractTestRealmKeycloakTest {
|
||||
// Logout confirmation page not shown as id_token_hint was included.
|
||||
// Redirected back to the application with expected "state"
|
||||
events.expectLogout(tokenResponse.getSessionState()).assertEvent();
|
||||
Assert.assertThat(false, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
MatcherAssert.assertThat(false, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
assertCurrentUrlEquals(APP_REDIRECT_URI + "?state=somethingg");
|
||||
|
||||
UserResource user = ApiUtil.findUserByUsernameId(testRealm(), "test-user@localhost");
|
||||
@ -578,19 +582,19 @@ public class RPInitiatedLogoutTest extends AbstractTestRealmKeycloakTest {
|
||||
// Assert logout confirmation page. Session still exists. Assert czech language on logout page
|
||||
Assert.assertEquals("Odhlašování", PageUtils.getPageTitle(driver)); // Logging out
|
||||
Assert.assertEquals("Čeština", logoutConfirmPage.getLanguageDropdownText());
|
||||
Assert.assertThat(true, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
MatcherAssert.assertThat(true, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
events.assertEmpty();
|
||||
logoutConfirmPage.confirmLogout();
|
||||
|
||||
// Info page present with the link "Back to application"
|
||||
events.expectLogout(tokenResponse.getSessionState()).removeDetail(Details.REDIRECT_URI).assertEvent();
|
||||
Assert.assertThat(false, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
MatcherAssert.assertThat(false, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
|
||||
infoPage.assertCurrent();
|
||||
Assert.assertEquals("Odhlášení bylo úspěšné", infoPage.getInfo()); // Logout success message
|
||||
infoPage.clickBackToApplicationLinkCs();
|
||||
WaitUtils.waitForPageToLoad();
|
||||
Assert.assertThat(driver.getCurrentUrl(), endsWith("/app/auth"));
|
||||
MatcherAssert.assertThat(driver.getCurrentUrl(), endsWith("/app/auth"));
|
||||
}
|
||||
}
|
||||
|
||||
@ -603,7 +607,7 @@ public class RPInitiatedLogoutTest extends AbstractTestRealmKeycloakTest {
|
||||
|
||||
// Assert logout confirmation page. Session still exists
|
||||
logoutConfirmPage.assertCurrent();
|
||||
Assert.assertThat(true, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
MatcherAssert.assertThat(true, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
events.assertEmpty();
|
||||
|
||||
// Set time offset to expire "action" inside logoutSession
|
||||
@ -614,11 +618,11 @@ public class RPInitiatedLogoutTest extends AbstractTestRealmKeycloakTest {
|
||||
Assert.assertEquals("Logout failed", errorPage.getError());
|
||||
|
||||
events.expectLogoutError(Errors.EXPIRED_CODE).assertEvent();
|
||||
Assert.assertThat(true, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
MatcherAssert.assertThat(true, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
|
||||
// Link "Back to application" present
|
||||
errorPage.clickBackToApplication();
|
||||
Assert.assertThat(driver.getCurrentUrl(), endsWith("/app/auth"));
|
||||
MatcherAssert.assertThat(driver.getCurrentUrl(), endsWith("/app/auth"));
|
||||
}
|
||||
|
||||
|
||||
@ -632,13 +636,13 @@ public class RPInitiatedLogoutTest extends AbstractTestRealmKeycloakTest {
|
||||
// Assert logout confirmation page as id_token_hint was not sent. Session still exists. Assert default language on logout page (English)
|
||||
logoutConfirmPage.assertCurrent();
|
||||
Assert.assertEquals("English", logoutConfirmPage.getLanguageDropdownText());
|
||||
Assert.assertThat(true, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
MatcherAssert.assertThat(true, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
events.assertEmpty();
|
||||
logoutConfirmPage.confirmLogout();
|
||||
|
||||
// Redirected back to the application with expected "state"
|
||||
events.expectLogout(tokenResponse.getSessionState()).assertEvent();
|
||||
Assert.assertThat(false, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
MatcherAssert.assertThat(false, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
assertCurrentUrlEquals(APP_REDIRECT_URI + "?state=somethingg");
|
||||
}
|
||||
|
||||
@ -657,7 +661,7 @@ public class RPInitiatedLogoutTest extends AbstractTestRealmKeycloakTest {
|
||||
|
||||
// Logout done and redirected back to the application with expected "state"
|
||||
events.expectLogout(tokenResponse.getSessionState()).assertEvent();
|
||||
Assert.assertThat(false, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
MatcherAssert.assertThat(false, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
assertCurrentUrlEquals(APP_REDIRECT_URI + "?state=somethingg");
|
||||
|
||||
// Test logout only with "client_id" and "post_logout_redirect_uri". Should automatically redirect as there is no logout (No active browser session)
|
||||
@ -687,7 +691,7 @@ public class RPInitiatedLogoutTest extends AbstractTestRealmKeycloakTest {
|
||||
Assert.assertEquals("Invalid parameter: id_token_hint", errorPage.getError());
|
||||
|
||||
events.expectLogoutError(Errors.INVALID_TOKEN).client("third-party").assertEvent();
|
||||
Assert.assertThat(true, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
MatcherAssert.assertThat(true, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
|
||||
// Case when client_id is non-existing client and redirect uri of different client is used
|
||||
logoutUrl = oauth.getLogoutUrl()
|
||||
@ -699,7 +703,7 @@ public class RPInitiatedLogoutTest extends AbstractTestRealmKeycloakTest {
|
||||
Assert.assertEquals("Invalid redirect uri", errorPage.getError());
|
||||
|
||||
events.expectLogoutError(Errors.INVALID_REDIRECT_URI).assertEvent();
|
||||
Assert.assertThat(true, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
MatcherAssert.assertThat(true, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
|
||||
// Case when client_id is non-existing client. Confirmation is needed.
|
||||
logoutUrl = oauth.getLogoutUrl()
|
||||
@ -721,7 +725,7 @@ public class RPInitiatedLogoutTest extends AbstractTestRealmKeycloakTest {
|
||||
}
|
||||
|
||||
events.expectLogout(tokenResponse.getSessionState()).removeDetail(Details.REDIRECT_URI).assertEvent();
|
||||
Assert.assertThat(false, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
MatcherAssert.assertThat(false, is(isSessionActive(tokenResponse.getSessionState())));
|
||||
}
|
||||
|
||||
|
||||
@ -744,7 +748,7 @@ public class RPInitiatedLogoutTest extends AbstractTestRealmKeycloakTest {
|
||||
URLUtils.sendPOSTRequestWithWebDriver(oauth.getLogoutUrl().build(), postParams);
|
||||
|
||||
events.expectLogout(tokenResponse.getSessionState()).detail(Details.REDIRECT_URI, redirectUri).assertEvent();
|
||||
Assert.assertThat(false, is(isSessionActive(sessionId)));
|
||||
MatcherAssert.assertThat(false, is(isSessionActive(sessionId)));
|
||||
assertCurrentUrlEquals(redirectUri + "&state=my-state");
|
||||
|
||||
// Logout with showing confirmation screen
|
||||
@ -764,12 +768,135 @@ public class RPInitiatedLogoutTest extends AbstractTestRealmKeycloakTest {
|
||||
|
||||
WaitUtils.waitForPageToLoad();
|
||||
events.expectLogout(tokenResponse.getSessionState()).detail(Details.REDIRECT_URI, redirectUri).assertEvent();
|
||||
Assert.assertThat(false, is(isSessionActive(sessionId)));
|
||||
MatcherAssert.assertThat(false, is(isSessionActive(sessionId)));
|
||||
assertCurrentUrlEquals(redirectUri + "&state=my-state-2");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testLocalizationPreferenceDuringLogout() throws IOException {
|
||||
try (RealmAttributeUpdater realmUpdater = new RealmAttributeUpdater(testRealm()).addSupportedLocale("cs").update()) {
|
||||
OAuthClient.AccessTokenResponse tokenResponse = loginUser();
|
||||
|
||||
// Set localization to the user account to "cs". Ensure that it is shown
|
||||
try (UserAttributeUpdater userUpdater = UserAttributeUpdater.forUserByUsername(testRealm(), "test-user@localhost").setAttribute(UserModel.LOCALE, "cs").update()) {
|
||||
driver.navigate().to(oauth.getLogoutUrl().build());
|
||||
Assert.assertEquals("Odhlašování", PageUtils.getPageTitle(driver)); // Logging out
|
||||
Assert.assertEquals("Čeština", logoutConfirmPage.getLanguageDropdownText());
|
||||
|
||||
// Set localization together with ui_locales param. User localization should have preference
|
||||
driver.navigate().to(oauth.getLogoutUrl().uiLocales("de").build());
|
||||
Assert.assertEquals("Odhlašování", PageUtils.getPageTitle(driver)); // Logging out
|
||||
Assert.assertEquals("Čeština", logoutConfirmPage.getLanguageDropdownText());
|
||||
}
|
||||
|
||||
UserAttributeUpdater.forUserByUsername(testRealm(), "test-user@localhost").removeAttribute(UserModel.LOCALE).update();
|
||||
|
||||
// Removed localization from user account. Now localization set by ui_locales parameter should be used
|
||||
driver.navigate().to(oauth.getLogoutUrl().uiLocales("de").build());
|
||||
Assert.assertEquals("Abmelden", PageUtils.getPageTitle(driver)); // Logging out
|
||||
Assert.assertEquals("Deutsch", logoutConfirmPage.getLanguageDropdownText());
|
||||
logoutConfirmPage.confirmLogout();
|
||||
WaitUtils.waitForPageToLoad();
|
||||
events.expectLogout(tokenResponse.getSessionState()).removeDetail(Details.REDIRECT_URI).assertEvent();
|
||||
|
||||
// Remove ui_locales from logout request. Default locale should be set
|
||||
tokenResponse = loginUser();
|
||||
driver.navigate().to(oauth.getLogoutUrl().build());
|
||||
Assert.assertEquals("Logging out", PageUtils.getPageTitle(driver));
|
||||
Assert.assertEquals("English", logoutConfirmPage.getLanguageDropdownText());
|
||||
logoutConfirmPage.confirmLogout();
|
||||
WaitUtils.waitForPageToLoad();
|
||||
events.expectLogout(tokenResponse.getSessionState()).removeDetail(Details.REDIRECT_URI).assertEvent();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testLocalizationDuringLogout() throws IOException {
|
||||
try (RealmAttributeUpdater realmUpdater = new RealmAttributeUpdater(testRealm()).addSupportedLocale("cs").update()) {
|
||||
OAuthClient.AccessTokenResponse tokenResponse = loginUser();
|
||||
|
||||
// Display the logout page. Then change the localization to Czech, then back to english and then and logout
|
||||
driver.navigate().to(oauth.getLogoutUrl().build());
|
||||
|
||||
logoutConfirmPage.assertCurrent();
|
||||
logoutConfirmPage.openLanguage("Čeština");
|
||||
|
||||
Assert.assertEquals("Odhlašování", PageUtils.getPageTitle(driver)); // Logging out
|
||||
Assert.assertEquals("Čeština", logoutConfirmPage.getLanguageDropdownText());
|
||||
|
||||
logoutConfirmPage.openLanguage("English");
|
||||
|
||||
Assert.assertEquals("Logging out", PageUtils.getPageTitle(driver));
|
||||
Assert.assertEquals("English", logoutConfirmPage.getLanguageDropdownText());
|
||||
|
||||
// Logout
|
||||
logoutConfirmPage.confirmLogout();
|
||||
infoPage.assertCurrent();
|
||||
Assert.assertEquals("You are logged out", infoPage.getInfo());
|
||||
try {
|
||||
logoutConfirmPage.clickBackToApplicationLink();
|
||||
fail();
|
||||
}
|
||||
catch (NoSuchElementException ex) {
|
||||
// expected
|
||||
}
|
||||
|
||||
// Display logout with ui_locales parameter set to "de"
|
||||
tokenResponse = loginUser();
|
||||
driver.navigate().to(oauth.getLogoutUrl()
|
||||
.clientId("test-app")
|
||||
.uiLocales("de")
|
||||
.build());
|
||||
|
||||
Assert.assertEquals("Abmelden", PageUtils.getPageTitle(driver)); // Logging out
|
||||
Assert.assertEquals("Deutsch", logoutConfirmPage.getLanguageDropdownText());
|
||||
|
||||
// Change locale. It should have preference over the "de" set by ui_locales
|
||||
logoutConfirmPage.openLanguage("Čeština");
|
||||
Assert.assertEquals("Odhlašování", PageUtils.getPageTitle(driver)); // Logging out
|
||||
Assert.assertEquals("Čeština", logoutConfirmPage.getLanguageDropdownText());
|
||||
|
||||
// Logout
|
||||
logoutConfirmPage.confirmLogout();
|
||||
|
||||
infoPage.assertCurrent();
|
||||
Assert.assertEquals("Odhlášení bylo úspěšné", infoPage.getInfo()); // Logout success message
|
||||
infoPage.clickBackToApplicationLinkCs();
|
||||
WaitUtils.waitForPageToLoad();
|
||||
MatcherAssert.assertThat(driver.getCurrentUrl(), endsWith("/app/auth"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testIncorrectChangingParameters() throws IOException {
|
||||
OAuthClient.AccessTokenResponse tokenResponse = loginUser();
|
||||
|
||||
// Display the logout page. Then change the localization to Czech and logout
|
||||
driver.navigate().to(oauth.getLogoutUrl().uiLocales("de").build());
|
||||
|
||||
Assert.assertEquals("Abmelden", PageUtils.getPageTitle(driver)); // Logging out
|
||||
logoutConfirmPage.openLanguage("English");
|
||||
|
||||
// Try to manually change value of parameter tab_id to some incorrect value. Error should be shown in this case
|
||||
String currentUrl = driver.getCurrentUrl();
|
||||
String changedUrl = UriBuilder.fromUri(currentUrl)
|
||||
.replaceQueryParam(Constants.TAB_ID, "invalid")
|
||||
.build().toString();
|
||||
|
||||
driver.navigate().to(changedUrl);
|
||||
WaitUtils.waitForPageToLoad();
|
||||
|
||||
errorPage.assertCurrent();
|
||||
Assert.assertEquals("Logout failed", errorPage.getError());
|
||||
|
||||
events.expectLogoutError(Errors.SESSION_EXPIRED).assertEvent();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testFrontChannelLogoutWithPostLogoutRedirectUri() throws Exception {
|
||||
ClientsResource clients = adminClient.realm(oauth.getRealm()).clients();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user