diff --git a/elytron/pom.xml b/elytron/pom.xml
index e506f39254d..e1858af4213 100644
--- a/elytron/pom.xml
+++ b/elytron/pom.xml
@@ -414,6 +414,7 @@
jacc-with-providers.xml
legacy*.xml
elytron-subsystem-community*.xml
+ elytron-subsystem-preview*.xml
src/main/resources/schema/wildfly-elytron_18_0.xsd
diff --git a/elytron/src/main/java/org/wildfly/extension/elytron/ElytronSubsystemSchema.java b/elytron/src/main/java/org/wildfly/extension/elytron/ElytronSubsystemSchema.java
index 14f6e99baa4..79b3ccc435b 100644
--- a/elytron/src/main/java/org/wildfly/extension/elytron/ElytronSubsystemSchema.java
+++ b/elytron/src/main/java/org/wildfly/extension/elytron/ElytronSubsystemSchema.java
@@ -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);
diff --git a/elytron/src/main/java/org/wildfly/extension/elytron/RealmParser.java b/elytron/src/main/java/org/wildfly/extension/elytron/RealmParser.java
index 4a350c30a4b..cb1b1350e9d 100644
--- a/elytron/src/main/java/org/wildfly/extension/elytron/RealmParser.java
+++ b/elytron/src/main/java/org/wildfly/extension/elytron/RealmParser.java
@@ -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();
@@ -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() {
}
diff --git a/elytron/src/main/java/org/wildfly/extension/elytron/TokenRealmDefinition.java b/elytron/src/main/java/org/wildfly/extension/elytron/TokenRealmDefinition.java
index d7b9293853e..f25afc4e979 100644
--- a/elytron/src/main/java/org/wildfly/extension/elytron/TokenRealmDefinition.java
+++ b/elytron/src/main/java/org/wildfly/extension/elytron/TokenRealmDefinition.java
@@ -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;
@@ -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)
@@ -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();
@@ -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();
@@ -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 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 namedKeys = new LinkedHashMap<>();
if (keyMap.isDefined()) {
@@ -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) {
@@ -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 sslContextInjector = new InjectedValue<>();
service = new TrivialService<>(new TrivialService.ValueSupplier() {
@@ -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();
diff --git a/elytron/src/main/resources/org/wildfly/extension/elytron/LocalDescriptions.properties b/elytron/src/main/resources/org/wildfly/extension/elytron/LocalDescriptions.properties
index 36d6297c7e5..c1a10913818 100644
--- a/elytron/src/main/resources/org/wildfly/extension/elytron/LocalDescriptions.properties
+++ b/elytron/src/main/resources/org/wildfly/extension/elytron/LocalDescriptions.properties
@@ -932,6 +932,8 @@ 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.
@@ -939,6 +941,8 @@ 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.
diff --git a/elytron/src/main/resources/schema/wildfly-elytron_preview_18_0.xsd b/elytron/src/main/resources/schema/wildfly-elytron_preview_18_0.xsd
index 10545bd6ff8..045aec6a8e3 100644
--- a/elytron/src/main/resources/schema/wildfly-elytron_preview_18_0.xsd
+++ b/elytron/src/main/resources/schema/wildfly-elytron_preview_18_0.xsd
@@ -2042,6 +2042,20 @@
+
+
+
+ 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.
+
+
+
+
+
+
+ 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.
+
+
+
@@ -2085,6 +2099,20 @@
+
+
+
+ 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.
+
+
+
+
+
+
+ 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.
+
+
+
diff --git a/elytron/src/test/resources/org/wildfly/extension/elytron/elytron-subsystem-preview-18.0.xml b/elytron/src/test/resources/org/wildfly/extension/elytron/elytron-subsystem-preview-18.0.xml
new file mode 100644
index 00000000000..d84d6ed2912
--- /dev/null
+++ b/elytron/src/test/resources/org/wildfly/extension/elytron/elytron-subsystem-preview-18.0.xml
@@ -0,0 +1,396 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+