Skip to content

Commit

Permalink
feat(jans-auth-server): populate statusListIndex in access and id tokens
Browse files Browse the repository at this point in the history
#8562
Signed-off-by: YuriyZ <yzabrovarniy@gmail.com>
  • Loading branch information
yuriyz committed Jun 7, 2024
1 parent 80d0efd commit 47b5f9b
Show file tree
Hide file tree
Showing 9 changed files with 90 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ public abstract class AbstractAuthorizationGrant implements IAuthorizationGrant
private String claims;
private String dpopJkt;
private String referenceId;
private Integer statusListIndex;

private String acrValues;
private String sessionDn;
Expand Down Expand Up @@ -107,6 +108,14 @@ public void setReferenceId(String referenceId) {
this.referenceId = referenceId;
}

public Integer getStatusListIndex() {
return statusListIndex;
}

public void setStatusListIndex(Integer statusListIndex) {
this.statusListIndex = statusListIndex;
}

public String getDpopJkt() {
return dpopJkt;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ public abstract class AbstractToken implements Serializable, Deletable {
@AttributeName(name = "jansId")
private String referenceId;

private Integer statusListIndex;

@Expiration
private int ttl;

Expand Down Expand Up @@ -232,6 +234,24 @@ public void setReferenceId(String referenceId) {
this.referenceId = referenceId;
}

/**
* Gets status list index
*
* @return status list index
*/
public Integer getStatusListIndex() {
return statusListIndex;
}

/**
* Sets status list index
*
* @param statusListIndex status list index
*/
public void setStatusListIndex(Integer statusListIndex) {
this.statusListIndex = statusListIndex;
}

/**
* Return <code>true</code> if the token has expired.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import io.jans.as.common.model.registration.Client;
import io.jans.as.common.service.AttributeService;
import io.jans.as.model.authzdetails.AuthzDetails;
import io.jans.as.model.common.FeatureFlagType;
import io.jans.as.model.common.ScopeConstants;
import io.jans.as.model.config.WebKeysConfiguration;
import io.jans.as.model.crypto.signature.SignatureAlgorithm;
Expand All @@ -34,6 +35,7 @@
import io.jans.as.server.service.external.context.ExternalIntrospectionContext;
import io.jans.as.server.service.external.context.ExternalUpdateTokenContext;
import io.jans.as.server.service.stat.StatService;
import io.jans.as.server.service.token.StatusListIndexService;
import io.jans.as.server.service.token.StatusListService;
import io.jans.as.server.util.ServerUtil;
import io.jans.as.server.util.TokenHashUtil;
Expand Down Expand Up @@ -106,6 +108,9 @@ public abstract class AuthorizationGrant extends AbstractAuthorizationGrant {
@Inject
private StatusListService statusListService;

@Inject
private StatusListIndexService statusListIndexService;

private boolean isCachedWithNoPersistence = false;

protected AuthorizationGrant() {
Expand All @@ -123,10 +128,17 @@ public void init(User user, AuthorizationGrantType authorizationGrantType, Clien
private IdToken createIdTokenInternal(AuthorizationCode authorizationCode, AccessToken accessToken, RefreshToken refreshToken, ExecutionContext executionContext) throws Exception {
executionContext.initFromGrantIfNeeded(this);

Integer statusListIndex = null;
if (errorResponseFactory.isFeatureFlagEnabled(FeatureFlagType.TOKEN_STATUS_LIST)) {
statusListIndex = statusListIndexService.next();
executionContext.setStatusListIndex(statusListIndex);
}

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));
idToken.setReferenceId(executionContext.getTokenReferenceId());
idToken.setStatusListIndex(statusListIndex);
if (log.isTraceEnabled())
log.trace("Created id_token: {}", idToken.getCode());
return idToken;
Expand Down Expand Up @@ -210,6 +222,14 @@ public AccessToken createAccessToken(ExecutionContext context) {
context.generateRandomTokenReferenceId();

final AccessToken accessToken = super.createAccessToken(context);

Integer statusListIndex = null;
if (errorResponseFactory.isFeatureFlagEnabled(FeatureFlagType.TOKEN_STATUS_LIST)) {
statusListIndex = statusListIndexService.next();
context.setStatusListIndex(statusListIndex);
accessToken.setStatusListIndex(statusListIndex);
}

if (accessToken.getExpiresIn() < 0) {
log.trace("Failed to create access token with negative expiration time");
return null;
Expand Down Expand Up @@ -305,7 +325,7 @@ public JwtSigner createAccessTokenAsJwt(AccessToken accessToken, ExecutionContex
}

Audience.setAudience(jwt.getClaims(), getClient());
statusListService.addStatusClaimWithIndex(jwt);
statusListService.addStatusClaimWithIndex(jwt, context);

if (isTrue(client.getAttributes().getRunIntrospectionScriptBeforeJwtCreation())) {
runIntrospectionScriptAndInjectValuesIntoJwt(jwt, context);
Expand Down Expand Up @@ -499,6 +519,7 @@ public TokenEntity asTokenEntity(AbstractToken token) {
result.setClientId(getClientId());
result.setReferenceId(token.getReferenceId());

result.getAttributes().setStatusListIndex(token.getStatusListIndex());
result.getAttributes().setX5cs256(token.getX5ts256());
result.getAttributes().setDpopJkt(getDpopJkt());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,7 @@ public AuthorizationGrant asGrant(TokenEntity tokenEntity) {
result.setDpopJkt(tokenEntity.getAttributes().getDpopJkt());
result.setTokenEntity(tokenEntity);
result.setReferenceId(tokenEntity.getReferenceId());
result.setStatusListIndex(tokenEntity.getAttributes().getStatusListIndex());
if (StringUtils.isNotBlank(grantId)) {
result.setGrantId(grantId);
}
Expand Down Expand Up @@ -382,39 +383,45 @@ public AuthorizationGrant asGrant(TokenEntity tokenEntity) {
final AuthorizationCodeGrant g = (AuthorizationCodeGrant) result;
code.setX5ts256(g.getX5ts256());
code.setReferenceId(tokenEntity.getReferenceId());
code.setStatusListIndex(tokenEntity.getAttributes().getStatusListIndex());
g.setAuthorizationCode(code);
}
break;
case REFRESH_TOKEN:
final RefreshToken refreshToken = new RefreshToken(tokenEntity.getTokenCode(), tokenEntity.getCreationDate(), tokenEntity.getExpirationDate());
refreshToken.setX5ts256(result.getX5ts256());
refreshToken.setReferenceId(tokenEntity.getReferenceId());
refreshToken.setStatusListIndex(tokenEntity.getAttributes().getStatusListIndex());
result.setRefreshTokens(Collections.singletonList(refreshToken));
break;
case ACCESS_TOKEN:
final AccessToken accessToken = new AccessToken(tokenEntity.getTokenCode(), tokenEntity.getCreationDate(), tokenEntity.getExpirationDate());
accessToken.setDpop(tokenEntity.getDpop());
accessToken.setX5ts256(result.getX5ts256());
accessToken.setReferenceId(tokenEntity.getReferenceId());
accessToken.setStatusListIndex(tokenEntity.getAttributes().getStatusListIndex());
result.setAccessTokens(Collections.singletonList(accessToken));
break;
case TX_TOKEN:
final TxToken txToken = new TxToken(tokenEntity.getTokenCode(), tokenEntity.getCreationDate(), tokenEntity.getExpirationDate());
txToken.setDpop(tokenEntity.getDpop());
txToken.setX5ts256(result.getX5ts256());
txToken.setReferenceId(tokenEntity.getReferenceId());
txToken.setStatusListIndex(tokenEntity.getAttributes().getStatusListIndex());
result.setTxTokens(Collections.singletonList(txToken));
break;
case ID_TOKEN:
final IdToken idToken = new IdToken(tokenEntity.getTokenCode(), tokenEntity.getCreationDate(), tokenEntity.getExpirationDate());
idToken.setX5ts256(result.getX5ts256());
idToken.setReferenceId(tokenEntity.getReferenceId());
idToken.setStatusListIndex(tokenEntity.getAttributes().getStatusListIndex());
result.setIdToken(idToken);
break;
case LONG_LIVED_ACCESS_TOKEN:
final AccessToken longLivedAccessToken = new AccessToken(tokenEntity.getTokenCode(), tokenEntity.getCreationDate(), tokenEntity.getExpirationDate());
longLivedAccessToken.setX5ts256(result.getX5ts256());
longLivedAccessToken.setReferenceId(tokenEntity.getReferenceId());
longLivedAccessToken.setStatusListIndex(tokenEntity.getAttributes().getStatusListIndex());
result.setLongLivedAccessToken(longLivedAccessToken);
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ public class ExecutionContext {
private String nonce;
private String state;
private String tokenReferenceId = IdUtil.randomShortUUID();
private Integer statusListIndex;

private boolean includeIdTokenClaims;

Expand Down Expand Up @@ -160,6 +161,14 @@ public static ExecutionContext of(ExecutionContext context) {
return executionContext;
}

public Integer getStatusListIndex() {
return statusListIndex;
}

public void setStatusListIndex(Integer statusListIndex) {
this.statusListIndex = statusListIndex;
}

public String generateRandomTokenReferenceId() {
tokenReferenceId = IdUtil.randomShortUUID();
return tokenReferenceId;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ private void fillClaims(JsonWebResponse jwr,
jwr.setClaim("sid", session.getOutsideSid());
}

statusListService.addStatusClaimWithIndex(jwr);
statusListService.addStatusClaimWithIndex(jwr, executionContext);

addTokenExchangeClaims(jwr, executionContext, session);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ public class StatusListIndexService {

private TokenPool tokenPool = null;

public Integer next() {
return nextIndex().getFirst();
}

public Pair<Integer, TokenPool> nextIndex() {
// Create copy of variable to make sure that another Thread not changed it
TokenPool localTokenPool = tokenPool;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import io.jans.as.model.configuration.AppConfiguration;
import io.jans.as.model.error.ErrorResponseFactory;
import io.jans.as.model.token.JsonWebResponse;
import io.jans.as.server.model.common.ExecutionContext;
import io.jans.as.server.service.DiscoveryService;
import io.jans.as.server.service.cluster.TokenPoolService;
import io.jans.model.token.TokenPool;
Expand Down Expand Up @@ -108,14 +109,19 @@ public StatusList join(List<TokenPool> pools) {
return result;
}

public void addStatusClaimWithIndex(JsonWebResponse jwr) {
public void addStatusClaimWithIndex(JsonWebResponse jwr, ExecutionContext executionContext) {
if (!errorResponseFactory.isFeatureFlagEnabled(FeatureFlagType.TOKEN_STATUS_LIST)) {
log.trace("Skipped status claim addition because {} feature flag is disabled.", FeatureFlagType.TOKEN_STATUS_LIST.getValue());
return;
}

final Integer index = executionContext.getStatusListIndex();
if (index == null || index < 0) {
return; // index is not set. It must be set into context to be saved in both entity bean and jwt consistently
}

final JSONObject indexAndUri = new JSONObject();
indexAndUri.put("idx", statusListIndexService.nextIndex());
indexAndUri.put("idx", index);
indexAndUri.put("uri", discoveryService.getTokenStatusListEndpoint());

final JSONObject statusList = new JSONObject();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@ public class TokenAttributes implements Serializable {
private String dpopJkt;
@JsonProperty("authorizationDetails")
private String authorizationDetails;
@JsonProperty("statusListIndex")
private Integer statusListIndex;

public Integer getStatusListIndex() {
return statusListIndex;
}

public void setStatusListIndex(Integer statusListIndex) {
this.statusListIndex = statusListIndex;
}

public String getAuthorizationDetails() {
return authorizationDetails;
Expand Down

0 comments on commit 47b5f9b

Please sign in to comment.