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

feat(jans-auth-server): end session - if id_token is expired but signature is correct, we should make attempt to look up session by "sid" claim #3231 #3291

Merged
merged 2 commits into from
Dec 12, 2022
Merged
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 @@ -37,6 +37,7 @@
import io.jans.as.server.service.external.ExternalEndSessionService;
import io.jans.as.server.service.external.context.EndSessionContext;
import io.jans.as.server.util.ServerUtil;
import io.jans.as.server.util.TokenHashUtil;
import io.jans.model.security.Identity;
import io.jans.util.Pair;
import io.jans.util.StringHelper;
Expand Down Expand Up @@ -125,16 +126,16 @@ public Response requestEndSession(String idTokenHint, String postLogoutRedirectU
errorResponseFactory.validateFeatureEnabled(FeatureFlagType.END_SESSION);

final SessionId sidSession = validateSidRequestParameter(sid, postLogoutRedirectUri);
Jwt idToken = validateIdTokenHint(idTokenHint, sidSession, postLogoutRedirectUri);
Jwt validatedIdToken = validateIdTokenHint(idTokenHint, sidSession, postLogoutRedirectUri);

final Pair<SessionId, AuthorizationGrant> pair = getPair(idTokenHint, sid, httpRequest);
final Pair<SessionId, AuthorizationGrant> pair = getPair(idTokenHint, validatedIdToken, sid, httpRequest);
if (pair.getFirst() == null) {
final String reason = "Failed to identify session by session_id query parameter or by session_id cookie.";
throw new WebApplicationException(createErrorResponse(postLogoutRedirectUri, EndSessionErrorResponseType.INVALID_GRANT_AND_SESSION, reason));
}

postLogoutRedirectUri = validatePostLogoutRedirectUri(postLogoutRedirectUri, pair);
validateSid(postLogoutRedirectUri, idToken, pair.getFirst());
validateSid(postLogoutRedirectUri, validatedIdToken, pair.getFirst());

endSession(pair, httpRequest, httpResponse);
auditLogging(httpRequest, pair);
Expand Down Expand Up @@ -311,7 +312,7 @@ private SessionId validateSidRequestParameter(String sid, String postLogoutRedir
return null;
}

protected Jwt validateIdTokenHint(String idTokenHint, SessionId sidSession, String postLogoutRedirectUri) {
private Jwt validateIdTokenHint(String idTokenHint, SessionId sidSession, String postLogoutRedirectUri) {
final boolean isIdTokenHintRequired = isTrue(appConfiguration.getForceIdTokenHintPrecense());

if (isIdTokenHintRequired && StringUtils.isBlank(idTokenHint)) { // must be present for logout tests #1279
Expand All @@ -331,6 +332,7 @@ protected Jwt validateIdTokenHint(String idTokenHint, SessionId sidSession, Stri

if (tokenHintGrant == null && isRejectEndSessionIfIdTokenExpired) {
final String reason = "id_token_hint is not valid. Logout is rejected. id_token_hint can be skipped or otherwise valid value must be provided.";
log.trace(reason);
throw new WebApplicationException(createErrorResponse(postLogoutRedirectUri, EndSessionErrorResponseType.INVALID_GRANT_AND_SESSION, reason));
}
return validateIdTokenJwt(tokenHintGrant, idTokenHint, sidSession, postLogoutRedirectUri);
Expand All @@ -342,9 +344,11 @@ private Jwt validateIdTokenJwt(AuthorizationGrant tokenHintGrant, String idToken
try {
final Jwt jwt = Jwt.parse(idTokenHint);
if (tokenHintGrant != null) { // id_token is in db
log.debug("Found id_token in db.");
return jwt;
}
validateIdTokenSignature(sidSession, jwt, postLogoutRedirectUri);
log.debug("id_token is validated successfully.");
return jwt;
} catch (InvalidJwtException e) {
log.error("Unable to parse id_token_hint as JWT.", e);
Expand All @@ -368,6 +372,7 @@ private void validateIdTokenSignature(SessionId sidSession, Jwt jwt, String post
if (isTrue(appConfiguration.getAllowEndSessionWithUnmatchedSid())) {
return;
}

final String sidClaim = jwt.getClaims().getClaimAsString("sid");
if (sidSession != null && StringUtils.equals(sidSession.getOutsideSid(), sidClaim)) {
return;
Expand All @@ -381,7 +386,12 @@ protected AuthorizationGrant getTokenHintGrant(String idTokenHint) {
return null;
}

AuthorizationGrant authorizationGrant = authorizationGrantList.getAuthorizationGrantByIdToken(idTokenHint);
AuthorizationGrant authorizationGrant = authorizationGrantList.getAuthorizationGrantByIdToken(TokenHashUtil.hash(idTokenHint));
if (authorizationGrant != null) {
return authorizationGrant;
}

authorizationGrant = authorizationGrantList.getAuthorizationGrantByIdToken(idTokenHint);
if (authorizationGrant != null) {
return authorizationGrant;
}
Expand Down Expand Up @@ -457,7 +467,7 @@ private Response okResponse(String html) {
build();
}

private Pair<SessionId, AuthorizationGrant> getPair(String idTokenHint, String sid, HttpServletRequest httpRequest) {
private Pair<SessionId, AuthorizationGrant> getPair(String idTokenHint, Jwt validatedIdToken, String sid, HttpServletRequest httpRequest) {
AuthorizationGrant authorizationGrant = authorizationGrantList.getAuthorizationGrantByIdToken(idTokenHint);
if (authorizationGrant == null) {
Boolean endSessionWithAccessToken = appConfiguration.getEndSessionWithAccessToken();
Expand All @@ -466,20 +476,32 @@ private Pair<SessionId, AuthorizationGrant> getPair(String idTokenHint, String s
}
}

SessionId ldapSessionId = null;
SessionId sessionId = null;

try {
String id = cookieService.getSessionIdFromCookie(httpRequest);
if (StringHelper.isNotEmpty(id)) {
ldapSessionId = sessionIdService.getSessionId(id);
String cookieSessionId = cookieService.getSessionIdFromCookie(httpRequest);
if (StringHelper.isNotEmpty(cookieSessionId)) {
sessionId = sessionIdService.getSessionId(cookieSessionId);
}
if (sessionId == null && StringUtils.isNotBlank(sid)) {
sessionId = sessionIdService.getSessionBySid(sid);
}
if (sessionId == null && validatedIdToken != null) {
final String sidClaim = validatedIdToken.getClaims().getClaimAsString("sid");
if (StringUtils.isNotBlank(sidClaim)) {
sessionId = sessionIdService.getSessionBySid(sidClaim);
}
}
if (StringUtils.isNotBlank(sid) && ldapSessionId == null) {
ldapSessionId = sessionIdService.getSessionBySid(sid);

if (sessionId == null) {
log.trace("Unable to find session for ending.");
} else {
log.trace("Found session for ending successfully.");
}
} catch (Exception e) {
log.error("Failed to current session id.", e);
log.error("Failed to find current session id.", e);
}
return new Pair<>(ldapSessionId, authorizationGrant);
return new Pair<>(sessionId, authorizationGrant);
}

private void endSession(Pair<SessionId, AuthorizationGrant> pair, HttpServletRequest httpRequest, HttpServletResponse httpResponse) {
Expand Down