Skip to content

Commit

Permalink
Merge pull request #338 from JanssenProject/yuriyz_fixes
Browse files Browse the repository at this point in the history
feat: added support for getIdTokenLifetimeInSeconds in update token script
  • Loading branch information
yuriyz authored Nov 23, 2021
2 parents 82259c5 + 63d1c34 commit 95b9083
Show file tree
Hide file tree
Showing 9 changed files with 208 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -713,13 +713,19 @@ private Response requestAuthorization(
}

ExternalUpdateTokenContext context = new ExternalUpdateTokenContext(httpRequest, authorizationGrant, client, appConfiguration, attributeService);

final Function<JsonWebResponse, Void> preProcessor = JwrService.wrapWithSidFunction(TokenBindingMessage.createIdTokenTokingBindingPreprocessing(tokenBindingHeader, client.getIdTokenTokenBindingCnf()), sessionUser.getOutsideSid());
Function<JsonWebResponse, Void> postProcessor = externalUpdateTokenService.buildModifyIdTokenProcessor(context);

final ExecutionContext executionContext = context.toExecutionContext();
executionContext.setPreProcessing(preProcessor);
executionContext.setPostProcessor(postProcessor);
executionContext.setIncludeIdTokenClaims(includeIdTokenClaims);
executionContext.setGrant(authorizationGrant);

IdToken idToken = authorizationGrant.createIdToken(
nonce, authorizationCode, newAccessToken, null,
state, authorizationGrant, includeIdTokenClaims,
JwrService.wrapWithSidFunction(TokenBindingMessage.createIdTokenTokingBindingPreprocessing(tokenBindingHeader, client.getIdTokenTokenBindingCnf()), sessionUser.getOutsideSid()),
postProcessor);
state, executionContext);

redirectUriResponse.getRedirectUri().addResponseParameter(AuthorizeResponseParam.ID_TOKEN, idToken.getCode());
}
Expand Down Expand Up @@ -848,7 +854,7 @@ private void runCiba(String authReqId, Client client, HttpServletRequest httpReq
log.debug("Issuing access token: {}", accessToken.getCode());

ExternalUpdateTokenContext context = new ExternalUpdateTokenContext(httpRequest, cibaGrant, client, appConfiguration, attributeService);
Function<JsonWebResponse, Void> postProcessor = externalUpdateTokenService.buildModifyIdTokenProcessor(context);


final int refreshTokenLifetimeInSeconds = externalUpdateTokenService.getRefreshTokenLifetimeInSeconds(context);
final RefreshToken refreshToken;
Expand All @@ -859,9 +865,11 @@ private void runCiba(String authReqId, Client client, HttpServletRequest httpReq
}
log.debug("Issuing refresh token: {}", (refreshToken != null ? refreshToken.getCode() : ""));

IdToken idToken = cibaGrant.createIdToken(
null, null, accessToken, refreshToken,
null, cibaGrant, false, null, postProcessor);
executionContext.setPostProcessor(externalUpdateTokenService.buildModifyIdTokenProcessor(context));
executionContext.setGrant(cibaGrant);
executionContext.setIncludeIdTokenClaims(false);

IdToken idToken = cibaGrant.createIdToken(null, null, accessToken, refreshToken,null, executionContext);

cibaGrant.setTokensDelivered(true);
cibaGrant.save();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,6 @@
import javax.inject.Inject;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Supplier;

import static org.apache.commons.lang3.BooleanUtils.isTrue;
Expand Down Expand Up @@ -107,13 +105,8 @@ public void init(User user, AuthorizationGrantType authorizationGrantType, Clien
super.init(user, authorizationGrantType, client, authenticationTime);
}

public IdToken createIdToken(
IAuthorizationGrant grant, String nonce,
AuthorizationCode authorizationCode, AccessToken accessToken, RefreshToken refreshToken,
String state, Set<String> scopes, boolean includeIdTokenClaims, Function<JsonWebResponse,
Void> preProcessing, Function<JsonWebResponse, Void> postProcessing, String claims) throws Exception {
JsonWebResponse jwr = idTokenFactory.createJwr(grant, nonce, authorizationCode, accessToken, refreshToken,
state, scopes, includeIdTokenClaims, preProcessing, postProcessing, claims);
private IdToken createIdTokenInternal(AuthorizationCode authorizationCode, AccessToken accessToken, RefreshToken refreshToken, ExecutionContext executionContext) throws Exception {
JsonWebResponse jwr = idTokenFactory.createJwr(this, authorizationCode, accessToken, refreshToken, executionContext);
final IdToken idToken = new IdToken(jwr.toString(), jwr.getClaims().getClaimAsDate(JwtClaimName.ISSUED_AT),
jwr.getClaims().getClaimAsDate(JwtClaimName.EXPIRATION_TIME));
if (log.isTraceEnabled())
Expand Down Expand Up @@ -349,12 +342,17 @@ public RefreshToken createRefreshToken(ExecutionContext context, Date expiration
@Override
public IdToken createIdToken(
String nonce, AuthorizationCode authorizationCode, AccessToken accessToken, RefreshToken refreshToken,
String state, AuthorizationGrant authorizationGrant, boolean includeIdTokenClaims, Function<JsonWebResponse, Void> preProcessing, Function<JsonWebResponse, Void> postProcessing) {
String state, ExecutionContext executionContext) {
try {
final IdToken idToken = createIdToken(this, nonce, authorizationCode, accessToken, refreshToken,
state, getScopes(), includeIdTokenClaims, preProcessing, postProcessing, this.getClaims());
final String acrValues = authorizationGrant.getAcrValues();
final String sessionDn = authorizationGrant.getSessionDn();
executionContext.setScopes(getScopes());
executionContext.setClaimsAsString(getClaims());
executionContext.setNonce(nonce);
executionContext.setState(state);

final IdToken idToken = createIdTokenInternal(authorizationCode, accessToken, refreshToken, executionContext);
final AuthorizationGrant grant = executionContext.getGrant();
final String acrValues = grant.getAcrValues();
final String sessionDn = grant.getSessionDn();
if (idToken.getExpiresIn() > 0) {
final TokenEntity tokenEntity = asToken(idToken);
tokenEntity.setAuthMode(acrValues);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,17 @@
import io.jans.as.common.model.registration.Client;
import io.jans.as.common.service.AttributeService;
import io.jans.as.model.configuration.AppConfiguration;
import io.jans.as.model.token.JsonWebResponse;
import io.jans.as.server.model.ldap.TokenEntity;
import io.jans.model.custom.script.conf.CustomScriptConfiguration;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;

/**
* @author Yuriy Zabrovarnyy
Expand All @@ -42,6 +46,17 @@ public class ExecutionContext {
private String dpop;
private String certAsPem;

private String nonce;
private String state;

private boolean includeIdTokenClaims;

private Function<JsonWebResponse, Void> preProcessing;
private Function<JsonWebResponse, Void> postProcessor;

private Set<String> scopes;
private String claimsAsString;

@NotNull
private final Map<String, String> attributes = new HashMap<>();

Expand Down Expand Up @@ -158,4 +173,61 @@ public String getCertAsPem() {
public void setCertAsPem(String certAsPem) {
this.certAsPem = certAsPem;
}

public boolean isIncludeIdTokenClaims() {
return includeIdTokenClaims;
}

public void setIncludeIdTokenClaims(boolean includeIdTokenClaims) {
this.includeIdTokenClaims = includeIdTokenClaims;
}

public Function<JsonWebResponse, Void> getPreProcessing() {
return preProcessing;
}

public void setPreProcessing(Function<JsonWebResponse, Void> preProcessing) {
this.preProcessing = preProcessing;
}

public Function<JsonWebResponse, Void> getPostProcessor() {
return postProcessor;
}

public void setPostProcessor(Function<JsonWebResponse, Void> postProcessor) {
this.postProcessor = postProcessor;
}

public Set<String> getScopes() {
if (scopes == null) scopes = new HashSet<>();
return scopes;
}

public void setScopes(Set<String> scopes) {
this.scopes = scopes;
}

public String getClaimsAsString() {
return claimsAsString;
}

public void setClaimsAsString(String claimsAsString) {
this.claimsAsString = claimsAsString;
}

public String getNonce() {
return nonce;
}

public void setNonce(String nonce) {
this.nonce = nonce;
}

public String getState() {
return state;
}

public void setState(String state) {
this.state = state;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,13 @@
import io.jans.as.common.model.common.User;
import io.jans.as.common.model.registration.Client;
import io.jans.as.model.common.GrantType;
import io.jans.as.model.token.JsonWebResponse;
import io.jans.as.server.model.authorize.JwtAuthorizationRequest;
import io.jans.as.server.model.ldap.TokenEntity;

import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.function.Function;

/**
* @author Yuriy Zabrovarnyy
Expand Down Expand Up @@ -51,7 +49,7 @@ public interface IAuthorizationGrant {

IdToken createIdToken(
String nonce, AuthorizationCode authorizationCode, AccessToken accessToken, RefreshToken refreshToken,
String state, AuthorizationGrant authorizationGrant, boolean includeIdTokenClaims, Function<JsonWebResponse, Void> preProcessing, Function<JsonWebResponse, Void> postProcessing);
String state, ExecutionContext executionContext);

RefreshToken getRefreshToken(String refreshTokenCode);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,13 @@
import io.jans.as.common.model.common.User;
import io.jans.as.common.model.registration.Client;
import io.jans.as.model.common.GrantType;
import io.jans.as.model.token.JsonWebResponse;
import io.jans.as.server.model.authorize.JwtAuthorizationRequest;
import io.jans.as.server.model.ldap.TokenEntity;

import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.function.Function;

/**
* Gives ability to use authorization grant in read-only mode.
Expand Down Expand Up @@ -95,8 +93,7 @@ public RefreshToken createRefreshToken(ExecutionContext executionContext, int li
@Override
public IdToken createIdToken(
String nonce, AuthorizationCode authorizationCode, AccessToken accessToken, RefreshToken refreshToken,
String state, AuthorizationGrant authorizationGrant, boolean includeIdTokenClaims, Function<JsonWebResponse, Void> preProcessing,
Function<JsonWebResponse, Void> postProcessing) {
String state, ExecutionContext executionContext) {
throw new UnsupportedOperationException(NOT_ALLOWED_FOR_UNMODIFIABLE_AUTHORIZATION_GRANT);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@
import io.jans.as.server.service.SessionIdService;
import io.jans.as.server.service.external.ExternalAuthenticationService;
import io.jans.as.server.service.external.ExternalDynamicScopeService;
import io.jans.as.server.service.external.ExternalUpdateTokenService;
import io.jans.as.server.service.external.context.DynamicScopeExternalContext;
import io.jans.as.server.service.external.context.ExternalUpdateTokenContext;
import io.jans.model.GluuAttribute;
import io.jans.model.custom.script.conf.CustomScriptConfiguration;
import io.jans.model.custom.script.type.auth.PersonAuthenticationType;
Expand All @@ -39,7 +41,6 @@
import javax.inject.Inject;
import javax.inject.Named;
import java.util.*;
import java.util.function.Function;

import static io.jans.as.model.common.ScopeType.DYNAMIC;

Expand Down Expand Up @@ -70,6 +71,9 @@ public class IdTokenFactory {
@Inject
private ExternalAuthenticationService externalAuthenticationService;

@Inject
private ExternalUpdateTokenService externalUpdateTokenService;

@Inject
private ScopeService scopeService;

Expand Down Expand Up @@ -109,15 +113,20 @@ private void setAmrClaim(JsonWebResponse jwt, String acrValues) {
}

private void fillClaims(JsonWebResponse jwr,
IAuthorizationGrant authorizationGrant, String nonce,
IAuthorizationGrant authorizationGrant,
AuthorizationCode authorizationCode, AccessToken accessToken, RefreshToken refreshToken,
String state, Set<String> scopes, boolean includeIdTokenClaims, Function<JsonWebResponse,
Void> preProcessing, Function<JsonWebResponse, Void> postProcessing, String requestedClaims) throws Exception {
ExecutionContext executionContext) throws Exception {

jwr.getClaims().setIssuer(appConfiguration.getIssuer());
Audience.setAudience(jwr.getClaims(), authorizationGrant.getClient());

int lifeTime = appConfiguration.getIdTokenLifetime();
int lifetimeFromScript = externalUpdateTokenService.getIdTokenLifetimeInSeconds(ExternalUpdateTokenContext.of(executionContext));
if (lifetimeFromScript > 0) {
lifeTime = lifetimeFromScript;
log.trace("Override id token lifetime with value from script: {}", lifetimeFromScript);
}

Calendar calendar = Calendar.getInstance();
Date issuedAt = calendar.getTime();
calendar.add(Calendar.SECOND, lifeTime);
Expand All @@ -127,8 +136,8 @@ private void fillClaims(JsonWebResponse jwr,
jwr.getClaims().setIssuedAt(issuedAt);
jwr.setClaim("code", UUID.randomUUID().toString());

if (preProcessing != null) {
preProcessing.apply(jwr);
if (executionContext.getPreProcessing() != null) {
executionContext.getPreProcessing().apply(jwr);
}
final SessionId session = sessionIdService.getSessionByDn(authorizationGrant.getSessionDn());
if (session != null) {
Expand All @@ -139,6 +148,7 @@ private void fillClaims(JsonWebResponse jwr,
jwr.setClaim(JwtClaimName.AUTHENTICATION_CONTEXT_CLASS_REFERENCE, authorizationGrant.getAcrValues());
setAmrClaim(jwr, authorizationGrant.getAcrValues());
}
String nonce = executionContext.getNonce();
if (StringUtils.isNotBlank(nonce)) {
jwr.setClaim(JwtClaimName.NONCE, nonce);
}
Expand All @@ -153,6 +163,7 @@ private void fillClaims(JsonWebResponse jwr,
String accessTokenHash = AbstractToken.getHash(accessToken.getCode(), jwr.getHeader().getSignatureAlgorithm());
jwr.setClaim(JwtClaimName.ACCESS_TOKEN_HASH, accessTokenHash);
}
String state = executionContext.getState();
if (Strings.isNotBlank(state)) {
String stateHash = AbstractToken.getHash(state, jwr.getHeader().getSignatureAlgorithm());
jwr.setClaim(JwtClaimName.STATE_HASH, stateHash);
Expand All @@ -164,8 +175,8 @@ private void fillClaims(JsonWebResponse jwr,

User user = authorizationGrant.getUser();
List<Scope> dynamicScopes = new ArrayList<>();
if (includeIdTokenClaims && authorizationGrant.getClient().isIncludeClaimsInIdToken()) {
for (String scopeName : scopes) {
if (executionContext.isIncludeIdTokenClaims() && authorizationGrant.getClient().isIncludeClaimsInIdToken()) {
for (String scopeName : executionContext.getScopes()) {
Scope scope = scopeService.getScopeById(scopeName);
if (scope == null) {
continue;
Expand Down Expand Up @@ -214,8 +225,8 @@ private void fillClaims(JsonWebResponse jwr,
}
}

setClaimsFromJwtAuthorizationRequest(jwr, authorizationGrant, scopes);
setClaimsFromRequestedClaims(requestedClaims, jwr, user);
setClaimsFromJwtAuthorizationRequest(jwr, authorizationGrant, executionContext.getScopes());
setClaimsFromRequestedClaims(executionContext.getClaimsAsString(), jwr, user);
filterClaimsBasedOnAccessToken(jwr, accessToken, authorizationCode);
jwrService.setSubjectIdentifier(jwr, authorizationGrant);

Expand All @@ -227,8 +238,8 @@ private void fillClaims(JsonWebResponse jwr,

processCiba(jwr, authorizationGrant, refreshToken);

if (postProcessing != null) {
postProcessing.apply(jwr);
if (executionContext.getPostProcessor() != null) {
executionContext.getPostProcessor().apply(jwr);
}
}

Expand Down Expand Up @@ -322,18 +333,15 @@ private void setClaimsFromJwtAuthorizationRequest(JsonWebResponse jwr, IAuthoriz
}

public JsonWebResponse createJwr(
IAuthorizationGrant grant, String nonce,
AuthorizationCode authorizationCode, AccessToken accessToken, RefreshToken refreshToken,
String state, Set<String> scopes, boolean includeIdTokenClaims, Function<JsonWebResponse,
Void> preProcessing, Function<JsonWebResponse, Void> postProcessing, String claims) throws Exception {
IAuthorizationGrant grant, AuthorizationCode authorizationCode, AccessToken accessToken, RefreshToken refreshToken,
ExecutionContext executionContext) throws Exception {

final Client client = grant.getClient();

JsonWebResponse jwr = jwrService.createJwr(client);
fillClaims(jwr, grant, nonce, authorizationCode, accessToken, refreshToken, state, scopes,
includeIdTokenClaims, preProcessing, postProcessing, claims);
fillClaims(jwr, grant, authorizationCode, accessToken, refreshToken, executionContext);
if (log.isTraceEnabled())
log.trace("Created claims for id_token, claims: " + jwr.getClaims().toJsonString());
log.trace("Created claims for id_token, claims: {}", jwr.getClaims().toJsonString());
return jwrService.encode(jwr, client);
}

Expand Down
Loading

0 comments on commit 95b9083

Please sign in to comment.