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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +