Skip to content

Commit

Permalink
feat(oxauth): added client_id parameter support to /end_session (4.6.…
Browse files Browse the repository at this point in the history
…0) (#1864)

#1853
  • Loading branch information
yuriyz authored Sep 7, 2023
1 parent 0933f5e commit 4e21972
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ Response requestEndSession(@QueryParam(EndSessionRequestParam.ID_TOKEN_HINT) Str
@QueryParam(EndSessionRequestParam.STATE) String state,
@QueryParam("session_id") String sessionId,
@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 @@ -113,11 +113,11 @@ public class EndSessionRestWebServiceImpl implements EndSessionRestWebService {
private AbstractCryptoProvider cryptoProvider;

@Override
public Response requestEndSession(String idTokenHint, String postLogoutRedirectUri, String state, String sessionId, String sid,
public Response requestEndSession(String idTokenHint, String postLogoutRedirectUri, String state, String sessionId, String sid, String clientId,
HttpServletRequest httpRequest, HttpServletResponse httpResponse, SecurityContext sec) {
try {
log.debug("Attempting to end session, idTokenHint: {}, postLogoutRedirectUri: {}, sessionId: {}, sid: {}, Is Secure = {}, state = {}",
idTokenHint, postLogoutRedirectUri, sessionId, sid, sec.isSecure(), state);
log.debug("Attempting to end session, idTokenHint: {}, postLogoutRedirectUri: {}, sessionId: {}, sid: {}, Is Secure = {}, state = {}, client_id = {}",
idTokenHint, postLogoutRedirectUri, sessionId, sid, sec.isSecure(), state, clientId);

if (StringUtils.isBlank(sid) && StringUtils.isNotBlank(sessionId))
sid = sessionId; // backward compatibility. WIll be removed in next major release.
Expand All @@ -131,7 +131,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 @@ -289,7 +289,7 @@ private SessionId validateSidRequestParameter(String sid, String postLogoutRedir
return null;
}

private Jwt validateIdTokenHint(String idTokenHint, SessionId sidSession, String postLogoutRedirectUri, String state) {
protected Jwt validateIdTokenHint(String idTokenHint, SessionId sidSession, String postLogoutRedirectUri, String state) {
final boolean isIdTokenHintRequired = isTrue(appConfiguration.getForceIdTokenHintPrecense());
if (isIdTokenHintRequired && StringUtils.isBlank(idTokenHint)) { // must be present for logout tests #1279
final String reason = "id_token_hint is not set";
Expand Down Expand Up @@ -385,7 +385,7 @@ protected AuthorizationGrant getTokenHintGrant(String idTokenHint) {
}


private String validatePostLogoutRedirectUri(String postLogoutRedirectUri, Pair<SessionId, AuthorizationGrant> pair, String state) {
public String validatePostLogoutRedirectUri(String postLogoutRedirectUri, Pair<SessionId, AuthorizationGrant> pair, String state, String clientId) {
try {
if (StringUtils.isBlank(postLogoutRedirectUri)) {
return "";
Expand All @@ -395,13 +395,18 @@ private String validatePostLogoutRedirectUri(String postLogoutRedirectUri, Pair<
return postLogoutRedirectUri;
}

final String result;
String result;
if (pair.getSecond() == null) {
result = redirectionUriService.validatePostLogoutRedirectUri(pair.getFirst(), postLogoutRedirectUri);
} else {
result = redirectionUriService.validatePostLogoutRedirectUri(pair.getSecond().getClient().getClientId(), postLogoutRedirectUri);
}

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)) {
log.trace("Failed to validate post_logout_redirect_uri.");
throw new WebApplicationException(createErrorResponse(postLogoutRedirectUri, EndSessionErrorResponseType.POST_LOGOUT_URI_NOT_ASSOCIATED_WITH_CLIENT, "", state));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,16 @@

import org.gluu.model.security.Identity;
import org.gluu.oxauth.audit.ApplicationAuditLogger;
import org.gluu.oxauth.model.common.AuthorizationGrant;
import org.gluu.oxauth.model.common.AuthorizationGrantList;
import org.gluu.oxauth.model.common.GrantType;
import org.gluu.oxauth.model.common.SessionId;
import org.gluu.oxauth.model.common.*;
import org.gluu.oxauth.model.configuration.AppConfiguration;
import org.gluu.oxauth.model.crypto.AbstractCryptoProvider;
import org.gluu.oxauth.model.error.ErrorResponseFactory;
import org.gluu.oxauth.model.jwt.Jwt;
import org.gluu.oxauth.model.registration.Client;
import org.gluu.oxauth.service.*;
import org.gluu.oxauth.service.external.ExternalApplicationSessionService;
import org.gluu.oxauth.service.external.ExternalEndSessionService;
import org.gluu.util.Pair;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.testng.MockitoTestNGListener;
Expand All @@ -23,6 +22,7 @@
import javax.ws.rs.WebApplicationException;

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 @@ -90,40 +90,57 @@ 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"));
assertNull(endSessionRestWebService.validateIdTokenHint("", null, "http://postlogout.com", ""));
}

@Test(expectedExceptions = WebApplicationException.class)
public void validateIdTokenHint_whenIdTokenHintIsBlankButRequired_shouldGetError() {
when(appConfiguration.getForceIdTokenHintPrecense()).thenReturn(true);

endSessionRestWebService.validateIdTokenHint("", null, "http://postlogout.com");
endSessionRestWebService.validateIdTokenHint("", null, "http://postlogout.com", "");
}

@Test(expectedExceptions = WebApplicationException.class)
public void validateIdTokenHint_whenIdTokenIsNotInDbAndExpiredIsNotAllowed_shouldGetError() {
when(appConfiguration.getRejectEndSessionIfIdTokenExpired()).thenReturn(true);
when(endSessionRestWebService.getTokenHintGrant("test")).thenReturn(null);

endSessionRestWebService.validateIdTokenHint("testToken", null, "http://postlogout.com");
endSessionRestWebService.validateIdTokenHint("testToken", null, "http://postlogout.com", "");
}

@Test(expectedExceptions = WebApplicationException.class)
public void validateIdTokenHint_whenIdTokenIsNotValidJwt_shouldGetError() {
when(appConfiguration.getEndSessionWithAccessToken()).thenReturn(true);
when(endSessionRestWebService.getTokenHintGrant("notValidJwt")).thenReturn(GRANT);

endSessionRestWebService.validateIdTokenHint("notValidJwt", null, "http://postlogout.com");
endSessionRestWebService.validateIdTokenHint("notValidJwt", null, "http://postlogout.com", "");
}

@Test
public void validateIdTokenHint_whenIdTokenIsValidJwt_shouldGetValidJwt() {
when(appConfiguration.getEndSessionWithAccessToken()).thenReturn(true);
when(endSessionRestWebService.getTokenHintGrant(DUMMY_JWT)).thenReturn(GRANT);

final Jwt jwt = endSessionRestWebService.validateIdTokenHint(DUMMY_JWT, null, "http://postlogout.com");
final Jwt jwt = endSessionRestWebService.validateIdTokenHint(DUMMY_JWT, null, "http://postlogout.com", "");
assertNotNull(jwt);
}

Expand All @@ -134,7 +151,7 @@ public void validateIdTokenHint_whenIdTokenSignatureIsBad_shouldGetError() throw
when(endSessionRestWebService.getTokenHintGrant(DUMMY_JWT)).thenReturn(null);
when(cryptoProvider.verifySignature(anyString(), anyString(), anyString(), isNull(), isNull(), any())).thenReturn(false);

assertNull(endSessionRestWebService.validateIdTokenHint(DUMMY_JWT, null, "http://postlogout.com"));
assertNull(endSessionRestWebService.validateIdTokenHint(DUMMY_JWT, null, "http://postlogout.com", ""));
}

@Test
Expand All @@ -144,7 +161,7 @@ public void validateIdTokenHint_whenIdTokenIsExpiredAndSidCheckIsNotRequired_sho
when(endSessionRestWebService.getTokenHintGrant(DUMMY_JWT)).thenReturn(null);
when(cryptoProvider.verifySignature(anyString(), anyString(), isNull(), isNull(), isNull(), any())).thenReturn(true);

final Jwt jwt = endSessionRestWebService.validateIdTokenHint(DUMMY_JWT, null, "http://postlogout.com");
final Jwt jwt = endSessionRestWebService.validateIdTokenHint(DUMMY_JWT, null, "http://postlogout.com", "");
assertNotNull(jwt);
}

Expand All @@ -158,7 +175,7 @@ public void validateIdTokenHint_whenIdTokenIsExpiredAndSidCheckIsRequired_should
SessionId sidSession = new SessionId();
sidSession.setOutsideSid("1234"); // sid encoded into DUMMY_JWT

final Jwt jwt = endSessionRestWebService.validateIdTokenHint(DUMMY_JWT, sidSession, "http://postlogout.com");
final Jwt jwt = endSessionRestWebService.validateIdTokenHint(DUMMY_JWT, sidSession, "http://postlogout.com", "");
assertNotNull(jwt);
}

Expand All @@ -172,7 +189,7 @@ public void validateIdTokenHint_whenIdTokenIsExpiredAndSidCheckIsRequiredButSess
SessionId sidSession = new SessionId();
sidSession.setOutsideSid("12345"); // sid encoded into DUMMY_JWT

final Jwt jwt = endSessionRestWebService.validateIdTokenHint(DUMMY_JWT, sidSession, "http://postlogout.com");
final Jwt jwt = endSessionRestWebService.validateIdTokenHint(DUMMY_JWT, sidSession, "http://postlogout.com", "");
assertNotNull(jwt);
}
}

0 comments on commit 4e21972

Please sign in to comment.