Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Honor OIDC logout requests when ID token has expired #35919

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
*
*/
public class SecurityEvent {
public static final String SESSION_TOKENS_PROPERTY = "session-tokens";

public enum Type {
/**
* OIDC Login event which is reported after the first user authentication but also when the user's session
Expand All @@ -30,6 +32,12 @@ public enum Type {
*/
OIDC_LOGOUT_RP_INITIATED,

/**
* OIDC Logout event is reported when the current user has started an RP-initiated OIDC logout flow but the session has
* already expired.
*/
OIDC_LOGOUT_RP_INITIATED_SESSION_EXPIRED,

/**
* OIDC BackChannel Logout initiated event is reported when the BackChannel logout request to logout the current user
* has been received.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,14 @@ public Uni<? extends SecurityIdentity> apply(Throwable t) {
t.getCause())));
}
// Token has expired, try to refresh
if (isRpInitiatedLogout(context, configContext)) {
LOG.debug("Session has expired, performing an RP initiated logout");
fireEvent(SecurityEvent.Type.OIDC_LOGOUT_RP_INITIATED_SESSION_EXPIRED,
Map.of(SecurityEvent.SESSION_TOKENS_PROPERTY, session));
return Uni.createFrom().item((SecurityIdentity) null)
.call(() -> buildLogoutRedirectUriUni(context, configContext,
currentIdToken));
}
if (session.getRefreshToken() == null) {
LOG.debug(
"Token has expired, token refresh is not possible because the refresh token is null");
Expand Down Expand Up @@ -983,6 +991,12 @@ private void fireEvent(SecurityEvent.Type eventType, SecurityIdentity securityId
}
}

private void fireEvent(SecurityEvent.Type eventType, Map<String, Object> properties) {
if (resolver.isSecurityEventObserved()) {
resolver.getSecurityEvent().fire(new SecurityEvent(eventType, properties));
}
}

private String getRedirectPath(OidcTenantConfig oidcConfig, RoutingContext context) {
Authentication auth = oidcConfig.getAuthentication();
return auth.getRedirectPath().isPresent() ? auth.getRedirectPath().get() : context.request().path();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ quarkus.oidc.tenant-logout.application-type=web-app
quarkus.oidc.tenant-logout.authentication.cookie-path=/tenant-logout
quarkus.oidc.tenant-logout.logout.path=/tenant-logout/logout
quarkus.oidc.tenant-logout.logout.post-logout-path=/tenant-logout/post-logout
quarkus.oidc.tenant-logout.authentication.session-age-extension=2M
quarkus.oidc.tenant-logout.token.refresh-expired=true

quarkus.oidc.tenant-refresh.auth-server-url=${keycloak.url}/realms/logout-realm
quarkus.oidc.tenant-refresh.client-id=quarkus-app
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,22 @@ public void testRPInitiatedLogout() throws IOException {

page = webClient.getPage("http://localhost:8081/tenant-logout");
assertEquals("Sign in to logout-realm", page.getTitleText());

// login again
loginForm = page.getForms().get(0);
loginForm.getInputByName("username").setValueAttribute("alice");
loginForm.getInputByName("password").setValueAttribute("alice");
page = loginForm.getInputByName("login").click();
assertEquals("Tenant Logout, refreshed: false", page.asNormalizedText());

assertNotNull(getSessionCookie(webClient, "tenant-logout"));

await().atLeast(Duration.ofSeconds(11));

page = webClient.getPage("http://localhost:8081/tenant-logout/logout");
assertTrue(page.asNormalizedText().contains("You were logged out, please login again"));
assertNull(getSessionCookie(webClient, "tenant-logout"));

webClient.getCookieManager().clearCookies();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public Map<String, String> start() {
// revoke refresh tokens so that they can only be used once
logoutRealm.setRevokeRefreshToken(true);
logoutRealm.setRefreshTokenMaxReuse(0);
logoutRealm.setSsoSessionMaxLifespan(15);
logoutRealm.setSsoSessionMaxLifespan(10);
logoutRealm.setAccessTokenLifespan(5);
client.createRealm(logoutRealm);
realms.add(logoutRealm);
Expand Down
Loading