Remove root auth session after backchannel logout
Closes #32197 Signed-off-by: Giuseppe Graziano <g.graziano94@gmail.com>
This commit is contained in:
parent
cb765c8d73
commit
b46fab2308
8 changed files with 65 additions and 40 deletions
|
@ -308,8 +308,7 @@ public class AuthenticationManager {
|
|||
checkUserSessionOnlyHasLoggedOutClients(realm, userSession, logoutAuthSession);
|
||||
} finally {
|
||||
logger.tracef("Removing logout session '%s' after backchannel logout", logoutAuthSession.getParentSession().getId());
|
||||
RootAuthenticationSessionModel rootAuthSession = logoutAuthSession.getParentSession();
|
||||
rootAuthSession.removeAuthenticationSessionByTabId(logoutAuthSession.getTabId());
|
||||
session.authenticationSessions().removeRootAuthenticationSession(realm, logoutAuthSession.getParentSession());
|
||||
}
|
||||
|
||||
userSession.setState(UserSessionModel.State.LOGGED_OUT);
|
||||
|
|
|
@ -79,6 +79,10 @@ public class BrowserTabUtil implements AutoCloseable {
|
|||
return instance;
|
||||
}
|
||||
|
||||
public static void cleanup() {
|
||||
instances = new ArrayList<>();
|
||||
}
|
||||
|
||||
public WebDriver getDriver() {
|
||||
return driver;
|
||||
}
|
||||
|
@ -155,4 +159,4 @@ public class BrowserTabUtil implements AutoCloseable {
|
|||
public void close() {
|
||||
destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@ import org.keycloak.testsuite.auth.page.login.OIDCLogin;
|
|||
import org.keycloak.testsuite.auth.page.login.UpdatePassword;
|
||||
import org.keycloak.testsuite.client.KeycloakTestingClient;
|
||||
import org.keycloak.testsuite.pages.LoginPasswordUpdatePage;
|
||||
import org.keycloak.testsuite.util.BrowserTabUtil;
|
||||
import org.keycloak.testsuite.util.CryptoInitRule;
|
||||
import org.keycloak.testsuite.util.DroneUtils;
|
||||
import org.keycloak.testsuite.util.OAuthClient;
|
||||
|
@ -258,6 +259,7 @@ public abstract class AbstractKeycloakTest {
|
|||
|
||||
// Remove all browsers from queue
|
||||
DroneUtils.resetQueue();
|
||||
BrowserTabUtil.cleanup();
|
||||
}
|
||||
|
||||
protected TestCleanup getCleanup(String realmName) {
|
||||
|
|
|
@ -49,6 +49,7 @@ import org.keycloak.testsuite.pages.LoginPage;
|
|||
import org.keycloak.testsuite.pages.LoginTotpPage;
|
||||
import org.keycloak.testsuite.pages.LoginUsernameOnlyPage;
|
||||
import org.keycloak.testsuite.pages.PasswordPage;
|
||||
import org.keycloak.testsuite.util.BrowserTabUtil;
|
||||
import org.keycloak.testsuite.util.FederatedIdentityBuilder;
|
||||
import org.keycloak.testsuite.util.FlowUtil;
|
||||
import org.keycloak.testsuite.util.OAuthClient;
|
||||
|
@ -366,6 +367,42 @@ public class ReAuthenticationTest extends AbstractTestRealmKeycloakTest {
|
|||
realmsResouce().realm(rep.getRealm()).update(rep);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loginAfterLogoutWithDifferentSessionId() {
|
||||
BrowserTabUtil tabUtil = BrowserTabUtil.getInstanceAndSetEnv(driver);
|
||||
|
||||
assertThat(tabUtil.getCountOfTabs(), Matchers.is(1));
|
||||
oauth.openLoginForm();
|
||||
loginPage.assertCurrent();
|
||||
|
||||
tabUtil.newTab(oauth.getLoginFormUrl());
|
||||
assertThat(tabUtil.getCountOfTabs(), Matchers.equalTo(2));
|
||||
oauth.openLoginForm();
|
||||
|
||||
tabUtil.closeTab(tabUtil.getCountOfTabs() - 1);
|
||||
assertThat(tabUtil.getCountOfTabs(), Matchers.equalTo(1));
|
||||
|
||||
tabUtil.switchToTab(0);
|
||||
loginPage.assertCurrent();
|
||||
|
||||
loginPage.login("test-user@localhost", "password");
|
||||
String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
|
||||
OAuthClient.AccessTokenResponse response1 = oauth.doAccessTokenRequest(code, "password");
|
||||
AccessToken accessToken1 = oauth.verifyToken(response1.getAccessToken());
|
||||
|
||||
oauth.doLogout(response1.getRefreshToken(), "password");
|
||||
|
||||
oauth.openLoginForm();
|
||||
loginPage.assertCurrent();
|
||||
loginPage.login("test-user@localhost", "password");
|
||||
code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
|
||||
OAuthClient.AccessTokenResponse response2 = oauth.doAccessTokenRequest(code, "password");
|
||||
AccessToken accessToken2 = oauth.verifyToken(response2.getAccessToken());
|
||||
|
||||
Assert.assertNotEquals(accessToken1.getId(), accessToken2.getId());
|
||||
Assert.assertNotEquals(accessToken1.getSessionId(), accessToken2.getSessionId());
|
||||
}
|
||||
|
||||
private void setupIdentityFirstFlow() {
|
||||
String newFlowAlias = "browser - identity first";
|
||||
testingClient.server("test").run(session -> FlowUtil.inCurrentRealm(session).copyBrowserFlow(newFlowAlias));
|
||||
|
|
|
@ -146,30 +146,14 @@ public class LogoutTest extends AbstractKeycloakTest {
|
|||
|
||||
setTimeOffset(2);
|
||||
|
||||
WaitUtils.waitForPageToLoad();
|
||||
loginPage.login("password");
|
||||
driver.navigate().refresh();
|
||||
oauth.fillLoginForm("test-user@localhost", "password");
|
||||
|
||||
Assert.assertFalse(loginPage.isCurrent());
|
||||
|
||||
String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
|
||||
OAuthClient.AccessTokenResponse tokenResponse2 = oauth.doAccessTokenRequest(code, "password");
|
||||
|
||||
// POST logout with token should fail
|
||||
try (CloseableHttpResponse response = oauth.doLogout(refreshToken1, "password")) {
|
||||
assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatusLine().getStatusCode());
|
||||
}
|
||||
|
||||
String logoutUrl = oauth.getLogoutUrl()
|
||||
.idTokenHint(accessTokenResponse.getIdToken())
|
||||
.postLogoutRedirectUri(oauth.APP_AUTH_ROOT)
|
||||
.build();
|
||||
|
||||
// GET logout with ID token should fail as well
|
||||
try (CloseableHttpClient c = HttpClientBuilder.create().disableRedirectHandling().build();
|
||||
CloseableHttpResponse response = c.execute(new HttpGet(logoutUrl))) {
|
||||
assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatusLine().getStatusCode());
|
||||
}
|
||||
|
||||
// finally POST logout with VALID token should succeed
|
||||
try (CloseableHttpResponse response = oauth.doLogout(tokenResponse2.getRefreshToken(), "password")) {
|
||||
MatcherAssert.assertThat(response, Matchers.statusCodeIsHC(Status.NO_CONTENT));
|
||||
|
@ -178,7 +162,6 @@ public class LogoutTest extends AbstractKeycloakTest {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void postLogoutFailWithCredentialsOfDifferentClient() throws Exception {
|
||||
oauth.doLogin("test-user@localhost", "password");
|
||||
|
@ -247,7 +230,7 @@ public class LogoutTest extends AbstractKeycloakTest {
|
|||
.idTokenHint(idTokenString)
|
||||
.postLogoutRedirectUri(oauth.APP_AUTH_ROOT)
|
||||
.build();
|
||||
|
||||
|
||||
try (CloseableHttpClient c = HttpClientBuilder.create().disableRedirectHandling().build();
|
||||
CloseableHttpResponse response = c.execute(new HttpGet(logoutUrl))) {
|
||||
MatcherAssert.assertThat(response, Matchers.statusCodeIsHC(Status.FOUND));
|
||||
|
|
|
@ -1070,8 +1070,8 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
|
|||
try {
|
||||
// Continue with login
|
||||
setTimeOffset(2);
|
||||
WaitUtils.waitForPageToLoad();
|
||||
loginPage.login("password");
|
||||
driver.navigate().refresh();
|
||||
oauth.fillLoginForm("test-user@localhost", "password");
|
||||
|
||||
assertFalse(loginPage.isCurrent());
|
||||
|
||||
|
@ -1104,8 +1104,8 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
|
|||
try {
|
||||
// Continue with login
|
||||
setTimeOffset(2);
|
||||
WaitUtils.waitForPageToLoad();
|
||||
loginPage.login("password");
|
||||
driver.navigate().refresh();
|
||||
oauth.fillLoginForm("test-user@localhost", "password");
|
||||
|
||||
assertFalse(loginPage.isCurrent());
|
||||
|
||||
|
@ -1137,8 +1137,8 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
|
|||
|
||||
// Continue with login
|
||||
setTimeOffset(2);
|
||||
WaitUtils.waitForPageToLoad();
|
||||
loginPage.login("password");
|
||||
driver.navigate().refresh();
|
||||
oauth.fillLoginForm("test-user@localhost", "password");
|
||||
|
||||
assertFalse(loginPage.isCurrent());
|
||||
|
||||
|
|
|
@ -250,8 +250,8 @@ public class TokenIntrospectionTest extends AbstractTestRealmKeycloakTest {
|
|||
|
||||
setTimeOffset(2);
|
||||
|
||||
WaitUtils.waitForPageToLoad();
|
||||
loginPage.login("password");
|
||||
driver.navigate().refresh();
|
||||
oauth.fillLoginForm("test-user@localhost", "password");
|
||||
events.expectLogin().assertEvent();
|
||||
|
||||
Assert.assertFalse(loginPage.isCurrent());
|
||||
|
|
|
@ -207,7 +207,7 @@ public class UserInfoTest extends AbstractKeycloakTest {
|
|||
client.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSuccess_postMethod_charset_body() throws Exception {
|
||||
Client client = AdminClientUtil.createResteasyClient();
|
||||
|
@ -531,7 +531,7 @@ public class UserInfoTest extends AbstractKeycloakTest {
|
|||
public void testSuccessSignedResponseRS256AcceptJWT() throws Exception {
|
||||
testSuccessSignedResponse(Algorithm.RS256, MediaType.APPLICATION_JWT);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSessionExpired() {
|
||||
Client client = AdminClientUtil.createResteasyClient();
|
||||
|
@ -607,8 +607,8 @@ public class UserInfoTest extends AbstractKeycloakTest {
|
|||
|
||||
setTimeOffset(2);
|
||||
|
||||
WaitUtils.waitForPageToLoad();
|
||||
loginPage.login("password");
|
||||
driver.navigate().refresh();
|
||||
oauth.fillLoginForm("test-user@localhost", "password");
|
||||
events.expectLogin().assertEvent();
|
||||
|
||||
Assert.assertFalse(loginPage.isCurrent());
|
||||
|
@ -630,7 +630,7 @@ public class UserInfoTest extends AbstractKeycloakTest {
|
|||
response.close();
|
||||
|
||||
events.expect(EventType.USER_INFO_REQUEST_ERROR)
|
||||
.error(Errors.INVALID_TOKEN)
|
||||
.error(Errors.USER_SESSION_NOT_FOUND)
|
||||
.user(Matchers.nullValue(String.class))
|
||||
.session(Matchers.nullValue(String.class))
|
||||
.detail(Details.AUTH_METHOD, Details.VALIDATE_ACCESS_TOKEN)
|
||||
|
@ -1088,23 +1088,23 @@ public class UserInfoTest extends AbstractKeycloakTest {
|
|||
assertNull(userInfo.getOtherClaims().get("realm_access"));
|
||||
assertNull(userInfo.getOtherClaims().get("resource_access"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void test_noContentType() throws Exception {
|
||||
Client client = AdminClientUtil.createResteasyClient();
|
||||
|
||||
try {
|
||||
AccessTokenResponse accessTokenResponse = executeGrantAccessTokenRequest(client);
|
||||
|
||||
|
||||
WebTarget userInfoTarget = UserInfoClientUtil.getUserInfoWebTarget(client);
|
||||
Response response = userInfoTarget.request()
|
||||
.header(HttpHeaders.AUTHORIZATION, "bearer " + accessTokenResponse.getToken())
|
||||
.build("POST")
|
||||
.invoke();
|
||||
|
||||
|
||||
Assert.assertEquals(200, response.getStatus());
|
||||
Assert.assertEquals("OK", response.getStatusInfo().toString());
|
||||
|
||||
|
||||
} finally {
|
||||
client.close();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue