Skip to content

Commit

Permalink
feat: add principal token to the application context (#123)
Browse files Browse the repository at this point in the history
* feat: add token parser service, add principal token to application context

* feat: add context principal token
  • Loading branch information
andrejpetras authored Jan 21, 2024
1 parent ae0e1e6 commit 09bfbfb
Show file tree
Hide file tree
Showing 22 changed files with 626 additions and 150 deletions.
9 changes: 8 additions & 1 deletion extensions/context/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,11 @@ Maven dependency
<groupId>org.tkit.quarkus.lib</groupId>
<artifactId>tkit-quarkus-context</artifactId>
</dependency>
```
```

Context object holds

* request ID
* principal name
* principal token
* business values
4 changes: 4 additions & 0 deletions extensions/context/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,9 @@
<artifactId>quarkus-arc</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.microprofile.jwt</groupId>
<artifactId>microprofile-jwt-auth-api</artifactId>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import java.util.*;

import org.eclipse.microprofile.jwt.JsonWebToken;

public class Context {

/**
Expand Down Expand Up @@ -36,14 +38,36 @@ public class Context {
*/
private final Stack<ApplicationError> errors;

Context(String correlationId, String businessContext, String principal, Map<String, String> meta, String tenantId) {
private final JsonWebToken principalToken;

Context(String correlationId, String businessContext, String principal, Map<String, String> meta, String tenantId,
JsonWebToken principalToken) {
this.correlationId = correlationId;
this.businessContext = businessContext;
this.meta = meta;
this.principal = principal;
this.businessParams = new HashSet<>();
this.errors = new Stack<>();
this.tenantId = tenantId;
this.principalToken = principalToken;
}

/**
* Gets the principal token
*
* @return the principal token
*/
public JsonWebToken getPrincipalToken() {
return principalToken;
}

/**
* Returns {@code true} if principal token is set in context.
*
* @return {@code true} if principal token is set in context.
*/
public boolean hasPrincipalToken() {
return principalToken != null;
}

/**
Expand All @@ -55,6 +79,15 @@ public String getPrincipal() {
return principal;
}

/**
* Returns {@code true} if principal is set in context.
*
* @return {@code true} if principal is set in context.
*/
public boolean hasPrincipal() {
return principal != null;
}

/**
* Gets business context.
*
Expand All @@ -73,6 +106,15 @@ public String getTenantId() {
return tenantId;
}

/**
* Returns {@code true} if tenant ID is set in context.
*
* @return {@code true} if tenant ID is set in context.
*/
public boolean hasTenantId() {
return tenantId != null;
}

/**
* Gets the correlation ID.
*
Expand Down Expand Up @@ -170,6 +212,8 @@ public static class ApplicationContextBuilder {

private final Map<String, String> meta = new HashMap<>();

private JsonWebToken principalToken;

public ApplicationContextBuilder correlationId(String correlationId) {
if (correlationId == null) {
return this;
Expand All @@ -178,6 +222,11 @@ public ApplicationContextBuilder correlationId(String correlationId) {
return this;
}

public ApplicationContextBuilder principalToken(JsonWebToken principalToken) {
this.principalToken = principalToken;
return this;
}

public ApplicationContextBuilder principal(String principal) {
this.principal = principal;
return this;
Expand All @@ -199,7 +248,7 @@ public ApplicationContextBuilder addMeta(String key, String value) {
}

public Context build() {
return new Context(correlationId, businessContext, principal, meta, tenantId);
return new Context(correlationId, businessContext, principal, meta, tenantId, principalToken);
}
}
}
}
65 changes: 50 additions & 15 deletions extensions/rest-context/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,27 +26,55 @@ tkit.rs.context.correlation-id.header-param-name=X-Correlation-ID
tkit.rs.context.business-context.enabled=false
# Business context header parameter
tkit.rs.context.business-context.header-param-name=business-context
# Add token to the context
tkit.rs.context.token-context=true
# Principal token is mandatory
tkit.rs.context.token-mandatory=false
# Principal is mandatory
tkit.rs.context.principal-mandatory=false
# Enable or disable token parser service
tkit.rs.context.token.enabled=true
# Make principal token required
tkit.rs.context.token.required=true
# Token type name for parsing token
tkit.rs.context.token.type=principal-token
# Verify the token or skip token verification
tkit.rs.context.token.verify=false
# Enable or disable the public key location for the verified token.
tkit.rs.context.token.public-key-location.enabled=false
# Token public key location suffix. This property is use only if public-key-location.enabled set to true.
tkit.rs.context.token.public-key-location.suffix=/protocol/openid-connect/certs
# Token header parameter
tkit.rs.context.token.header-param=apm-principal-token

```

Runtime principal configuration.
Runtime principal name configuration.

```properties
# Enable or disable principal name for the context
tkit.rs.context.principal.enabled=true
tkit.rs.context.principal.name.enabled=true
# Enable or disable custom principal service
tkit.rs.context.principal.name.custom-service-enabled=false
# Enabled or disable `SecurityContext` principal name resolver
tkit.rs.context.principal.security-context.enabled=false
tkit.rs.context.principal.name.security-context.enabled=false
# Optional default principal name, default null
tkit.rs.context.principal.name.default=
# Read name from token
tkit.rs.context.principal.name.token-enabled=true
# Token claim name for principal name
tkit.rs.context.principal.name.token-claim-name=sub
# Use header parameter as principal name
tkit.rs.context.principal.name.header-param-enabled=false
# Principal name header for header-param-enabled
tkit.rs.context.principal.name.header-param-name=x-principal-id
```

Runtime principal token configuration.

```properties
# Enabled or disable token resolver for principal name
tkit.rs.context.principal.token.enabled=true
# Verify the token or skip token verification
tkit.rs.context.principal.token.verify=false
# Enable or disable the public key location for the verified token.
tkit.rs.context.principal.token.public-key-location.enabled=false
# Token public key location suffix. This property is use only if public-key-location.enabled set to true.
tkit.rs.context.principal.token.public-key-location.suffix=/protocol/openid-connect/certs
# Token header parameter
tkit.rs.context.principal.token.token-header-param=apm-principal-token
# Token claim name for principal name
tkit.rs.context.principal.token.claim-name=sub
```

Runtime tenant configuration.
Expand All @@ -56,10 +84,19 @@ Runtime tenant configuration.
tkit.rs.context.tenant-id.enabled=false
# default tenant ID
tkit.rs.context.tenant-id.default=default
# Use token claim to setup tenant ID
tkit.rs.context.tenant-id.token.enabled=false
# Token claim parameter for tenant ID
tkit.rs.context.tenant-id.token.claim-tenant-param=tenantId
# enable or disable tenant ID from header parameter
tkit.rs.context.tenant-id.header-param-enabled=false
# header parameter of the tenant ID
tkit.rs.context.tenant-id.header-param-name=tenant-id
```

Tenant mock service for testing

```properties
# enable or disable tenant ID mock service
tkit.rs.context.tenant-id.mock.enabled=false
# default tenant ID
Expand All @@ -68,8 +105,6 @@ tkit.rs.context.tenant-id.mock.default-tenant=default
tkit.rs.context.tenant-id.mock.data.<org-id>=<tenant-id>
# token claim parameter of organization ID
tkit.rs.context.tenant-id.mock.claim-org-id=orgId
# token header parameter
tkit.rs.context.tenant-id.mock.token-header-param=apm-principal-token
```

Priority of the tenant ID resolver:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.tkit.quarkus.rs.context;

public class PrincipalRequiredException extends RestContextException {

public PrincipalRequiredException() {
super(ErrorKeys.PRINCIPAL_REQUIRED, "Principal is required");
}

public enum ErrorKeys {

PRINCIPAL_REQUIRED;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.tkit.quarkus.rs.context;

public class PrincipalTokenRequiredException extends RestContextException {

public PrincipalTokenRequiredException() {
super(ErrorKeys.PRINCIPAL_TOKEN_REQUIRED, "Principal token is required");
}

public enum ErrorKeys {

PRINCIPAL_TOKEN_REQUIRED;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,21 @@ public interface RestContextConfig {
@WithName("business-context")
RestContextBusinessConfig businessContext();

@WithName("token")
TokenConfig token();

@WithName("token-context")
@WithDefault("true")
boolean tokenContext();

@WithName("token-mandatory")
@WithDefault("false")
boolean tokenMandatory();

@WithName("principal-mandatory")
@WithDefault("false")
boolean principalMandatory();

interface RestContextCorrelationIdConfig {

@WithName("enabled")
Expand All @@ -47,4 +62,32 @@ interface RestContextBusinessConfig {

}

interface TokenConfig {

@WithName("enabled")
@WithDefault("true")
boolean enabled();

@WithName("type")
@WithDefault("principal-token")
String type();

@WithName("verify")
@WithDefault("false")
boolean verify();

@WithName("public-key-location.enabled")
@WithDefault("false")
boolean issuerEnabled();

@WithName("public-key-location.suffix")
@WithDefault("/protocol/openid-connect/certs")
String issuerSuffix();

@WithName("header-param")
@WithDefault("apm-principal-token")
String tokenHeaderParam();

}

}
Loading

0 comments on commit 09bfbfb

Please sign in to comment.