Skip to content

Commit

Permalink
feat(jans-auth-server): add client_id parameter support to /end_session
Browse files Browse the repository at this point in the history
#5942 (#6032)

Signed-off-by: YuriyZ <yzabrovarniy@gmail.com>
  • Loading branch information
yuriyz authored Sep 14, 2023
1 parent 7589bca commit 09ee345
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 7 deletions.
4 changes: 4 additions & 0 deletions docs/admin/auth-server/endpoints/end-session.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down
5 changes: 5 additions & 0 deletions jans-auth-server/docs/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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);
Expand Down Expand Up @@ -407,8 +407,7 @@ protected AuthorizationGrant getTokenHintGrant(String idTokenHint) {
return null;
}


private String validatePostLogoutRedirectUri(String postLogoutRedirectUri, Pair<SessionId, AuthorizationGrant> pair, String state) {
protected String validatePostLogoutRedirectUri(String postLogoutRedirectUri, Pair<SessionId, AuthorizationGrant> pair, String state, String clientId) {
try {
if (StringUtils.isBlank(postLogoutRedirectUri)) {
return "";
Expand All @@ -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)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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<SessionId, AuthorizationGrant> 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"));
Expand Down

0 comments on commit 09ee345

Please sign in to comment.