Skip to content

Commit

Permalink
Adding a test case to check that the expiration time is set on logout…
Browse files Browse the repository at this point in the history
… tokens

Closes #25753

Signed-off-by: Alexander Schwartz <aschwart@redhat.com>
(cherry picked from commit 9e89026)
  • Loading branch information
ahus1 committed Dec 27, 2023
1 parent 9659182 commit de3634a
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,8 @@ public LogoutToken initLogoutToken(ClientModel client, UserModel user,
LogoutToken token = new LogoutToken();
token.id(KeycloakModelUtils.generateId());
token.issuedNow();
// From the spec "OpenID Connect Back-Channel Logout 1.0 incorporating errata set 1" at https://openid.net/specs/openid-connect-backchannel-1_0.html
// "OPs are encouraged to use short expiration times in Logout Tokens, preferably at most two minutes in the future [...]"
token.exp(Time.currentTime() + Duration.ofMinutes(2).getSeconds());
token.issuer(clientSession.getNote(OIDCLoginProtocol.ISSUER));
token.putEvents(TokenUtil.TOKEN_BACKCHANNEL_LOGOUT_EVENT, JsonSerialization.createObjectNode());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package org.keycloak.testsuite.oauth;

import org.hamcrest.MatcherAssert;
import org.jboss.arquillian.graphene.page.Page;
import org.junit.Before;
import org.junit.Rule;
Expand All @@ -32,6 +33,7 @@
import org.keycloak.jose.jws.JWSInput;
import org.keycloak.protocol.oidc.OIDCConfigAttributes;
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
import org.keycloak.representations.LogoutToken;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
Expand All @@ -42,6 +44,8 @@
import org.keycloak.testsuite.pages.LoginPage;

import java.util.List;
import java.util.Map;

import jakarta.ws.rs.core.HttpHeaders;
import jakarta.ws.rs.core.Response.Status;
import jakarta.ws.rs.core.UriBuilder;
Expand Down Expand Up @@ -331,13 +335,31 @@ public void backChannelPreferenceOverKLogout() throws Exception {
assertThat(response.getFirstHeader(HttpHeaders.LOCATION).getValue(), is(oauth.APP_AUTH_ROOT));
}

assertNotNull(testingClient.testApp().getBackChannelLogoutToken());
validateLogoutToken(testingClient.testApp().getBackChannelLogoutToken());
} finally {
rep.getAttributes().put(OIDCConfigAttributes.BACKCHANNEL_LOGOUT_URL, "");
clientResource.update(rep);
}
}

/**
* Validate the token matches the spec at <a href="https://openid.net/specs/openid-connect-backchannel-1_0.html#LogoutToken">OpenID Connect Back-Channel Logout 1.0 incorporating errata set 1</a>
*/
private void validateLogoutToken(LogoutToken backChannelLogoutToken) {
assertNotNull("token must be present", backChannelLogoutToken);
assertNotNull("iss must be present", backChannelLogoutToken.getIssuer());
assertNotNull("aud must be present", backChannelLogoutToken.getAudience());
assertNotNull("iat must be present", backChannelLogoutToken.getIat());
assertNotNull("exp must be present", backChannelLogoutToken.getExp());
assertNotNull("jti must be present", backChannelLogoutToken.getId());
Map<String, Object> events = backChannelLogoutToken.getEvents();
assertNotNull("events must be present", events);
Object backchannelLogoutEvent = events.get("http://schemas.openid.net/event/backchannel-logout");
assertNotNull("back-channel logout event must be present", backchannelLogoutEvent);
assertTrue("back-channel logout event must have a member object", backchannelLogoutEvent instanceof Map);
MatcherAssert.assertThat("map of back-channel logout event member object should be an empty object", (Map<?, ?>) backchannelLogoutEvent, org.hamcrest.Matchers.anEmptyMap());
}

private OAuthClient.AccessTokenResponse loginAndForceNewLoginPage() {
oauth.doLogin("test-user@localhost", "password");

Expand Down

0 comments on commit de3634a

Please sign in to comment.