Skip to content

Commit

Permalink
Add constants for JWT claim names and audiences
Browse files Browse the repository at this point in the history
  • Loading branch information
vierbergenlars committed Jul 10, 2024
1 parent 274310c commit ed27711
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 10 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.contentgrid.gateway.runtime.security.authority;

import com.contentgrid.gateway.runtime.security.jwt.ContentGridClaimNames;
import com.contentgrid.gateway.security.authority.Actor;
import com.contentgrid.gateway.security.authority.DelegatedAuthenticationDetailsGrantedAuthority;
import com.contentgrid.gateway.security.jwt.issuer.encrypt.TextEncryptorFactory;
Expand All @@ -23,11 +24,11 @@ public class ExtensionDelegationGrantedAuthorityConverter implements

@Override
public Collection<GrantedAuthority> convert(Jwt source) {
var principal = actorConverter.convert(decryptClaims(source.getClaimAsString("restrict:principal_claims")));
var principal = actorConverter.convert(decryptClaims(source.getClaimAsString(ContentGridClaimNames.RESTRICT_PRINCIPAL_CLAIMS)));
if (principal == null) {
return null;
}
var actor = actorConverter.convert(() -> source.getClaimAsMap("act"));
var actor = actorConverter.convert(() -> source.getClaimAsMap(ContentGridClaimNames.ACT));
if (actor == null) {
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.contentgrid.gateway.runtime.security.authority.ClaimUtil;
import com.contentgrid.gateway.runtime.security.authority.ExtensionDelegationGrantedAuthorityConverter;
import com.contentgrid.gateway.runtime.security.bearer.RuntimePlatformExternalIssuerProperties.OidcIssuerProperties;
import com.contentgrid.gateway.runtime.security.jwt.ContentGridAudiences;
import com.contentgrid.gateway.security.authority.Actor;
import com.contentgrid.gateway.security.authority.Actor.ActorType;
import com.contentgrid.gateway.security.authority.ActorConverter;
Expand Down Expand Up @@ -147,7 +148,7 @@ private static PostValidatingJwtAuthenticationManager<List<String>> createApplic
) {
return new PostValidatingJwtAuthenticationManager<>(
new JwtClaimValidator<List<String>>(JwtClaimNames.AUD,
aud -> aud != null && aud.contains("contentgrid:application:" + applicationId.getValue())),
aud -> aud != null && aud.contains(ContentGridAudiences.application(applicationId))),
new DelegatingReactiveAuthenticationManager(
extensionSystemAuthenticationManager,
extensionDelegationAuthenticationManager
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.contentgrid.gateway.runtime.security.jwt;

import com.contentgrid.gateway.runtime.application.ApplicationId;
import lombok.experimental.UtilityClass;

@UtilityClass
public class ContentGridAudiences {

/**
* Audience for the 'authentication' endpoint
* @see <a href="https://github.com/xenit-eu/contentgrid-system-design/blob/main/specs/automation-extension-authentication.md#client-facing-token-exchange">Automation extension authentication spec</a>
*/
public static final String SYSTEM_ENDPOINT_AUTHENTICATION = systemEndpoint("authentication");

public static String systemEndpoint(String endpointId) {
return "contentgrid:system:endpoints:"+endpointId;
}

/**
* Audience for an application
*
* @see <a href="https://github.com/xenit-eu/contentgrid-system-design/blob/main/specs/automation-extension-authentication.md#gateway-extension">Automation extension authentication spec</a>
*/
public static String application(ApplicationId applicationId) {
return "contentgrid:application:"+applicationId.getValue();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.contentgrid.gateway.runtime.security.jwt;

import lombok.experimental.UtilityClass;

@UtilityClass
public class ContentGridClaimNames {

/**
* Contains encrypted claims of the principal in a delegated authentication token
* @see <a href="https://github.com/xenit-eu/contentgrid-system-design/blob/main/specs/automation-extension-authentication.md#additional-jwt-claims">Automation extension authentication spec</a>
*/
public static final String RESTRICT_PRINCIPAL_CLAIMS = "restrict:principal_claims";

/**
* The application ID ({@link com.contentgrid.gateway.runtime.application.ApplicationId}) for which the token is valid
* @see <a href="https://github.com/xenit-eu/contentgrid-system-design/blob/main/specs/automation-extension-authentication.md#additional-jwt-claims">Automation extension authentication spec</a>
*/
public static final String CONTEXT_APPLICATION_ID = "context:application:id";

/**
* All domain names belonging to the application for which the token is valid
* @see <a href="https://github.com/xenit-eu/contentgrid-system-design/blob/main/specs/automation-extension-authentication.md#additional-jwt-claims">Automation extension authentication spec</a>
*/
public static final String CONTEXT_APPLICATION_DOMAINS = "context:application:domains";

/**
* Contains the claims of the actor in a delegated authentication token
* @see <a href="https://www.rfc-editor.org/rfc/rfc8693.html#name-act-actor-claim">RFC8693</a>
*/
public static final String ACT = "act";
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import com.contentgrid.gateway.runtime.application.ApplicationId;
import com.contentgrid.gateway.runtime.config.ApplicationConfigurationRepository;
import com.contentgrid.gateway.runtime.security.jwt.ContentGridAudiences;
import com.contentgrid.gateway.runtime.security.jwt.ContentGridClaimNames;
import com.contentgrid.gateway.security.authority.AuthenticationDetails;
import com.contentgrid.gateway.runtime.web.ContentGridAppRequestWebFilter;
import com.contentgrid.gateway.security.jwt.issuer.JwtClaimsResolver;
Expand Down Expand Up @@ -31,13 +33,13 @@ public Mono<JWTClaimsSet> resolveAdditionalClaims(ServerWebExchange exchange, Au

var claimsBuilder = new JWTClaimsSet.Builder();

claimsBuilder.audience("contentgrid:system:endpoints:authentication");
claimsBuilder.claim("context:application:id", applicationId.toString());
claimsBuilder.audience(ContentGridAudiences.SYSTEM_ENDPOINT_AUTHENTICATION);
claimsBuilder.claim(ContentGridClaimNames.CONTEXT_APPLICATION_ID, applicationId.toString());
if (applicationConfiguration != null) {
claimsBuilder.claim("context:application:domains", applicationConfiguration.getDomains());
claimsBuilder.claim(ContentGridClaimNames.CONTEXT_APPLICATION_DOMAINS, applicationConfiguration.getDomains());
}
try {
claimsBuilder.claim("restrict:principal_claims",
claimsBuilder.claim(ContentGridClaimNames.RESTRICT_PRINCIPAL_CLAIMS,
principalClaimsEncryptor.newEncryptor()
.encrypt(createFromClaimAccessor(authenticationDetails.getPrincipal().getClaims()))
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.contentgrid.gateway.security.authority;

import com.contentgrid.gateway.runtime.security.jwt.ContentGridClaimNames;
import com.contentgrid.gateway.security.authority.Actor.ActorType;
import java.util.function.Predicate;
import lombok.AllArgsConstructor;
Expand Down Expand Up @@ -29,7 +30,7 @@ public Actor convert(ClaimAccessor claimAccessor) {
if (!issuerMatcher.test(issuer)) {
return null;
}
var parentActorClaims = claimAccessor.getClaimAsMap("act");
var parentActorClaims = claimAccessor.getClaimAsMap(ContentGridClaimNames.ACT);
Actor parentActor;
if (parentActorClaims != null) {
/* The actor claim has a nested actor claim. A nested claim means a "parent" actor
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.contentgrid.gateway.security.jwt.issuer;

import com.contentgrid.gateway.runtime.security.jwt.ContentGridClaimNames;
import com.contentgrid.gateway.security.authority.Actor;
import com.contentgrid.gateway.security.authority.AuthenticationDetails;
import com.nimbusds.jose.JOSEException;
Expand Down Expand Up @@ -93,7 +94,7 @@ private Mono<JWTClaimsSet> createClaims(ServerWebExchange exchange, Authenticati
}
// RFC 8693
if(authenticationDetails.getActor() != null) {
builder.claim("act", reconstructActorChain(authenticationDetails.getActor()));
builder.claim(ContentGridClaimNames.ACT, reconstructActorChain(authenticationDetails.getActor()));
}

return builder
Expand Down Expand Up @@ -124,7 +125,7 @@ private Optional<Instant> findExpirationTime(Authentication authentication) {
private Map<String, Object> reconstructActorChain(Actor actor) {
var claims = new HashMap<>(actor.getClaims().getClaims());
if(actor.getParent() != null) {
claims.put("act", reconstructActorChain(actor.getParent()));
claims.put(ContentGridClaimNames.ACT, reconstructActorChain(actor.getParent()));
}
return claims;
}
Expand Down

0 comments on commit ed27711

Please sign in to comment.