Skip to content

Commit

Permalink
[WFCORE-5691] Allow setting timeout for token introspection
Browse files Browse the repository at this point in the history
  • Loading branch information
lvydra committed Jul 15, 2024
1 parent 5365664 commit d07f14e
Show file tree
Hide file tree
Showing 7 changed files with 501 additions and 4 deletions.
1 change: 1 addition & 0 deletions elytron/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,7 @@
<exclude>jacc-with-providers.xml</exclude>
<exclude>legacy*.xml</exclude>
<exclude>elytron-subsystem-community*.xml</exclude>
<exclude>elytron-subsystem-preview*.xml</exclude>
</excludes>
<systemId>src/main/resources/schema/wildfly-elytron_18_0.xsd</systemId>
</validationSet>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,9 @@ private void addMapperParser(PersistentResourceXMLDescription.PersistentResource

private void addRealmParser(PersistentResourceXMLDescription.PersistentResourceXMLBuilder builder) {
RealmParser realmParser = new RealmParser();
if (this.since(ElytronSubsystemSchema.VERSION_18_0)) {
if (this.since(ElytronSubsystemSchema.VERSION_18_0_PREVIEW)) {
builder.addChild(realmParser.realmParserPreview_18_0);
} else if (this.since(ElytronSubsystemSchema.VERSION_18_0)) {
builder.addChild(realmParser.realmParser_18);
} else if (this.since(ElytronSubsystemSchema.VERSION_16_0)) {
builder.addChild(realmParser.realmParser_16);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@ class RealmParser {
private final PersistentResourceXMLDescription tokenRealmParser = builder(PathElement.pathElement(ElytronDescriptionConstants.TOKEN_REALM))
.addAttributes(TokenRealmDefinition.ATTRIBUTES)
.build();
private final PersistentResourceXMLDescription tokenRealmParserPreview_18_0 = builder(PathElement.pathElement(ElytronDescriptionConstants.TOKEN_REALM))
.addAttributes(TokenRealmDefinition.ATTRIBUTES)
.build();
private final PersistentResourceXMLDescription cachingRealmParser = builder(PathElement.pathElement(ElytronDescriptionConstants.CACHING_REALM))
.addAttributes(CachingRealmDefinition.ATTRIBUTES)
.build();
Expand Down Expand Up @@ -272,6 +275,23 @@ class RealmParser {
.addChild(jaasRealmParser)
.build();

final PersistentResourceXMLDescription realmParserPreview_18_0 = decorator(ElytronDescriptionConstants.SECURITY_REALMS)
.addChild(aggregateRealmParser_8_0)
.addChild(customRealmParser)
.addChild(customModifiableRealmParser)
.addChild(identityRealmParser)
.addChild(jdbcRealmParser_14_0)
.addChild(keyStoreRealmParser)
.addChild(propertiesRealmParser_14_0)
.addChild(ldapRealmParser)
.addChild(filesystemRealmParser_16)
.addChild(tokenRealmParserPreview_18_0)
.addChild(cachingRealmParser)
.addChild(distributedRealmParser_18)
.addChild(failoverRealmParser)
.addChild(jaasRealmParser)
.build();

RealmParser() {

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,13 @@
import org.jboss.as.controller.StringListAttributeDefinition;
import org.jboss.as.controller.capability.RuntimeCapability;
import org.jboss.as.controller.operations.validation.EnumValidator;
import org.jboss.as.controller.operations.validation.IntRangeValidator;
import org.jboss.as.controller.operations.validation.StringLengthValidator;
import org.jboss.as.controller.parsing.ParseUtils;
import org.jboss.as.controller.registry.AttributeAccess;
import org.jboss.as.controller.registry.ManagementResourceRegistration;
import org.jboss.as.controller.registry.OperationEntry;
import org.jboss.as.version.Stability;
import org.jboss.dmr.ModelNode;
import org.jboss.dmr.ModelType;
import org.jboss.msc.service.ServiceBuilder;
Expand Down Expand Up @@ -148,6 +150,20 @@ static class JwtValidatorAttributes {
.setMinSize(1)
.build();

static final SimpleAttributeDefinition CONNECTION_TIMEOUT = new SimpleAttributeDefinitionBuilder(ElytronDescriptionConstants.CONNECTION_TIMEOUT, ModelType.INT, true)
.setStability(Stability.PREVIEW)
.setAllowExpression(true)
.setValidator(new IntRangeValidator(0))
.setRestartAllServices()
.build();

static final SimpleAttributeDefinition READ_TIMEOUT = new SimpleAttributeDefinitionBuilder(ElytronDescriptionConstants.READ_TIMEOUT, ModelType.INT, true)
.setStability(Stability.PREVIEW)
.setAllowExpression(true)
.setValidator(new IntRangeValidator(0))
.setRestartAllServices()
.build();

static final PropertiesAttributeDefinition KEY_MAP = new PropertiesAttributeDefinition.Builder(ElytronDescriptionConstants.KEY_MAP, true)
.setAllowExpression(true)
.setMinSize(1)
Expand All @@ -171,7 +187,7 @@ public void marshallSingleElement(AttributeDefinition attribute, ModelNode prope
.setRestartAllServices()
.build();

static final ObjectTypeAttributeDefinition JWT_VALIDATOR = new ObjectTypeAttributeDefinition.Builder(JWT, ISSUER, AUDIENCE, PUBLIC_KEY, KEY_STORE, CERTIFICATE, SSL_CONTEXT, HOSTNAME_VERIFICATION_POLICY, KEY_MAP)
static final ObjectTypeAttributeDefinition JWT_VALIDATOR = new ObjectTypeAttributeDefinition.Builder(JWT, ISSUER, AUDIENCE, PUBLIC_KEY, KEY_STORE, CERTIFICATE, SSL_CONTEXT, HOSTNAME_VERIFICATION_POLICY, KEY_MAP, CONNECTION_TIMEOUT, READ_TIMEOUT)
.setRequired(false)
.setRestartAllServices()
.build();
Expand All @@ -198,9 +214,23 @@ static class OAuth2IntrospectionValidatorAttributes {
.setFlags(AttributeAccess.Flag.RESTART_RESOURCE_SERVICES)
.build();

static final AttributeDefinition[] ATTRIBUTES = new AttributeDefinition[]{CLIENT_ID, CLIENT_SECRET, INTROSPECTION_URL, SSL_CONTEXT, HOSTNAME_VERIFICATION_POLICY};
static final SimpleAttributeDefinition CONNECTION_TIMEOUT = new SimpleAttributeDefinitionBuilder(ElytronDescriptionConstants.CONNECTION_TIMEOUT, ModelType.INT, true)
.setStability(Stability.PREVIEW)
.setAllowExpression(true)
.setValidator(new IntRangeValidator(0))
.setRestartAllServices()
.build();

static final SimpleAttributeDefinition READ_TIMEOUT = new SimpleAttributeDefinitionBuilder(ElytronDescriptionConstants.READ_TIMEOUT, ModelType.INT, true)
.setStability(Stability.PREVIEW)
.setAllowExpression(true)
.setValidator(new IntRangeValidator(0))
.setRestartAllServices()
.build();

static final AttributeDefinition[] ATTRIBUTES = new AttributeDefinition[]{CLIENT_ID, CLIENT_SECRET, INTROSPECTION_URL, SSL_CONTEXT, HOSTNAME_VERIFICATION_POLICY, CONNECTION_TIMEOUT, READ_TIMEOUT};

static final ObjectTypeAttributeDefinition OAUTH2_INTROSPECTION_VALIDATOR = new ObjectTypeAttributeDefinition.Builder(OAUTH2_INTROSPECTION, CLIENT_ID, CLIENT_SECRET, INTROSPECTION_URL, SSL_CONTEXT, HOSTNAME_VERIFICATION_POLICY)
static final ObjectTypeAttributeDefinition OAUTH2_INTROSPECTION_VALIDATOR = new ObjectTypeAttributeDefinition.Builder(OAUTH2_INTROSPECTION, CLIENT_ID, CLIENT_SECRET, INTROSPECTION_URL, SSL_CONTEXT, HOSTNAME_VERIFICATION_POLICY, CONNECTION_TIMEOUT, READ_TIMEOUT)
.setRequired(false)
.setRestartAllServices()
.build();
Expand Down Expand Up @@ -271,6 +301,8 @@ protected void performRuntime(OperationContext context, ModelNode operation, Mod
String sslContextRef = SSL_CONTEXT.resolveModelAttribute(context, jwtValidatorNode).asStringOrNull();
String hostNameVerificationPolicy = HOSTNAME_VERIFICATION_POLICY.resolveModelAttribute(context, jwtValidatorNode).asStringOrNull();
InjectedValue<SSLContext> sslContextInjector = new InjectedValue<>();
Integer connectionTimeout = JwtValidatorAttributes.CONNECTION_TIMEOUT.resolveModelAttribute(context, jwtValidatorNode).asIntOrNull();
Integer readTimeout = JwtValidatorAttributes.READ_TIMEOUT.resolveModelAttribute(context, jwtValidatorNode).asIntOrNull();
ModelNode keyMap = KEY_MAP.resolveModelAttribute(context, jwtValidatorNode);
Map<String, PublicKey> namedKeys = new LinkedHashMap<>();
if (keyMap.isDefined()) {
Expand Down Expand Up @@ -320,6 +352,12 @@ public SecurityRealm get() throws StartException {
if (namedKeys.size() > 0) {
jwtValidatorBuilder.publicKeys(namedKeys);
}
if (connectionTimeout != null) {
jwtValidatorBuilder.connectionTimeout(connectionTimeout);
}
if (readTimeout != null) {
jwtValidatorBuilder.readTimeout(readTimeout);
}
KeyStore keyStore = keyStoreInjector.getOptionalValue();

if (keyStore != null) {
Expand Down Expand Up @@ -375,6 +413,8 @@ public void dispose() {
String introspectionUrl = OAuth2IntrospectionValidatorAttributes.INTROSPECTION_URL.resolveModelAttribute(context, oAuth2IntrospectionNode).asString();
String sslContextRef = SSL_CONTEXT.resolveModelAttribute(context, oAuth2IntrospectionNode).asStringOrNull();
String hostNameVerificationPolicy = HOSTNAME_VERIFICATION_POLICY.resolveModelAttribute(context, oAuth2IntrospectionNode).asStringOrNull();
Integer connectionTimeout = OAuth2IntrospectionValidatorAttributes.CONNECTION_TIMEOUT.resolveModelAttribute(context, oAuth2IntrospectionNode).asIntOrNull();
Integer readTimeout = OAuth2IntrospectionValidatorAttributes.READ_TIMEOUT.resolveModelAttribute(context, oAuth2IntrospectionNode).asIntOrNull();
InjectedValue<SSLContext> sslContextInjector = new InjectedValue<>();

service = new TrivialService<>(new TrivialService.ValueSupplier<SecurityRealm>() {
Expand All @@ -389,6 +429,12 @@ public SecurityRealm get() throws StartException {
.tokenIntrospectionUrl(new URL(introspectionUrl))
.useSslContext(sslContextInjector.getOptionalValue())
.useSslHostnameVerifier(verifier);
if (connectionTimeout != null) {
builder.connectionTimeout(connectionTimeout);
}
if (readTimeout != null) {
builder.readTimeout(readTimeout);
}
return TokenSecurityRealm.builder().principalClaimName(principalClaimNode.asString())
.validator(builder.build())
.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -932,13 +932,17 @@ elytron.token-realm.jwt.key-map=A map of named public keys for token verificatio
elytron.token-realm.jwt.certificate=The name of the certificate with a public key to load from the key store.
elytron.token-realm.jwt.client-ssl-context=The SSL context to be used for fetching jku keys using HTTPS.
elytron.token-realm.jwt.host-name-verification-policy=A policy that defines how host names should be verified when using HTTPS.
elytron.token-realm.jwt.connection-timeout=The timeout for connecting in milliseconds. A non-zero value specifies the timeout when connecting to a resource. A timeout of zero is interpreted as an infinite timeout.
elytron.token-realm.jwt.read-timeout=The read timeout in milliseconds. A non-zero value specifies the timeout when reading from Input stream when a connection is established to a resource. A timeout of zero is interpreted as an infinite timeout.
# OAuth2 Introspection Validator Complex Attribute
elytron.token-realm.oauth2-introspection=A token validator to be used in conjunction with a token-based realm that handles OAuth2 Access Tokens and validates them using an endpoint compliant with OAuth2 Token Introspection specification(RFC-7662).
elytron.token-realm.oauth2-introspection.client-id=The identifier of the client on the OAuth2 Authorization Server.
elytron.token-realm.oauth2-introspection.client-secret=The secret of the client.
elytron.token-realm.oauth2-introspection.introspection-url=The URL of token introspection endpoint.
elytron.token-realm.oauth2-introspection.client-ssl-context=The SSL context to be used if the introspection endpoint is using HTTPS.
elytron.token-realm.oauth2-introspection.host-name-verification-policy=A policy that defines how host names should be verified when using HTTPS. Allowed values: 'ANY'.
elytron.token-realm.oauth2-introspection.connection-timeout=The timeout for connecting in milliseconds. A non-zero value specifies the timeout when connecting to a resource. A timeout of zero is interpreted as an infinite timeout.
elytron.token-realm.oauth2-introspection.read-timeout=The read timeout in milliseconds. A non-zero value specifies the timeout when reading from Input stream when a connection is established to a resource. A timeout of zero is interpreted as an infinite timeout.

# Identity management descriptions
elytron.modifiable-security-realm.add-identity=Add an identity to a security realm.
Expand Down
28 changes: 28 additions & 0 deletions elytron/src/main/resources/schema/wildfly-elytron_preview_18_0.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -2042,6 +2042,20 @@
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="connection-timeout" type="xs:integer" use="optional">
<xs:annotation>
<xs:documentation>
The timeout for connecting in milliseconds. A non-zero value specifies the timeout when connecting to a resource. A timeout of zero is interpreted as an infinite timeout.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="read-timeout" type="xs:integer" use="optional">
<xs:annotation>
<xs:documentation>
The read timeout in milliseconds. A non-zero value specifies the timeout when reading from Input stream when a connection is established to a resource. A timeout of zero is interpreted as an infinite timeout.
</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>

<xs:complexType name="oauth2IntrospectionTokenRealmValidatorType">
Expand Down Expand Up @@ -2085,6 +2099,20 @@
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="connection-timeout" type="xs:integer" use="optional">
<xs:annotation>
<xs:documentation>
The timeout for connecting in milliseconds. A non-zero value specifies the timeout when connecting to a resource. A timeout of zero is interpreted as an infinite timeout.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="read-timeout" type="xs:integer" use="optional">
<xs:annotation>
<xs:documentation>
The read timeout in milliseconds. A non-zero value specifies the timeout when reading from Input stream when a connection is established to a resource. A timeout of zero is interpreted as an infinite timeout.
</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>

<xs:complexType name="dirContextsType">
Expand Down
Loading

0 comments on commit d07f14e

Please sign in to comment.