diff --git a/docs/admin/auth-server/endpoints/end-session.md b/docs/admin/auth-server/endpoints/end-session.md index e1982844718..cec21a2a334 100644 --- a/docs/admin/auth-server/endpoints/end-session.md +++ b/docs/admin/auth-server/endpoints/end-session.md @@ -31,6 +31,10 @@ https://janssen.server.host/jans-auth/restv1/end_session Refer to [this](https://gluu.org/docs/gluu-server/4.4/operation/logout/#openid-connect-single-log-out-slo) article from Gluu Server documentation to understand how end session endpoint works in Janssen Server. +More information about request and response of the end session endpoint can be found in the OpenAPI specification +of [jans-auth-server module](https://gluu.org/swagger-ui/?url=https://raw.githubusercontent.com/JanssenProject/jans/vreplace-janssen-version/jans-auth-server/docs/swagger.yaml). + + ## Disabling The Endpoint Using Feature Flag `/end_session` endpoint can be enabled or disable using [END_SESSION feature flag](../../reference/json/feature-flags/janssenauthserver-feature-flags.md#endsession). diff --git a/jans-auth-server/docs/swagger.yaml b/jans-auth-server/docs/swagger.yaml index 1b3b23b7f84..aa1cd41a2f0 100644 --- a/jans-auth-server/docs/swagger.yaml +++ b/jans-auth-server/docs/swagger.yaml @@ -2523,6 +2523,11 @@ paths: description: Session Id schema: type: string + - name: client_id + in: query + description: Client Id. It can be useful to specify client id explicitly in case id_token and session are expired so AS can still validate "post_logout_redirect_uri" + schema: + type: string responses: 200: description: OK - User redirected to logout page diff --git a/jans-auth-server/server/src/main/java/io/jans/as/server/session/ws/rs/EndSessionRestWebService.java b/jans-auth-server/server/src/main/java/io/jans/as/server/session/ws/rs/EndSessionRestWebService.java index f13a62b3103..bf1f6bf1591 100644 --- a/jans-auth-server/server/src/main/java/io/jans/as/server/session/ws/rs/EndSessionRestWebService.java +++ b/jans-auth-server/server/src/main/java/io/jans/as/server/session/ws/rs/EndSessionRestWebService.java @@ -32,6 +32,7 @@ Response requestEndSession(@QueryParam(EndSessionRequestParam.ID_TOKEN_HINT) Str @QueryParam(EndSessionRequestParam.POST_LOGOUT_REDIRECT_URI) String postLogoutRedirectUri, @QueryParam(EndSessionRequestParam.STATE) String state, @QueryParam("sid") String sid, + @QueryParam("client_id") String clientId, @Context HttpServletRequest httpRequest, @Context HttpServletResponse httpResponse, @Context SecurityContext securityContext); diff --git a/jans-auth-server/server/src/main/java/io/jans/as/server/session/ws/rs/EndSessionRestWebServiceImpl.java b/jans-auth-server/server/src/main/java/io/jans/as/server/session/ws/rs/EndSessionRestWebServiceImpl.java index fbc9385c760..46a348c3cb9 100644 --- a/jans-auth-server/server/src/main/java/io/jans/as/server/session/ws/rs/EndSessionRestWebServiceImpl.java +++ b/jans-auth-server/server/src/main/java/io/jans/as/server/session/ws/rs/EndSessionRestWebServiceImpl.java @@ -119,11 +119,11 @@ public class EndSessionRestWebServiceImpl implements EndSessionRestWebService { private EndSessionService endSessionService; @Override - public Response requestEndSession(String idTokenHint, String postLogoutRedirectUri, String state, String sid, + public Response requestEndSession(String idTokenHint, String postLogoutRedirectUri, String state, String sid, String clientId, HttpServletRequest httpRequest, HttpServletResponse httpResponse, SecurityContext sec) { try { - log.debug("Attempting to end session, idTokenHint: {}, postLogoutRedirectUri: {}, sid: {}, Is Secure = {}", - idTokenHint, postLogoutRedirectUri, sid, sec.isSecure()); + log.debug("Attempting to end session, idTokenHint: {}, postLogoutRedirectUri: {}, sid: {}, Is Secure = {}, clientId = {}", + idTokenHint, postLogoutRedirectUri, sid, sec.isSecure(), clientId); errorResponseFactory.validateFeatureEnabled(FeatureFlagType.END_SESSION); @@ -136,7 +136,7 @@ public Response requestEndSession(String idTokenHint, String postLogoutRedirectU throw new WebApplicationException(createErrorResponse(postLogoutRedirectUri, EndSessionErrorResponseType.INVALID_GRANT_AND_SESSION, reason, state)); } - postLogoutRedirectUri = validatePostLogoutRedirectUri(postLogoutRedirectUri, pair, state); + postLogoutRedirectUri = validatePostLogoutRedirectUri(postLogoutRedirectUri, pair, state, clientId); validateSid(postLogoutRedirectUri, validatedIdToken, pair.getFirst(), state); endSession(pair, httpRequest, httpResponse); @@ -407,8 +407,7 @@ protected AuthorizationGrant getTokenHintGrant(String idTokenHint) { return null; } - - private String validatePostLogoutRedirectUri(String postLogoutRedirectUri, Pair pair, String state) { + protected String validatePostLogoutRedirectUri(String postLogoutRedirectUri, Pair pair, String state, String clientId) { try { if (StringUtils.isBlank(postLogoutRedirectUri)) { return ""; @@ -418,11 +417,18 @@ private String validatePostLogoutRedirectUri(String postLogoutRedirectUri, Pair< return postLogoutRedirectUri; } - final String result; + String result; if (pair.getSecond() == null) { result = redirectionUriService.validatePostLogoutRedirectUri(pair.getFirst(), postLogoutRedirectUri); + log.trace("Validated post_logout_redirect_uri: {} against session: {}, result: {}" , postLogoutRedirectUri, pair.getFirst(), result); } else { result = redirectionUriService.validatePostLogoutRedirectUri(pair.getSecond().getClient().getClientId(), postLogoutRedirectUri); + log.trace("Validated post_logout_redirect_uri: {} against (pair) client: {}, result: {}" , postLogoutRedirectUri, pair.getSecond().getClient().getClientId(), result); + } + + if (StringUtils.isBlank(result) && StringUtils.isNotBlank(clientId)) { + result = redirectionUriService.validatePostLogoutRedirectUri(clientId, postLogoutRedirectUri); + log.trace("Validated post_logout_redirect_uri: {} against client_id: {}, result: {}" , postLogoutRedirectUri, clientId, result); } if (StringUtils.isBlank(result)) { diff --git a/jans-auth-server/server/src/test/java/io/jans/as/server/session/ws/rs/EndSessionRestWebServiceImplTest.java b/jans-auth-server/server/src/test/java/io/jans/as/server/session/ws/rs/EndSessionRestWebServiceImplTest.java index db7eb2d062c..d0fa54fbc23 100644 --- a/jans-auth-server/server/src/test/java/io/jans/as/server/session/ws/rs/EndSessionRestWebServiceImplTest.java +++ b/jans-auth-server/server/src/test/java/io/jans/as/server/session/ws/rs/EndSessionRestWebServiceImplTest.java @@ -1,5 +1,6 @@ package io.jans.as.server.session.ws.rs; +import io.jans.as.common.model.registration.Client; import io.jans.as.common.model.session.SessionId; import io.jans.as.model.common.GrantType; import io.jans.as.model.configuration.AppConfiguration; @@ -9,10 +10,12 @@ import io.jans.as.server.audit.ApplicationAuditLogger; import io.jans.as.server.model.common.AuthorizationGrant; import io.jans.as.server.model.common.AuthorizationGrantList; +import io.jans.as.server.model.common.SimpleAuthorizationGrant; import io.jans.as.server.service.*; import io.jans.as.server.service.external.ExternalApplicationSessionService; import io.jans.as.server.service.external.ExternalEndSessionService; import io.jans.model.security.Identity; +import io.jans.util.Pair; import jakarta.ws.rs.WebApplicationException; import org.mockito.InjectMocks; import org.mockito.Mock; @@ -22,6 +25,7 @@ import org.testng.annotations.Test; import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.testng.Assert.assertNull; import static org.testng.AssertJUnit.assertNotNull; @@ -88,6 +92,23 @@ public GrantType getGrantType() { @Mock private AbstractCryptoProvider cryptoProvider; + @Test + public void validatePostLogoutRedirectUri_whenValidClientIdIsPassed_shouldValidateSuccessfully() { + Client client = new Client(); + client.setClientId("my_client"); + client.setPostLogoutRedirectUris(new String[] {"http://postlogout.com"}); + + final SimpleAuthorizationGrant grant = mock(SimpleAuthorizationGrant.class); + when(grant.getClient()).thenReturn(client); + + Pair pair = new Pair<>(null, grant); + when(appConfiguration.getAllowPostLogoutRedirectWithoutValidation()).thenReturn(false); + + when(redirectionUriService.validatePostLogoutRedirectUri(anyString(), anyString())).thenReturn("http://postlogout.com"); + + assertNotNull(endSessionRestWebService.validatePostLogoutRedirectUri("http://postlogout.com", pair, "state", "my_client")); + } + @Test public void validateIdTokenHint_whenIdTokenHintIsBlank_shouldGetNoError() { assertNull(endSessionRestWebService.validateIdTokenHint("", null, "", "http://postlogout.com"));