From 9cd89d433096ab9ec502dee02b6e6bb53a9a12bc Mon Sep 17 00:00:00 2001 From: Cameron Rodriguez Date: Mon, 3 Oct 2022 18:28:13 -0400 Subject: [PATCH] [WFCORE-5279] Restored Service API, add test resources [WFCORE-5279] Restored original Service API [WFCORE-5279] Add missing test resources, fix XML marshalling --- .../tls/subsystem/AcmeAccountService.java | 24 +- .../subsystem/AggregateComponentService.java | 5 +- ...CertificateAuthorityAccountDefinition.java | 20 +- .../CertificateAuthorityDefinition.java | 23 +- .../CredentialStoreResourceDefinition.java | 9 +- .../subsystem/DefaultSSLContextService.java | 9 +- .../tls/subsystem/ElytronDoohickey.java | 16 +- .../ElytronTlsSubsystemDefinition.java | 64 +- .../ElytronTlsSubsystemParser_1_0.java | 12 +- .../KeyManagerAttributeDefinition.java | 27 - .../tls/subsystem/KeyStoreDefinition.java | 16 +- .../elytron/tls/subsystem/KeyStoreParser.java | 10 +- .../tls/subsystem/KeyStoreService.java | 36 +- .../elytron/tls/subsystem/ManagerParsers.java | 4 +- .../subsystem/ModifiableKeyStoreService.java | 4 +- .../tls/subsystem/ProviderDefinitions.java | 11 +- .../ProviderRegistrationService.java | 12 +- .../tls/subsystem/SSLContextDefinitions.java | 815 +++++++++--------- .../SecretKeyCredentialStoreDefinition.java | 12 +- .../SecurityPropertiesWriteHandler.java | 6 +- .../subsystem/SecurityPropertyService.java | 9 +- .../elytron/tls/subsystem/TrivialService.java | 8 +- .../tls/subsystem/TrustManagerBuilder.java | 51 -- .../elytron/tls/subsystem/Validators.java | 31 + .../subsystem/_private/ElytronTLSLogger.java | 22 +- .../CertificateAuthoritiesTestCase.java | 10 +- .../tls/subsystem/KeyStoresTestCase.java | 61 +- .../elytron/tls/subsystem/account.keystore | Bin 0 -> 31169 bytes .../tls/subsystem/test-original.keystore | Bin 0 -> 2811 bytes .../elytron/tls/subsystem/tls-ibm.xml | 16 +- .../tls/subsystem/tls-oracle13plus.xml | 16 +- .../elytron/tls/subsystem/tls-sun.xml | 16 +- .../extension/elytron/tls/subsystem/tls.xml | 42 +- 33 files changed, 710 insertions(+), 707 deletions(-) delete mode 100644 subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/KeyManagerAttributeDefinition.java delete mode 100644 subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/TrustManagerBuilder.java create mode 100644 subsystem/src/test/resources/org/wildfly/extension/elytron/tls/subsystem/account.keystore create mode 100644 subsystem/src/test/resources/org/wildfly/extension/elytron/tls/subsystem/test-original.keystore diff --git a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/AcmeAccountService.java b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/AcmeAccountService.java index c5ef158..d686c50 100644 --- a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/AcmeAccountService.java +++ b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/AcmeAccountService.java @@ -25,15 +25,16 @@ import java.security.PrivateKey; import java.security.cert.X509Certificate; import java.util.List; -import java.util.function.Supplier; import org.jboss.as.controller.OperationContext; import org.jboss.as.controller.OperationFailedException; -import org.jboss.msc.Service; +import org.jboss.msc.inject.Injector; +import org.jboss.msc.service.Service; import org.jboss.msc.service.ServiceRegistry; import org.jboss.msc.service.StartContext; import org.jboss.msc.service.StartException; import org.jboss.msc.service.StopContext; +import org.jboss.msc.value.InjectedValue; import org.wildfly.common.function.ExceptionSupplier; import org.wildfly.security.credential.source.CredentialSource; import org.wildfly.security.x500.cert.acme.AcmeAccount; @@ -44,10 +45,10 @@ * * @author Farah Juma */ -class AcmeAccountService implements Service { +class AcmeAccountService implements Service { - private Supplier keyStoreSupplier; - private ExceptionSupplier credentialSourceSupplier; + private final InjectedValue keyStoreInjector = new InjectedValue<>(); + private final InjectedValue> credentialSourceSupplierInjector = new InjectedValue<>(); private final String certificateAuthorityName; private final List contactUrlsList; private final String alias; @@ -67,7 +68,7 @@ public void start(StartContext startContext) throws StartException { final ServiceRegistry serviceRegistry = startContext.getController().getServiceContainer(); final ModifiableKeyStoreService keyStoreService = CertificateAuthorityAccountDefinition.getModifiableKeyStoreService(serviceRegistry, keyStoreName); char[] keyPassword = resolveKeyPassword((KeyStoreService) keyStoreService); - KeyStore keyStore = keyStoreSupplier.get(); + KeyStore keyStore = keyStoreInjector.getValue(); CertificateAuthority certificateAuthority; if (certificateAuthorityName.equalsIgnoreCase(CertificateAuthority.LETS_ENCRYPT.getName())) { certificateAuthority = CertificateAuthority.LETS_ENCRYPT; @@ -112,21 +113,22 @@ public void stop(StopContext stopContext) { acmeAccount = null; } + @Override public AcmeAccount getValue() throws IllegalStateException, IllegalArgumentException { return acmeAccount; } - void setKeyStoreSupplier(Supplier keyStoreSupplier) { - this.keyStoreSupplier = keyStoreSupplier; + Injector getKeyStoreInjector() { + return keyStoreInjector; } - void setCredentialSourceSupplier(ExceptionSupplier credentialSourceSupplier) { - this.credentialSourceSupplier = credentialSourceSupplier; + Injector> getCredentialSourceSupplierInjector() { + return credentialSourceSupplierInjector; } char[] resolveKeyPassword(KeyStoreService keyStoreService) throws RuntimeException { try { - return keyStoreService.resolveKeyPassword(credentialSourceSupplier); + return keyStoreService.resolveKeyPassword(credentialSourceSupplierInjector.getOptionalValue()); } catch (Exception e) { throw new RuntimeException(e); } diff --git a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/AggregateComponentService.java b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/AggregateComponentService.java index 4277865..a72026b 100644 --- a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/AggregateComponentService.java +++ b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/AggregateComponentService.java @@ -25,6 +25,7 @@ import org.jboss.msc.inject.Injector; import org.jboss.msc.service.Service; import org.jboss.msc.service.StartContext; +import org.jboss.msc.service.StartException; import org.jboss.msc.service.StopContext; import org.jboss.msc.value.InjectedValue; @@ -38,7 +39,7 @@ class AggregateComponentService implements Service { private final Class aggregationType; private final Function aggregator; - private List> injections = new ArrayList<>(); + private List> injections = new ArrayList>(); private T aggregation; @@ -52,7 +53,7 @@ class AggregateComponentService implements Service { */ @SuppressWarnings("unchecked") @Override - public void start(StartContext context) { + public void start(StartContext context) throws StartException { ArrayList toAggregate = new ArrayList<>(injections.size()); for (InjectedValue current : injections) { toAggregate.add(current.getValue()); diff --git a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/CertificateAuthorityAccountDefinition.java b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/CertificateAuthorityAccountDefinition.java index 7606d3e..2bdb468 100644 --- a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/CertificateAuthorityAccountDefinition.java +++ b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/CertificateAuthorityAccountDefinition.java @@ -27,11 +27,11 @@ import static org.wildfly.extension.elytron.tls.subsystem.Capabilities.CERTIFICATE_AUTHORITY_RUNTIME_CAPABILITY; import static org.wildfly.extension.elytron.tls.subsystem.Capabilities.KEY_STORE_CAPABILITY; import static org.wildfly.extension.elytron.tls.subsystem.Capabilities.KEY_STORE_RUNTIME_CAPABILITY; +import static org.wildfly.extension.elytron.tls.subsystem.ElytronTlsExtension.getRequiredService; +import static org.wildfly.extension.elytron.tls.subsystem.ElytronTlsExtension.isServerOrHostController; import static org.wildfly.extension.elytron.tls.subsystem.ElytronTlsSubsystemDefinition.commonRequirements; import static org.wildfly.extension.elytron.tls.subsystem.FileAttributeDefinitions.PATH; import static org.wildfly.extension.elytron.tls.subsystem.FileAttributeDefinitions.RELATIVE_TO; -import static org.wildfly.extension.elytron.tls.subsystem.ElytronTlsExtension.getRequiredService; -import static org.wildfly.extension.elytron.tls.subsystem.ElytronTlsExtension.isServerOrHostController; import static org.wildfly.extension.elytron.tls.subsystem._private.ElytronTLSLogger.LOGGER; import java.security.KeyStore; @@ -60,7 +60,6 @@ import org.jboss.as.controller.registry.OperationEntry; import org.jboss.as.controller.registry.Resource; import org.jboss.as.controller.security.CredentialReference; -import org.jboss.as.domain.http.server.ConsoleAvailabilityService.LogAdminConsole; import org.jboss.dmr.ModelNode; import org.jboss.dmr.ModelType; import org.jboss.msc.service.ServiceBuilder; @@ -228,19 +227,16 @@ protected void performRuntime(OperationContext context, ModelNode operation, Res ServiceTarget serviceTarget = context.getServiceTarget(); RuntimeCapability certificateAuthorityAccountRuntimeCapability = CERTIFICATE_AUTHORITY_ACCOUNT_RUNTIME_CAPABILITY.fromBaseCapability(context.getCurrentAddressValue()); ServiceName acmeAccountServiceName = certificateAuthorityAccountRuntimeCapability.getCapabilityServiceName(AcmeAccount.class); - ServiceBuilder acmeAccountServiceBuilder = (ServiceBuilder) serviceTarget.addService(acmeAccountServiceName).setInitialMode(ServiceController.Mode.ACTIVE); - - acmeAccountService.setCredentialSourceSupplier(credentialSourceSupplier); + ServiceBuilder acmeAccountServiceBuilder = serviceTarget.addService(acmeAccountServiceName, acmeAccountService).setInitialMode(ServiceController.Mode.ACTIVE); + acmeAccountService.getCredentialSourceSupplierInjector().inject(credentialSourceSupplier); - String keyStoreCapabilityName = RuntimeCapability.buildDynamicCapabilityName(KEY_STORE_CAPABILITY, finalKeyStoreName); - ServiceName keyStoreServiceName = context.getCapabilityServiceName(keyStoreCapabilityName, KeyStore.class); - acmeAccountService.setKeyStoreSupplier(acmeAccountServiceBuilder.requires(keyStoreServiceName)); - + String keyStoreCapabilityName = RuntimeCapability.buildDynamicCapabilityName(KEY_STORE_CAPABILITY, keyStoreName); + acmeAccountServiceBuilder.addDependency(context.getCapabilityServiceName(keyStoreCapabilityName, KeyStore.class), KeyStore.class, acmeAccountService.getKeyStoreInjector()); if (certificateAuthorityName.equalsIgnoreCase(CertificateAuthority.LETS_ENCRYPT.getName())) { - commonRequirements(acmeAccountServiceBuilder, true, true).install(); + commonRequirements(acmeAccountServiceBuilder).install(); } else { acmeAccountServiceBuilder.requires(CERTIFICATE_AUTHORITY_RUNTIME_CAPABILITY.getCapabilityServiceName(certificateAuthorityName)); - commonRequirements(acmeAccountServiceBuilder, true, true).install(); + commonRequirements(acmeAccountServiceBuilder).install(); } } diff --git a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/CertificateAuthorityDefinition.java b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/CertificateAuthorityDefinition.java index 704c9c6..5c20fcf 100644 --- a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/CertificateAuthorityDefinition.java +++ b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/CertificateAuthorityDefinition.java @@ -18,6 +18,14 @@ package org.wildfly.extension.elytron.tls.subsystem; +import static org.wildfly.extension.elytron.tls.subsystem.Capabilities.CERTIFICATE_AUTHORITY_RUNTIME_CAPABILITY; +import static org.wildfly.extension.elytron.tls.subsystem.ElytronTlsExtension.getRequiredService; +import static org.wildfly.extension.elytron.tls.subsystem.ElytronTlsSubsystemDefinition.commonRequirements; +import static org.wildfly.extension.elytron.tls.subsystem._private.ElytronTLSLogger.LOGGER; + +import java.net.MalformedURLException; +import java.net.URL; + import org.jboss.as.controller.AbstractAddStepHandler; import org.jboss.as.controller.AttributeDefinition; import org.jboss.as.controller.OperationContext; @@ -34,21 +42,14 @@ import org.jboss.as.controller.registry.OperationEntry; import org.jboss.dmr.ModelNode; import org.jboss.dmr.ModelType; +import org.jboss.msc.service.Service; import org.jboss.msc.service.ServiceBuilder; import org.jboss.msc.service.ServiceController; +import org.jboss.msc.service.ServiceController.Mode; import org.jboss.msc.service.ServiceName; import org.jboss.msc.service.ServiceRegistry; import org.jboss.msc.service.ServiceTarget; import org.wildfly.security.x500.cert.acme.CertificateAuthority; -import org.jboss.msc.service.ServiceController.Mode; - -import java.net.MalformedURLException; -import java.net.URL; - -import static org.wildfly.extension.elytron.tls.subsystem.Capabilities.CERTIFICATE_AUTHORITY_RUNTIME_CAPABILITY; -import static org.wildfly.extension.elytron.tls.subsystem.ElytronTlsSubsystemDefinition.commonRequirements; -import static org.wildfly.extension.elytron.tls.subsystem.ElytronTlsExtension.getRequiredService; -import static org.wildfly.extension.elytron.tls.subsystem._private.ElytronTLSLogger.LOGGER; /** * A {@link ResourceDefinition} for a single certificate authority. @@ -124,7 +125,7 @@ protected void performRuntime(OperationContext context, ModelNode operation, Mod if (certificateAuthorityName.equalsIgnoreCase(CertificateAuthority.LETS_ENCRYPT.getName())) { throw LOGGER.letsEncryptNameNotAllowed(); } - commonRequirements(installService(context, model), true, true).setInitialMode(Mode.ACTIVE).install(); + commonRequirements(installService(context, model)).setInitialMode(Mode.ACTIVE).install(); } ServiceBuilder installService(OperationContext context, ModelNode model) { @@ -143,7 +144,7 @@ protected TrivialService.ValueSupplier getValueSupplier(Op } } - static org.jboss.msc.service.Service getCertificateAuthorityService(ServiceRegistry serviceRegistry, String certificateAuthorityName) { + static Service getCertificateAuthorityService(ServiceRegistry serviceRegistry, String certificateAuthorityName) { RuntimeCapability runtimeCapability = CERTIFICATE_AUTHORITY_RUNTIME_CAPABILITY.fromBaseCapability(certificateAuthorityName); ServiceName serviceName = runtimeCapability.getCapabilityServiceName(); ServiceController serviceContainer = getRequiredService(serviceRegistry, serviceName, CertificateAuthority.class); diff --git a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/CredentialStoreResourceDefinition.java b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/CredentialStoreResourceDefinition.java index 9202be7..bb403a6 100644 --- a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/CredentialStoreResourceDefinition.java +++ b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/CredentialStoreResourceDefinition.java @@ -18,7 +18,6 @@ package org.wildfly.extension.elytron.tls.subsystem; -import static org.jboss.as.controller.AbstractControllerService.PATH_MANAGER_CAPABILITY; import static org.jboss.as.controller.security.CredentialReference.getCredentialSource; import static org.jboss.as.controller.security.CredentialReference.handleCredentialReferenceUpdate; import static org.jboss.as.controller.security.CredentialReference.rollbackCredentialStoreUpdate; @@ -70,6 +69,7 @@ import org.jboss.as.controller.registry.OperationEntry; import org.jboss.as.controller.registry.Resource; import org.jboss.as.controller.security.CredentialReference; +import org.jboss.as.controller.services.path.PathManagerService; import org.jboss.dmr.ModelNode; import org.jboss.dmr.ModelType; import org.jboss.msc.service.ServiceName; @@ -455,11 +455,12 @@ protected void resolveRuntime(ModelNode model, OperationContext context) throws protected ExceptionSupplier prepareServiceSupplier(OperationContext context, CapabilityServiceBuilder serviceBuilder) throws OperationFailedException { + final Supplier pathManager; if (relativeTo != null) { - pathManagerSupplier = serviceBuilder.requires(PATH_MANAGER_CAPABILITY.getCapabilityServiceName()); + pathManager = serviceBuilder.requires(PathManagerService.SERVICE_NAME); serviceBuilder.requires(pathName(relativeTo)); } else { - pathManagerSupplier = null; + pathManager = null; } final Supplier providerSupplier; @@ -498,7 +499,7 @@ public CredentialStore get() throws StartException { PathResolver pathResolver = pathResolver(); pathResolver.path(location); if (relativeTo != null) { - pathResolver.relativeTo(relativeTo, pathManagerSupplier.get()); + pathResolver.relativeTo(relativeTo, pathManager.get()); } File resolved = pathResolver.resolve(); pathResolver.clear(); diff --git a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/DefaultSSLContextService.java b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/DefaultSSLContextService.java index e404c8a..b86e8d0 100644 --- a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/DefaultSSLContextService.java +++ b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/DefaultSSLContextService.java @@ -16,8 +16,11 @@ package org.wildfly.extension.elytron.tls.subsystem; +import static org.wildfly.extension.elytron.tls.subsystem.ElytronTlsSubsystemDefinition.RESTORE_DEFAULT_SSL_CONTEXT; import static org.wildfly.extension.elytron.tls.subsystem.SecurityActions.doPrivileged; +import static org.wildfly.extension.elytron.tls.subsystem._private.ElytronTLSLogger.LOGGER; +import java.security.NoSuchAlgorithmException; import java.security.PrivilegedAction; import java.util.function.Consumer; import java.util.function.Supplier; @@ -30,7 +33,6 @@ import org.jboss.msc.service.StartException; import org.jboss.msc.service.StopContext; - /** * A simple {@link Service} to take an {@link SSLContext} and register it as the process wide default. * @@ -40,7 +42,7 @@ class DefaultSSLContextService implements Service { static final ServiceName SERVICE_NAME = ElytronTlsExtension.BASE_SERVICE_NAME.append(Constants.SSL_CONTEXT_REGISTRATION); - //private static final boolean RESTORE_SSL_CONTEXT = doPrivileged((PrivilegedAction) () -> Boolean.getBoolean(RESTORE_DEFAULT_SSL_CONTEXT)); + private static final boolean RESTORE_SSL_CONTEXT = doPrivileged((PrivilegedAction) () -> Boolean.getBoolean(RESTORE_DEFAULT_SSL_CONTEXT)); private final Supplier defaultSSLContextSupplier; private final Consumer valueConsumer; @@ -64,7 +66,6 @@ public void start(StartContext context) throws StartException { public void stop(StopContext context) { // We can't set the default back to 'null' as that would cause a NullPointerException. // For the purpose of testing we may want to restore the default. - /* if (RESTORE_SSL_CONTEXT) { try { final SSLContext defaultSSLContext = SSLContext.getInstance("Default"); @@ -75,7 +76,7 @@ public void stop(StopContext context) { } catch (NoSuchAlgorithmException e) { LOGGER.debug(e); } - }*/ + } } } diff --git a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/ElytronDoohickey.java b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/ElytronDoohickey.java index 9d59a1a..99522c9 100644 --- a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/ElytronDoohickey.java +++ b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/ElytronDoohickey.java @@ -26,7 +26,6 @@ import java.util.Iterator; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; -import java.util.function.Supplier; import org.jboss.as.controller.CapabilityServiceBuilder; import org.jboss.as.controller.OperationContext; @@ -48,9 +47,12 @@ */ abstract class ElytronDoohickey implements ExceptionFunction { - private static final Supplier> CALL_STACK_SUPPLIER = ArrayDeque::new; - - private static final ThreadLocal> CALL_STACK = ThreadLocal.withInitial(CALL_STACK_SUPPLIER); + private static final ThreadLocal> CALL_STACK = new ThreadLocal() { + @Override + protected Deque initialValue() { + return new ArrayDeque<>(); + } + }; /* * As each Thread tracks the addresses of the relevent resources we could likely implement some form of @@ -63,7 +65,6 @@ abstract class ElytronDoohickey implements ExceptionFunction serviceValueSupplier; - protected volatile Supplier pathManagerSupplier; private volatile T value; @@ -164,9 +165,8 @@ protected File resolveRelativeToImmediately(String path, String relativeTo, Oper PathResolver pathResolver = pathResolver(); pathResolver.path(path); if (relativeTo != null) { -// PathManager pathManager = (PathManager) foreignContext.getServiceRegistry(false) -// .getRequiredService(PATH_MANAGER_CAPABILITY.getCapabilityServiceName()).getValue(); - PathManager pathManager = pathManagerSupplier.get(); + PathManager pathManager = (PathManager) foreignContext.getServiceRegistry(false) + .getRequiredService(PathManagerService.SERVICE_NAME).getValue(); pathResolver.relativeTo(relativeTo, pathManager); } File resolved = pathResolver.resolve(); diff --git a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/ElytronTlsSubsystemDefinition.java b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/ElytronTlsSubsystemDefinition.java index 943bb8c..12bac9f 100644 --- a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/ElytronTlsSubsystemDefinition.java +++ b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/ElytronTlsSubsystemDefinition.java @@ -17,11 +17,10 @@ package org.wildfly.extension.elytron.tls.subsystem; import static org.jboss.as.controller.OperationContext.Stage.RUNTIME; -import static org.jboss.as.server.deployment.Phase.DEPENDENCIES; -import static org.jboss.as.server.deployment.Phase.STRUCTURE; -import static org.jboss.as.server.deployment.Phase.STRUCTURE_ELYTRON_EXPRESSION_RESOLVER; import static org.jboss.as.server.deployment.Phase.CONFIGURE_DEFAULT_SSL_CONTEXT; import static org.jboss.as.server.deployment.Phase.CONFIGURE_MODULE; +import static org.jboss.as.server.deployment.Phase.DEPENDENCIES; +import static org.jboss.as.server.deployment.Phase.STRUCTURE; import static org.wildfly.extension.elytron.tls.subsystem.Capabilities.ELYTRON_TLS_RUNTIME_CAPABILITY; import static org.wildfly.extension.elytron.tls.subsystem.Capabilities.PROVIDERS_CAPABILITY; import static org.wildfly.extension.elytron.tls.subsystem.Capabilities.SSL_CONTEXT_CAPABILITY; @@ -44,6 +43,7 @@ import org.jboss.as.controller.AttributeMarshaller; import org.jboss.as.controller.AttributeParser; import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationContext.AttachmentKey; import org.jboss.as.controller.OperationFailedException; import org.jboss.as.controller.OperationStepHandler; import org.jboss.as.controller.PersistentResourceDefinition; @@ -61,7 +61,7 @@ import org.jboss.as.server.DeploymentProcessorTarget; import org.jboss.dmr.ModelNode; import org.jboss.dmr.ModelType; -import org.jboss.msc.Service; +import org.jboss.msc.service.Service; import org.jboss.msc.service.ServiceBuilder; import org.jboss.msc.service.ServiceController; import org.jboss.msc.service.ServiceController.Mode; @@ -71,17 +71,27 @@ import org.wildfly.extension.elytron.tls.subsystem._private.ElytronTLSLogger; import org.wildfly.extension.elytron.tls.subsystem.deployment.DependencyProcessor; import org.wildfly.extension.elytron.tls.subsystem.expression.DeploymentExpressionResolverProcessor; +import org.wildfly.security.Version; /** + * Top level {@link PersistentResourceDefinition} for the Elytron TLS subsystem. + * * @author Kabir Khan * @author Cameron Rodriguez */ public class ElytronTlsSubsystemDefinition extends PersistentResourceDefinition { + /** + * System property which if set to {@code true} will cause the JVM wide default {@link SSLContext} to be restored when the subsystem shuts down. + * + * This property is only for use by test cases. + */ + static final String RESTORE_DEFAULT_SSL_CONTEXT = ElytronTlsSubsystemDefinition.class.getPackage().getName() + ".restore-default-ssl-context"; + static final PropertiesAttributeDefinition SECURITY_PROPERTIES = new PropertiesAttributeDefinition.Builder(Constants.SECURITY_PROPERTIES, true) .build(); - private static final OperationContext.AttachmentKey SECURITY_PROPERTY_SERVICE_KEY = OperationContext.AttachmentKey.create(SecurityPropertyService.class); + private static final AttachmentKey SECURITY_PROPERTY_SERVICE_KEY = AttachmentKey.create(SecurityPropertyService.class); static final SimpleAttributeDefinition DEFAULT_SSL_CONTEXT = new SimpleAttributeDefinitionBuilder(Constants.DEFAULT_SSL_CONTEXT, ModelType.STRING, true) @@ -183,9 +193,11 @@ protected void revertUpdateToRuntime(OperationContext context, ModelNode operati @Override public void registerAdditionalRuntimePackages(ManagementResourceRegistration resourceRegistration) { - super.registerAdditionalRuntimePackages(resourceRegistration); } + static ServiceBuilder commonRequirements(ServiceBuilder serviceBuilder) { + return commonRequirements(serviceBuilder, true, true); + } static ServiceBuilder commonRequirements(ServiceBuilder serviceBuilder, boolean dependOnProperties, boolean dependOnProviderRegistration) { if (dependOnProperties) serviceBuilder.requires(SecurityPropertyService.SERVICE_NAME); @@ -193,11 +205,10 @@ static ServiceBuilder commonRequirements(ServiceBuilder serviceBuilder return serviceBuilder; } - private static void installService(ServiceName serviceName, Service service, ServiceTarget serviceTarget) { - serviceTarget.addService(serviceName) - .setInstance(service) - .setInitialMode(Mode.ACTIVE) - .install(); + private static void installService(ServiceName serviceName, Service service, ServiceTarget serviceTarget) { + serviceTarget.addService(serviceName, service) + .setInitialMode(Mode.ACTIVE) + .install(); } private static SecurityPropertyService uninstallSecurityPropertyService(OperationContext context) { @@ -207,7 +218,7 @@ private static SecurityPropertyService uninstallSecurityPropertyService(Operatio if (service != null) { Object serviceImplementation = service.getService(); context.removeService(service); - if (serviceImplementation instanceof SecurityPropertyService) { + if (serviceImplementation != null && serviceImplementation instanceof SecurityPropertyService) { return (SecurityPropertyService) serviceImplementation; } } @@ -221,9 +232,15 @@ private ElytronTlsAdd() { super(INITIAL_PROVIDERS, FINAL_PROVIDERS, DISALLOWED_PROVIDERS, SECURITY_PROPERTIES, DEFAULT_SSL_CONTEXT); } + @Override + protected void populateModel(ModelNode operation, ModelNode model) throws OperationFailedException { + Version.getVersion(); + super.populateModel(operation, model); + } + @Override protected void performBoottime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException { - Map securityProperties = SECURITY_PROPERTIES.unwrap(context, model); + Map securityProperties = SECURITY_PROPERTIES.unwrap(context, model); final String defaultSSLContext = DEFAULT_SSL_CONTEXT.resolveModelAttribute(context, model).asStringOrNull(); ServiceTarget target = context.getServiceTarget(); @@ -231,20 +248,21 @@ protected void performBoottime(OperationContext context, ModelNode operation, Mo List disallowedProviders = DISALLOWED_PROVIDERS.unwrap(context, operation); ProviderRegistrationService prs = new ProviderRegistrationService(disallowedProviders); - ServiceBuilder builder = target.addService(ProviderRegistrationService.SERVICE_NAME) - .setInstance(prs) - .setInitialMode(Mode.ACTIVE); + ServiceBuilder builder = target.addService(ProviderRegistrationService.SERVICE_NAME, prs) + .setInitialMode(Mode.ACTIVE); String initialProviders = INITIAL_PROVIDERS.resolveModelAttribute(context, model).asStringOrNull(); if (initialProviders != null) { - builder.requires( - context.getCapabilityServiceName(PROVIDERS_CAPABILITY, initialProviders, Provider[].class)); + builder.addDependency( + context.getCapabilityServiceName(PROVIDERS_CAPABILITY, initialProviders, Provider[].class), + Provider[].class, prs.getInitialProivders()); } String finalProviders = FINAL_PROVIDERS.resolveModelAttribute(context, model).asStringOrNull(); if (finalProviders != null) { - builder.requires( - context.getCapabilityServiceName(PROVIDERS_CAPABILITY, finalProviders, Provider[].class)); + builder.addDependency( + context.getCapabilityServiceName(PROVIDERS_CAPABILITY, finalProviders, Provider[].class), + Provider[].class, prs.getFinalProviders()); } builder.install(); @@ -260,7 +278,7 @@ protected void performBoottime(OperationContext context, ModelNode operation, Mo serviceBuilder.setInstance(defaultSSLContextService).install(); } - if(context.isNormalServer()){ + if (context.isNormalServer()) { context.addStep(new AbstractDeploymentChainStep() { @Override public void execute(DeploymentProcessorTarget processorTarget) { @@ -293,11 +311,11 @@ protected boolean requiresRuntime(final OperationContext context) { private static class ElytronTlsRemove extends AbstractRemoveStepHandler implements ElytronOperationStepHandler { private ElytronTlsRemove() { - super(); + super(ELYTRON_TLS_RUNTIME_CAPABILITY); } @Override - protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) { + protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException { if (context.isResourceServiceRestartAllowed()) { SecurityPropertyService securityPropertyService = uninstallSecurityPropertyService(context); if (securityPropertyService != null) { diff --git a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/ElytronTlsSubsystemParser_1_0.java b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/ElytronTlsSubsystemParser_1_0.java index d2fc720..2975896 100644 --- a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/ElytronTlsSubsystemParser_1_0.java +++ b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/ElytronTlsSubsystemParser_1_0.java @@ -75,11 +75,11 @@ String getNameSpace() { PersistentResourceXMLDescription getTlsParser() { return PersistentResourceXMLDescription.decorator(TLS) - .addChild(getServerSSLContextParser()) - .addChild(getClientSSLContextParser()) .addChild(getKeyStoreParser()) .addChild(getKeyManagerParser()) .addChild(getTrustManagerParser()) + .addChild(getServerSSLContextParser()) + .addChild(getClientSSLContextParser()) .addChild(getCertificateAuthorityParser()) .addChild(getCertificateAuthorityAccountParser()) .build(); @@ -88,16 +88,16 @@ PersistentResourceXMLDescription getTlsParser() { @Override public PersistentResourceXMLDescription getParserDescription() { return PersistentResourceXMLDescription.builder(ElytronTlsExtension.SUBSYSTEM_PATH, getNameSpace()) - .addAttribute(ElytronTlsSubsystemDefinition.SECURITY_PROPERTIES, - new AttributeParsers.PropertiesParser(null, SECURITY_PROPERTY, true), - new AttributeMarshallers.PropertiesAttributeMarshaller(null, SECURITY_PROPERTY, true)) .addAttribute(ElytronTlsSubsystemDefinition.INITIAL_PROVIDERS) .addAttribute(ElytronTlsSubsystemDefinition.FINAL_PROVIDERS) .addAttribute(ElytronTlsSubsystemDefinition.DISALLOWED_PROVIDERS) + .addAttribute(ElytronTlsSubsystemDefinition.SECURITY_PROPERTIES, + new AttributeParsers.PropertiesParser(null, SECURITY_PROPERTY, true), + new AttributeMarshallers.PropertiesAttributeMarshaller(null, SECURITY_PROPERTY, true)) .addAttribute(ElytronTlsSubsystemDefinition.DEFAULT_SSL_CONTEXT) + .addChild(getProviderParser()) .addChild(getTlsParser()) .addChild(getCredentialStoresParser()) - .addChild(getProviderParser()) .addChild(getExpressionResolverParser()) .build(); } diff --git a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/KeyManagerAttributeDefinition.java b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/KeyManagerAttributeDefinition.java deleted file mode 100644 index 41dd136..0000000 --- a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/KeyManagerAttributeDefinition.java +++ /dev/null @@ -1,27 +0,0 @@ - /* - * Copyright 2022 Red Hat, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.wildfly.extension.elytron.tls.subsystem; - -import org.jboss.as.controller.ObjectTypeAttributeDefinition; - -public class KeyManagerAttributeDefinition extends ObjectTypeAttributeDefinition { - - protected KeyManagerAttributeDefinition(Builder builder) { - super(builder); - } - -} diff --git a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/KeyStoreDefinition.java b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/KeyStoreDefinition.java index 9a6e4f9..43ee449 100644 --- a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/KeyStoreDefinition.java +++ b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/KeyStoreDefinition.java @@ -18,7 +18,6 @@ package org.wildfly.extension.elytron.tls.subsystem; -import static org.jboss.as.controller.AbstractControllerService.PATH_MANAGER_CAPABILITY; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP; import static org.jboss.as.controller.security.CredentialReference.handleCredentialReferenceUpdate; import static org.jboss.as.controller.security.CredentialReference.rollbackCredentialStoreUpdate; @@ -62,6 +61,8 @@ import org.jboss.as.controller.registry.OperationEntry; import org.jboss.as.controller.registry.Resource; import org.jboss.as.controller.security.CredentialReference; +import org.jboss.as.controller.services.path.PathManager; +import org.jboss.as.controller.services.path.PathManagerService; import org.jboss.dmr.ModelNode; import org.jboss.dmr.ModelType; import org.jboss.msc.service.ServiceBuilder; @@ -267,10 +268,9 @@ protected void performRuntime(OperationContext context, ModelNode operation, Res ServiceTarget serviceTarget = context.getServiceTarget(); RuntimeCapability runtimeCapability = KEY_STORE_RUNTIME_CAPABILITY.fromBaseCapability(context.getCurrentAddressValue()); ServiceName serviceName = runtimeCapability.getCapabilityServiceName(KeyStore.class); - ServiceBuilder serviceBuilder = (ServiceBuilder) serviceTarget.addService(serviceName).setInitialMode(Mode.ACTIVE); + ServiceBuilder serviceBuilder = serviceTarget.addService(serviceName, keyStoreService).setInitialMode(Mode.ACTIVE); - keyStoreService.setPathManagerSupplier(serviceBuilder.requires( - PATH_MANAGER_CAPABILITY.getCapabilityServiceName())); + serviceBuilder.addDependency(PathManagerService.SERVICE_NAME, PathManager.class, keyStoreService.getPathManagerInjector()); if (relativeTo != null) { serviceBuilder.requires(pathName(relativeTo)); } @@ -278,13 +278,13 @@ protected void performRuntime(OperationContext context, ModelNode operation, Res if (providers != null) { String providersCapabilityName = RuntimeCapability.buildDynamicCapabilityName(PROVIDERS_CAPABILITY, providers); ServiceName providerLoaderServiceName = context.getCapabilityServiceName(providersCapabilityName, Provider[].class); - keyStoreService.setProvidersSupplier(serviceBuilder.requires(providerLoaderServiceName)); + serviceBuilder.addDependency(providerLoaderServiceName, Provider[].class, keyStoreService.getProvidersInjector()); } - keyStoreService.setCredentialSourceSupplier(CredentialReference.getCredentialSourceSupplier( - context, CREDENTIAL_REFERENCE, model, serviceBuilder)); + keyStoreService.getCredentialSourceSupplierInjector() + .inject(CredentialReference.getCredentialSourceSupplier(context, KeyStoreDefinition.CREDENTIAL_REFERENCE, model, serviceBuilder)); - commonRequirements(serviceBuilder, true, true).install(); + commonRequirements(serviceBuilder).install(); } @Override diff --git a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/KeyStoreParser.java b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/KeyStoreParser.java index f9d0fa3..9c81878 100644 --- a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/KeyStoreParser.java +++ b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/KeyStoreParser.java @@ -27,14 +27,14 @@ class KeyStoreParser { final PersistentResourceXMLDescription keyStoreParser_1_0 = PersistentResourceXMLDescription.builder(PathElement.pathElement(KEY_STORE)) .setXmlWrapperElement(KEY_STORES) - .addAttribute(KeyStoreDefinition.CREDENTIAL_REFERENCE) .addAttribute(KeyStoreDefinition.TYPE) - .addAttribute(FileAttributeDefinitions.PATH) - .addAttribute(FileAttributeDefinitions.RELATIVE_TO) - .addAttribute(KeyStoreDefinition.ALIAS_FILTER) - .addAttribute(KeyStoreDefinition.PROVIDERS) .addAttribute(KeyStoreDefinition.PROVIDER_NAME) + .addAttribute(KeyStoreDefinition.PROVIDERS) + .addAttribute(KeyStoreDefinition.CREDENTIAL_REFERENCE) + .addAttribute(KeyStoreDefinition.ALIAS_FILTER) .addAttribute(KeyStoreDefinition.REQUIRED) + .addAttribute(FileAttributeDefinitions.PATH) + .addAttribute(FileAttributeDefinitions.RELATIVE_TO) .addAttribute(CredentialReference.getAttributeDefinition()) .build(); } diff --git a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/KeyStoreService.java b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/KeyStoreService.java index f9f69a5..5441083 100644 --- a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/KeyStoreService.java +++ b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/KeyStoreService.java @@ -47,10 +47,12 @@ import org.jboss.as.controller.OperationFailedException; import org.jboss.as.controller.services.path.PathManager; import org.jboss.logging.Logger; -import org.jboss.msc.Service; +import org.jboss.msc.inject.Injector; +import org.jboss.msc.service.Service; import org.jboss.msc.service.StartContext; import org.jboss.msc.service.StartException; import org.jboss.msc.service.StopContext; +import org.jboss.msc.value.InjectedValue; import org.wildfly.common.function.ExceptionSupplier; import org.wildfly.common.iteration.ByteIterator; import org.wildfly.extension.elytron.tls.subsystem.FileAttributeDefinitions.PathResolver; @@ -87,9 +89,9 @@ class KeyStoreService implements ModifiableKeyStoreService { private final boolean required; private final String aliasFilter; - private Supplier pathManagerSupplier; - private Supplier providersSupplier; - private ExceptionSupplier credentialSourceSupplier; + private final InjectedValue pathManager = new InjectedValue<>(); + private final InjectedValue providers = new InjectedValue<>(); + private final InjectedValue> credentialSourceSupplier = new InjectedValue<>(); private PathResolver pathResolver; private File resolvedPath; @@ -160,7 +162,7 @@ public void start(StartContext startContext) throws StartException { if (type != null) { keyStore.load(is, password); } else { - Provider[] resolvedProviders = providersSupplier.get(); + Provider[] resolvedProviders = providers.getOptionalValue(); if (resolvedProviders == null) { resolvedProviders = Security.getProviders(); } @@ -200,9 +202,9 @@ public void start(StartContext startContext) throws StartException { } private Provider resolveProvider() throws StartException { - Provider[] candidates = providersSupplier.get(); - Supplier resolveProvidersSupplier = () -> candidates == null ? Security.getProviders() : candidates; - Provider identified = findProvider(resolveProvidersSupplier, provider, KeyStore.class, type); + Provider[] candidates = providers.getOptionalValue(); + Supplier providersSupplier = () -> candidates == null ? Security.getProviders() : candidates; + Provider identified = findProvider(providersSupplier, provider, KeyStore.class, type); if (identified == null) { throw LOGGER.noSuitableProvider(type); } @@ -249,6 +251,7 @@ public void stop(StopContext stopContext) { } } + @Override public KeyStore getValue() throws IllegalStateException, IllegalArgumentException { return unmodifiableKeyStore; } @@ -257,16 +260,16 @@ public KeyStore getModifiableValue() { return trackingKeyStore; } - void setPathManagerSupplier(Supplier pathManagerSupplier) { - this.pathManagerSupplier = pathManagerSupplier; + Injector getPathManagerInjector() { + return pathManager; } - void setProvidersSupplier(Supplier providersSupplier) { - this.providersSupplier = providersSupplier; + Injector getProvidersInjector() { + return providers; } - void setCredentialSourceSupplier(ExceptionSupplier credentialSourceSupplier) { - this.credentialSourceSupplier = credentialSourceSupplier; + Injector> getCredentialSourceSupplierInjector() { + return credentialSourceSupplier; } String getResolvedAbsolutePath() { @@ -336,7 +339,8 @@ char[] resolveKeyPassword(final ExceptionSupplier k } private char[] resolvePassword() throws Exception { - CredentialSource cs = credentialSourceSupplier != null ? credentialSourceSupplier.get() : null; + ExceptionSupplier sourceSupplier = credentialSourceSupplier.getValue(); + CredentialSource cs = sourceSupplier != null ? sourceSupplier.get() : null; String path = resolvedPath != null ? resolvedPath.getPath() : "null"; if (cs == null) throw LOGGER.keyStorePasswordCannotBeResolved(path); PasswordCredential credential = cs.getCredential(PasswordCredential.class); @@ -350,7 +354,7 @@ private char[] resolvePassword() throws Exception { File getResolvedPath(PathResolver pathResolver, String path, String relativeTo) { pathResolver.path(path); if (relativeTo != null) { - pathResolver.relativeTo(relativeTo, pathManagerSupplier.get()); + pathResolver.relativeTo(relativeTo, pathManager.getValue()); } return pathResolver.resolve(); } diff --git a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/ManagerParsers.java b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/ManagerParsers.java index d0c8917..3713190 100644 --- a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/ManagerParsers.java +++ b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/ManagerParsers.java @@ -33,10 +33,10 @@ class ManagerParsers { .addAttribute(SSLContextDefinitions.KEY_STORE) // .addAttribute(SSLContextDefinitions.KEY_STORE_OBJECT) .addAttribute(SSLContextDefinitions.ALIAS_FILTER) - .addAttribute(SSLContextDefinitions.PROVIDER_NAME) .addAttribute(SSLContextDefinitions.PROVIDERS) - .addAttribute(SSLContextDefinitions.GENERATE_SELF_SIGNED_CERTIFICATE_HOST) // new + .addAttribute(SSLContextDefinitions.PROVIDER_NAME) .addAttribute(CredentialReference.getAttributeDefinition()) + .addAttribute(SSLContextDefinitions.GENERATE_SELF_SIGNED_CERTIFICATE_HOST) // new .build(); final PersistentResourceXMLDescription trustManagerParser_1_0 = PersistentResourceXMLDescription.builder(PathElement.pathElement(TRUST_MANAGER)) diff --git a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/ModifiableKeyStoreService.java b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/ModifiableKeyStoreService.java index fd94757..fcc079b 100644 --- a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/ModifiableKeyStoreService.java +++ b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/ModifiableKeyStoreService.java @@ -20,14 +20,14 @@ import java.security.KeyStore; -import org.jboss.msc.Service; +import org.jboss.msc.service.Service; /** * An interface for KeyStore services, which provide modifiable KeyStore. * * @author Jan Kalina */ -interface ModifiableKeyStoreService extends Service { +interface ModifiableKeyStoreService extends Service { KeyStore getModifiableValue(); diff --git a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/ProviderDefinitions.java b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/ProviderDefinitions.java index 1cd5d96..0005450 100644 --- a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/ProviderDefinitions.java +++ b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/ProviderDefinitions.java @@ -18,7 +18,6 @@ package org.wildfly.extension.elytron.tls.subsystem; -import static org.jboss.as.controller.AbstractControllerService.PATH_MANAGER_CAPABILITY; import static org.wildfly.extension.elytron.tls.subsystem.Capabilities.PROVIDERS_API_CAPABILITY; import static org.wildfly.extension.elytron.tls.subsystem.Capabilities.PROVIDERS_RUNTIME_CAPABILITY; import static org.wildfly.extension.elytron.tls.subsystem.ClassLoadingAttributeDefinitions.CLASS_NAMES; @@ -64,6 +63,7 @@ import org.jboss.as.controller.SimpleAttributeDefinition; import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; import org.jboss.as.controller.SimpleMapAttributeDefinition; +import org.jboss.as.controller.services.path.PathManagerService; import org.jboss.dmr.ModelNode; import org.jboss.dmr.ModelType; import org.jboss.modules.Module; @@ -165,11 +165,12 @@ protected void resolveRuntime(ModelNode model, OperationContext context) throws @Override protected ExceptionSupplier prepareServiceSupplier(OperationContext context, CapabilityServiceBuilder serviceBuilder) throws OperationFailedException { + final Supplier pathManager; if (properties == null && relativeTo != null) { - pathManagerSupplier = serviceBuilder.requires(PATH_MANAGER_CAPABILITY.getCapabilityServiceName()); + pathManager = serviceBuilder.requires(PathManagerService.SERVICE_NAME); serviceBuilder.requires(pathName(relativeTo)); } else { - pathManagerSupplier = null; + pathManager = null; } return new ExceptionSupplier() { @@ -180,8 +181,8 @@ public Provider[] get() throws StartException { if (properties == null && relativeTo != null) { PathResolver pathResolver = pathResolver(); pathResolver.path(path); - if (relativeTo != null && pathManagerSupplier != null) { - pathResolver.relativeTo(relativeTo, pathManagerSupplier.get()); + if (relativeTo != null) { + pathResolver.relativeTo(relativeTo, pathManager.get()); } resolved = pathResolver.resolve(); pathResolver.clear(); diff --git a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/ProviderRegistrationService.java b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/ProviderRegistrationService.java index 3f5f533..6b79b5a 100644 --- a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/ProviderRegistrationService.java +++ b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/ProviderRegistrationService.java @@ -27,10 +27,11 @@ import java.util.Iterator; import java.util.Set; -import org.jboss.msc.Service; import org.jboss.msc.inject.Injector; +import org.jboss.msc.service.Service; import org.jboss.msc.service.ServiceName; import org.jboss.msc.service.StartContext; +import org.jboss.msc.service.StartException; import org.jboss.msc.service.StopContext; import org.jboss.msc.value.InjectedValue; @@ -39,7 +40,7 @@ * * @author Darran Lofthouse */ -class ProviderRegistrationService implements Service { +class ProviderRegistrationService implements Service { static final ServiceName SERVICE_NAME = ElytronTlsExtension.BASE_SERVICE_NAME.append(Constants.PROVIDER_REGISTRATION); @@ -54,7 +55,7 @@ class ProviderRegistrationService implements Service { } @Override - public void start(StartContext context) { + public void start(StartContext context) throws StartException { SecurityActions.doPrivileged((PrivilegedAction) () -> { for (String s : providersToRemove) { Security.removeProvider(s); @@ -109,4 +110,9 @@ Injector getInitialProivders() { Injector getFinalProviders() { return finalProviders; } + + @Override + public Void getValue() throws IllegalStateException, IllegalArgumentException { + return null; + } } diff --git a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/SSLContextDefinitions.java b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/SSLContextDefinitions.java index d0f428e..0148492 100644 --- a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/SSLContextDefinitions.java +++ b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/SSLContextDefinitions.java @@ -16,7 +16,6 @@ package org.wildfly.extension.elytron.tls.subsystem; -import static org.jboss.as.controller.AbstractControllerService.PATH_MANAGER_CAPABILITY; import static org.jboss.as.controller.capability.RuntimeCapability.buildDynamicCapabilityName; import static org.jboss.as.controller.security.CredentialReference.handleCredentialReferenceUpdate; import static org.jboss.as.controller.security.CredentialReference.rollbackCredentialStoreUpdate; @@ -33,9 +32,6 @@ import static org.wildfly.extension.elytron.tls.subsystem.FileAttributeDefinitions.PATH; import static org.wildfly.extension.elytron.tls.subsystem.FileAttributeDefinitions.RELATIVE_TO; import static org.wildfly.extension.elytron.tls.subsystem.FileAttributeDefinitions.pathName; -import static org.wildfly.extension.elytron.tls.subsystem.FileAttributeDefinitions.pathResolver; -import static org.wildfly.extension.elytron.tls.subsystem.TrivialResourceDefinition.Builder; -import static org.wildfly.extension.elytron.tls.subsystem.TrivialService.ValueSupplier; import static org.wildfly.extension.elytron.tls.subsystem._private.ElytronTLSLogger.LOGGER; import java.io.File; @@ -51,7 +47,6 @@ import java.security.Principal; import java.security.PrivateKey; import java.security.Provider; -import java.security.Security; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.ArrayList; @@ -61,7 +56,6 @@ import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Supplier; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; @@ -75,6 +69,8 @@ import org.jboss.as.controller.AbstractAddStepHandler; import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.MapAttributeDefinition; +import org.jboss.as.controller.ModelVersion; import org.jboss.as.controller.ObjectListAttributeDefinition; import org.jboss.as.controller.ObjectTypeAttributeDefinition; import org.jboss.as.controller.OperationContext; @@ -84,6 +80,7 @@ import org.jboss.as.controller.ResourceDefinition; import org.jboss.as.controller.SimpleAttributeDefinition; import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.as.controller.SimpleMapAttributeDefinition; import org.jboss.as.controller.SimpleOperationDefinitionBuilder; import org.jboss.as.controller.StringListAttributeDefinition; import org.jboss.as.controller.capability.RuntimeCapability; @@ -95,6 +92,7 @@ import org.jboss.as.controller.registry.Resource; import org.jboss.as.controller.security.CredentialReference; import org.jboss.as.controller.services.path.PathManager; +import org.jboss.as.controller.services.path.PathManagerService; import org.jboss.dmr.ModelNode; import org.jboss.dmr.ModelType; import org.jboss.msc.service.ServiceBuilder; @@ -103,24 +101,24 @@ import org.jboss.msc.service.ServiceName; import org.jboss.msc.service.ServiceRegistry; import org.jboss.msc.service.StartException; +import org.jboss.msc.value.InjectedValue; import org.wildfly.common.function.ExceptionSupplier; -import org.wildfly.security.EmptyProvider; +import org.wildfly.extension.elytron.tls.subsystem.TrivialResourceDefinition.Builder; +import org.wildfly.extension.elytron.tls.subsystem.TrivialService.ValueSupplier; import org.wildfly.security.credential.PasswordCredential; import org.wildfly.security.credential.source.CredentialSource; import org.wildfly.security.keystore.AliasFilter; -import org.wildfly.security.keystore.AtomicLoadKeyStore; import org.wildfly.security.keystore.FilteringKeyStore; -import org.wildfly.security.keystore.KeyStoreUtil; import org.wildfly.security.password.interfaces.ClearPassword; -import org.wildfly.security.provider.util.ProviderUtil; import org.wildfly.security.ssl.CipherSuiteSelector; import org.wildfly.security.ssl.DomainlessSSLContextBuilder; import org.wildfly.security.ssl.Protocol; import org.wildfly.security.ssl.ProtocolSelector; import org.wildfly.security.ssl.X509RevocationTrustManager; - /** + * Definitions for resources used to configure SSLContexts. + * * @author Cameron Rodriguez */ public class SSLContextDefinitions { @@ -220,6 +218,14 @@ public class SSLContextDefinitions { .setRestartAllServices() .build(); + @Deprecated + static final SimpleAttributeDefinition MAXIMUM_CERT_PATH_CRL = new SimpleAttributeDefinitionBuilder(Constants.MAXIMUM_CERT_PATH, ModelType.INT, true) + .setDeprecated(ModelVersion.create(8)) + .setValidator(new IntRangeValidator(1)) + .setAllowExpression(true) + .setRestartAllServices() + .build(); + static final SimpleAttributeDefinition GENERATE_SELF_SIGNED_CERTIFICATE_HOST = new SimpleAttributeDefinitionBuilder(Constants.GENERATE_SELF_SIGNED_CERTIFICATE_HOST, ModelType.STRING, true) .setMinSize(1) .setAllowExpression(true) @@ -439,21 +445,22 @@ public class SSLContextDefinitions { /* SSL Context definitions */ - static final SimpleAttributeDefinition DEFAULT_SSL_CONTEXT = new SimpleAttributeDefinitionBuilder(Constants.DEFAULT_SSL_CONTEXT, ModelType.STRING) + static final SimpleAttributeDefinition DEFAULT_SSL_CONTEXT = new SimpleAttributeDefinitionBuilder(Constants.DEFAULT_SSL_CONTEXT, ModelType.STRING) .setRequired(true) .setCapabilityReference(SSL_CONTEXT_CAPABILITY) .setRestartAllServices() .build(); -// static final MapAttributeDefinition HOST_CONTEXT_MAP = new SimpleMapAttributeDefinition.Builder(Constants.HOST_CONTEXT_MAP, ModelType.STRING, true) -// .setMinSize(0) -// .setMapValidator(new HostContextMapValidator()) -// .setCapabilityReference(SSL_CONTEXT_CAPABILITY) -// .setAllowExpression(false) -// .setRestartAllServices() -// .build(); + static final MapAttributeDefinition HOST_CONTEXT_MAP = new SimpleMapAttributeDefinition.Builder(Constants.HOST_CONTEXT_MAP, ModelType.STRING, true) + .setMinSize(0) + .setCapabilityReference(SSL_CONTEXT_CAPABILITY) + .setMapValidator(new Validators.HostContextMapValidator()) + .setAllowExpression(false) + .setRestartAllServices() + .build(); + + /* Runtime Attributes */ - /** Runtime Attributes */ private static final SimpleAttributeDefinition ACTIVE_SESSION_COUNT = new SimpleAttributeDefinitionBuilder(Constants.ACTIVE_SESSION_COUNT, ModelType.INT) .setStorageRuntime() .build(); @@ -484,32 +491,36 @@ protected ValueSupplier getValueSupplier(ServiceBuilder final String providerName = PROVIDER_NAME.resolveModelAttribute(context, model).asStringOrNull(); final String providersName = providersKMDefinition.resolveModelAttribute(context, model).asStringOrNull(); - Supplier providersSupplier = addRequirement(PROVIDERS_CAPABILITY, Provider[].class, serviceBuilder, - context, providersName); - Supplier pathManagerSupplier = serviceBuilder.requires(PATH_MANAGER_CAPABILITY.getCapabilityServiceName()); + final InjectedValue providersInjector = new InjectedValue<>(); + if (providersName != null) { + serviceBuilder.addDependency(context.getCapabilityServiceName( + buildDynamicCapabilityName(PROVIDERS_CAPABILITY, providersName), Provider[].class), + Provider[].class, providersInjector); + } // final ModelNode keyStoreObject = keystoreKMObjectDefinition.resolveModelAttribute(context, model); final String keyStoreName = keystoreKMDefinition.resolveModelAttribute(context, model).asStringOrNull(); final ModifiableKeyStoreService keyStoreService = getModifiableKeyStoreService(context, keyStoreName); - ExceptionSupplier keyStoreSupplier; + final InjectedValue keyStoreInjector = new InjectedValue<>(); - /* if (keyStoreName != null) { - if (keyStoreObject != null) { - throw LOGGER.multipleKeystoreDefinitions(); - } - keyStoreSupplier = new SSLContextExceptionSupplier<>(KEY_STORE_CAPABILITY, KeyStore.class, serviceBuilder, context, keyStoreName); - } else { - if (keyStoreObject == null) { - LOGGER.missingKeyStoreDefinition(); - } - keyStoreSupplier = createKeyStore(serviceBuilder, context, keyStoreObject, pathManagerSupplier, providersSupplier); - } */ - keyStoreSupplier = new SSLContextExceptionSupplier<>(KEY_STORE_CAPABILITY, KeyStore.class, serviceBuilder, context, keyStoreName); + if (keyStoreName != null) { + /* if (keyStoreObject.isDefined()) { + throw LOGGER.multipleKeyStoreDefinitions(); + } */ + serviceBuilder.addDependency(context.getCapabilityServiceName( + buildDynamicCapabilityName(KEY_STORE_CAPABILITY, keyStoreName), KeyStore.class), + KeyStore.class, keyStoreInjector); + /* } else { + if (!keyStoreObject.isDefined()) { + LOGGER.missingKeyStoreDefinition(); + } + keyStoreInjector = createKeyStore(serviceBuilder, context, keyStoreObject, providersInjector); */ + } final String algorithm = algorithmName != null ? algorithmName : KeyManagerFactory.getDefaultAlgorithm(); DelegatingKeyManager delegatingKeyManager = new DelegatingKeyManager(); return () -> { - Provider[] providers = providersSupplier.get(); + Provider[] providers = providersInjector.getOptionalValue(); KeyManagerFactory keyManagerFactory = null; if (providers != null) { for (Provider current : providers) { @@ -533,7 +544,7 @@ protected ValueSupplier getValueSupplier(ServiceBuilder } } - KeyStore keyStore = keyStoreSupplier.get(); + KeyStore keyStore = keyStoreInjector.getOptionalValue(); char[] password; try { CredentialSource cs = credentialSourceSupplier.get(); @@ -577,22 +588,6 @@ protected ValueSupplier getValueSupplier(ServiceBuilder protected void rollbackRuntime(OperationContext context, final ModelNode operation, final Resource resource) { rollbackCredentialStoreUpdate(credentialReferenceDefinition, context, resource); } - - class SSLContextExceptionSupplier implements ExceptionSupplier { - private final Supplier supplier; - private final ExceptionSupplier exceptionSupplier; - - SSLContextExceptionSupplier (String baseName, Class type, ServiceBuilder serviceBuilder, - OperationContext context, String dynamicModelElement) { - this.supplier = addRequirement(baseName, type, serviceBuilder, context, dynamicModelElement); - this.exceptionSupplier = this.supplier::get; - } - - @Override - public T get() throws E { - return exceptionSupplier.get(); - } - } }; final ServiceUtil KEY_MANAGER_UTIL = ServiceUtil.newInstance(KEY_MANAGER_RUNTIME_CAPABILITY, Constants.KEY_MANAGER, KeyManager.class); @@ -621,41 +616,45 @@ protected ValueSupplier getValueSupplier(ServiceBuilder providersSupplier = addRequirement(PROVIDERS_CAPABILITY, Provider[].class, serviceBuilder, - context, providersName); - Supplier pathManagerSupplier = serviceBuilder.requires(PATH_MANAGER_CAPABILITY.getCapabilityServiceName()); + final InjectedValue providersInjector = new InjectedValue<>(); + if (providerLoader != null) { + serviceBuilder.addDependency(context.getCapabilityServiceName( + buildDynamicCapabilityName(PROVIDERS_CAPABILITY, providerLoader), Provider[].class), + Provider[].class, providersInjector); + } // final ModelNode keyStoreObject = keystoreTMObjectDefinition.resolveModelAttribute(context, model); - final String keyStoreName = keystoreTMDefinition.resolveModelAttribute(context, model).asStringOrNull(); - final ExceptionSupplier keyStoreSupplier; + final InjectedValue keyStoreInjector = new InjectedValue<>(); - /* if (keyStoreName != null) { - if (keyStoreObject != null) { - throw LOGGER.multipleKeystoreDefinitions(); - } - keyStoreSupplier = new SSLContextExceptionSupplier<>(KEY_STORE_CAPABILITY, KeyStore.class, serviceBuilder, context, keyStoreName); - } else { - if (keyStoreObject == null) { + if (keyStoreName != null) { + /* if (keyStoreObject.isDefined()) { + throw LOGGER.multipleKeyStoreDefinitions(); + } */ + serviceBuilder.addDependency(context.getCapabilityServiceName( + buildDynamicCapabilityName(KEY_STORE_CAPABILITY, keyStoreName), KeyStore.class), + KeyStore.class, keyStoreInjector); + /* } else { + if (!keyStoreObject.isDefined()) { LOGGER.missingKeyStoreDefinition(); } - keyStoreSupplier = createKeyStore(serviceBuilder, context, keyStoreObject, pathManagerSupplier, providersSupplier); - } */ - keyStoreSupplier = new SSLContextExceptionSupplier<>(KEY_STORE_CAPABILITY, KeyStore.class, serviceBuilder, context, keyStoreName); + keyStoreInjector = createKeyStore(serviceBuilder, context, keyStoreObject, providersInjector); */ + } final String algorithm = algorithmName != null ? algorithmName : TrustManagerFactory.getDefaultAlgorithm(); if (model.hasDefined(CERTIFICATE_REVOCATION_LIST.getName()) || model.hasDefined(OCSP.getName()) || model.hasDefined(CERTIFICATE_REVOCATION_LISTS.getName())) { - return createX509RevocationTrustManager(serviceBuilder, context, model, algorithm, providerName, providersSupplier, keyStoreSupplier, aliasFilter); + return createX509RevocationTrustManager(serviceBuilder, context, model, algorithm, providerName, providersInjector, keyStoreInjector, aliasFilter); } DelegatingTrustManager delegatingTrustManager = new DelegatingTrustManager(); return () -> { - Provider[] providers = providersSupplier.get(); + Provider[] providers = providersInjector.getOptionalValue(); TrustManagerFactory trustManagerFactory = createTrustManagerFactory(providers, providerName, algorithm); - KeyStore keyStore = keyStoreSupplier.get(); + KeyStore keyStore = keyStoreInjector.getOptionalValue(); try { if (aliasFilter != null) { @@ -669,7 +668,7 @@ protected ValueSupplier getValueSupplier(ServiceBuilder getValueSupplier(ServiceBuilder createX509RevocationTrustManager(ServiceBuilder serviceBuilder, OperationContext context, - ModelNode model, String algorithm, String providerName, Supplier providersSupplier, - ExceptionSupplier keyStoreSupplier, String aliasFilter) throws OperationFailedException { - + ModelNode model, String algorithm, String providerName, InjectedValue providersInjector, + InjectedValue keyStoreInjector, String aliasFilter) throws OperationFailedException { ModelNode crlNode = CERTIFICATE_REVOCATION_LIST.resolveModelAttribute(context, model); ModelNode ocspNode = OCSP.resolveModelAttribute(context, model); ModelNode multipleCrlsNode = CERTIFICATE_REVOCATION_LISTS.resolveModelAttribute(context, model); @@ -696,9 +694,20 @@ private ValueSupplier createX509RevocationTrustManager(ServiceBuil boolean onlyLeafCert = ONLY_LEAF_CERT.resolveModelAttribute(context, model).asBoolean(); Integer maxCertPath = MAXIMUM_CERT_PATH.resolveModelAttribute(context, model).asIntOrNull(); + //BW compatibility, max cert path is now in trust-manager + @Deprecated + Integer crlCertPath = MAXIMUM_CERT_PATH_CRL.resolveModelAttribute(context, crlNode).asIntOrNull(); + if (crlCertPath != null) { + LOGGER.warn("maximum-cert-path in certificate-revocation-list is for legacy support. Please use only the one in trust-manager!"); + if (maxCertPath != null) { + throw LOGGER.multipleMaximumCertPathDefinitions(); + } + maxCertPath = crlCertPath; + } + String crlPath = null; String crlRelativeTo = null; - Supplier pathManagerSupplier = serviceBuilder.requires(PATH_MANAGER_CAPABILITY.getCapabilityServiceName()); + InjectedValue pathManagerInjector = new InjectedValue<>(); List crlFiles = new ArrayList<>(); if (crlNode.isDefined()) { @@ -707,20 +716,23 @@ private ValueSupplier createX509RevocationTrustManager(ServiceBuil if (crlPath != null) { if (crlRelativeTo != null) { + serviceBuilder.addDependency(PathManagerService.SERVICE_NAME, PathManager.class, pathManagerInjector); serviceBuilder.requires(pathName(crlRelativeTo)); } - crlFiles.add(new CrlFile(crlPath, crlRelativeTo, pathManagerSupplier)); + crlFiles.add(new CrlFile(crlPath, crlRelativeTo, pathManagerInjector)); } } else if (multipleCrlsNode.isDefined()) { // certificate-revocation-lists and certificate-revocation-list are mutually exclusive for (ModelNode crl : multipleCrlsNode.asList()) { crlPath = PATH.resolveModelAttribute(context, crl).asStringOrNull(); crlRelativeTo = RELATIVE_TO.resolveModelAttribute(context, crl).asStringOrNull(); + pathManagerInjector = new InjectedValue<>(); if (crlPath != null) { if (crlRelativeTo != null) { + serviceBuilder.addDependency(PathManagerService.SERVICE_NAME, PathManager.class, pathManagerInjector); serviceBuilder.requires(pathName(crlRelativeTo)); } - crlFiles.add(new CrlFile(crlPath, crlRelativeTo, pathManagerSupplier)); + crlFiles.add(new CrlFile(crlPath, crlRelativeTo, pathManagerInjector)); } } } @@ -730,9 +742,13 @@ private ValueSupplier createX509RevocationTrustManager(ServiceBuil String responderCertAlias = RESPONDER_CERTIFICATE.resolveModelAttribute(context, ocspNode).asStringOrNull(); String responderKeystore = RESPONDER_KEYSTORE.resolveModelAttribute(context, ocspNode).asStringOrNull(); - final ExceptionSupplier responderStoreSupplier = responderKeystore != null - ? new SSLContextExceptionSupplier<>(KEY_STORE_CAPABILITY, KeyStore.class, serviceBuilder, context, responderKeystore) - : keyStoreSupplier; + final InjectedValue responderStoreInjector = responderKeystore != null ? new InjectedValue<>() : keyStoreInjector; + + if (responderKeystore != null) { + serviceBuilder.addDependency(context.getCapabilityServiceName( + buildDynamicCapabilityName(KEY_STORE_CAPABILITY, responderKeystore), KeyStore.class), + KeyStore.class, responderStoreInjector); + } URI responderUri; try { @@ -765,8 +781,8 @@ private ValueSupplier createX509RevocationTrustManager(ServiceBuil } final List finalCrlFiles = crlFiles; return () -> { - TrustManagerFactory trustManagerFactory = createTrustManagerFactory(providersSupplier.get(), providerName, algorithm); - KeyStore keyStore = keyStoreSupplier.get(); + TrustManagerFactory trustManagerFactory = createTrustManagerFactory(providersInjector.getOptionalValue(), providerName, algorithm); + KeyStore keyStore = keyStoreInjector.getOptionalValue(); if (aliasFilter != null) { try { @@ -777,7 +793,7 @@ private ValueSupplier createX509RevocationTrustManager(ServiceBuil } if (responderCertAlias != null) { - KeyStore responderStore = responderStoreSupplier.get(); + KeyStore responderStore = responderStoreInjector.getOptionalValue(); try { builder.setOcspResponderCert((X509Certificate) responderStore.getCertificate(responderCertAlias)); } catch (KeyStoreException e) { @@ -801,7 +817,7 @@ private List getCrlStreams(List crlFiles) throws StartExce List crlStreams = new ArrayList<>(); for (CrlFile crl : crlFiles) { try { - crlStreams.add(new FileInputStream(resolveFileLocation(crl.getCrlPath(), crl.getRelativeTo(), crl.getPathManagerSupplier()))); + crlStreams.add(new FileInputStream(resolveFileLocation(crl.getCrlPath(), crl.getRelativeTo(), crl.getPathManagerInjector()))); } catch (FileNotFoundException e) { throw LOGGER.unableToAccessCRL(e); } @@ -866,10 +882,10 @@ public X509Certificate[] getAcceptedIssuers() { }; } - private File resolveFileLocation(String path, String relativeTo, Supplier pathManagerSupplier) { + private File resolveFileLocation(String path, String relativeTo, InjectedValue pathManagerInjector) { final File resolvedPath; if (relativeTo != null) { - PathManager pathManager = pathManagerSupplier.get(); + PathManager pathManager = pathManagerInjector.getValue(); resolvedPath = new File(pathManager.resolveRelativePathEntry(path, relativeTo)); } else { resolvedPath = new File(path); @@ -901,22 +917,6 @@ private TrustManagerFactory createTrustManagerFactory(Provider[] providers, Stri throw new StartException(e); } } - - class SSLContextExceptionSupplier implements ExceptionSupplier { - private final Supplier supplier; - private final ExceptionSupplier exceptionSupplier; - - SSLContextExceptionSupplier (String baseName, Class type, ServiceBuilder serviceBuilder, - OperationContext context, String dynamicModelElement) { - this.supplier = addRequirement(baseName, type, serviceBuilder, context, dynamicModelElement); - this.exceptionSupplier = this.supplier::get; - } - - @Override - public T get() throws E { - return exceptionSupplier.get(); - } - } }; ResourceDescriptionResolver resolver = ElytronTlsExtension.getResourceDescriptionResolver(Constants.TRUST_MANAGER); @@ -930,22 +930,21 @@ public T get() throws E { .addOperation(new SimpleOperationDefinitionBuilder(Constants.RELOAD_CERTIFICATE_REVOCATION_LIST, resolver) .setRuntimeOnly() .build(), new ElytronRuntimeOnlyHandler() { - - @Override - protected void executeRuntimeStep(OperationContext context, ModelNode operation) throws OperationFailedException { - ServiceName serviceName = TRUST_MANAGER_RUNTIME_CAPABILITY.fromBaseCapability(context.getCurrentAddressValue()).getCapabilityServiceName(); - ServiceController serviceContainer = getRequiredService(context.getServiceRegistry(true), serviceName, TrustManager.class); - State serviceState; - if ((serviceState = serviceContainer.getState()) != State.UP) { - throw LOGGER.requiredServiceNotUp(serviceName, serviceState); - } - TrustManager trustManager = serviceContainer.getValue(); - if (! (trustManager instanceof ReloadableX509ExtendedTrustManager)) { - throw LOGGER.unableToReloadCRLNotReloadable(); - } - ((ReloadableX509ExtendedTrustManager) trustManager).reload(); - } - }) + @Override + protected void executeRuntimeStep(OperationContext context, ModelNode operation) throws OperationFailedException { + ServiceName serviceName = TRUST_MANAGER_RUNTIME_CAPABILITY.fromBaseCapability(context.getCurrentAddressValue()).getCapabilityServiceName(); + ServiceController serviceContainer = getRequiredService(context.getServiceRegistry(true), serviceName, TrustManager.class); + State serviceState; + if ((serviceState = serviceContainer.getState()) != State.UP) { + throw LOGGER.requiredServiceNotUp(serviceName, serviceState); + } + TrustManager trustManager = serviceContainer.getValue(); + if (! (trustManager instanceof ReloadableX509ExtendedTrustManager)) { + throw LOGGER.unableToReloadCRLNotReloadable(); + } + ((ReloadableX509ExtendedTrustManager) trustManager).reload(); + } + }) .addOperation(new SimpleOperationDefinitionBuilder(Constants.INIT, RESOURCE_RESOLVER) .setRuntimeOnly() .build(), init(TRUST_MANAGER_UTIL)) @@ -1008,44 +1007,44 @@ static ResourceDefinition getClientSSLContextDefinition(boolean serverOrHostCont @Override protected ValueSupplier getValueSupplier(ServiceBuilder serviceBuilder, OperationContext context, ModelNode model) throws OperationFailedException { final String providerName = PROVIDER_NAME.resolveModelAttribute(context, model).asStringOrNull(); - final String providersName = providersDefinition.resolveModelAttribute(context, model).asStringOrNull(); final List protocols = PROTOCOLS.unwrap(context, model); final String cipherSuiteFilter = CIPHER_SUITE_FILTER.resolveModelAttribute(context, model).asString(); final String cipherSuiteNames = CIPHER_SUITE_NAMES.resolveModelAttribute(context, model).asStringOrNull(); - Supplier providersSupplier = addRequirement(PROVIDERS_CAPABILITY, Provider[].class, serviceBuilder, - context, providersName); - Supplier pathManagerSupplier = serviceBuilder.requires(PATH_MANAGER_CAPABILITY.getCapabilityServiceName()); - SSLContextExceptionSupplier keyManagerSupplier; - SSLContextExceptionSupplier trustManagerSupplier; + final InjectedValue providersInjector = addSSLContextDependency(PROVIDERS_CAPABILITY, providersDefinition, Provider[].class, serviceBuilder, context, model); + final InjectedValue keyManagerInjector = addSSLContextDependency(KEY_MANAGER_CAPABILITY, KEY_MANAGER, KeyManager.class, serviceBuilder, context, model); + final InjectedValue trustManagerInjector = addSSLContextDependency(TRUST_MANAGER_CAPABILITY, TRUST_MANAGER, TrustManager.class, serviceBuilder, context, model);; + // final ModelNode keyManagerObject = KEY_MANAGER_OBJECT.resolveModelAttribute(context, model); + // final ModelNode trustManagerObject = TRUST_MANAGER_OBJECT.resolveModelAttribute(context, model); - final String keyManagerName = KEY_MANAGER.resolveModelAttribute(context, model).asStringOrNull(); - /* final ModelNode keyManagerObject = KEY_MANAGER_OBJECT.resolveModelAttribute(context, model); - if (keyManagerObject.isDefined()) { - keyManagerSupplier = (SSLContextExceptionSupplier) createKeyManager(serviceBuilder, context, keyManagerObject, pathManagerSupplier, providersSupplier); + /* if (keyManagerName != null) { + if (keyManagerObject.isDefined()) { + throw LOGGER.multipleKeyManagerDefinitions(); + } + keyManagerInjector = addSSLContextDependency(KEY_MANAGER_CAPABILITY, KEY_MANAGER, KeyManager.class, serviceBuilder, context, model); } else { // Use reference - keyManagerSupplier = new SSLContextExceptionSupplier<>(KEY_MANAGER_CAPABILITY, KeyManager.class, serviceBuilder, - context, keyManagerName); - } */ - keyManagerSupplier = new SSLContextExceptionSupplier<>(KEY_MANAGER_CAPABILITY, KeyManager.class, serviceBuilder, context, keyManagerName); + if (!keyManagerObject.isDefined()) { + LOGGER.missingKeyManagerDefinition(); + } + keyManagerInjector = createKeyManager(serviceBuilder, context, keyManagerObject, providersInjector); + } - final String trustManagerName = TRUST_MANAGER.resolveModelAttribute(context, model).asStringOrNull(); - /* final ModelNode trustManagerObject = TRUST_MANAGER_OBJECT.resolveModelAttribute(context, model); - if (trustManagerObject.isDefined()) { - trustManagerSupplier = (SSLContextExceptionSupplier) createTrustManager(serviceBuilder, context, trustManagerObject, pathManagerSupplier, providersSupplier); + if (trustManagerName != null) { + if (trustManagerObject.isDefined()) { + throw LOGGER.multipleTrustManagerDefinitions(); + } + trustManagerInjector = addSSLContextDependency(TRUST_MANAGER_CAPABILITY, TRUST_MANAGER, TrustManager.class, serviceBuilder, context, model); } else { - trustManagerSupplier = new SSLContextExceptionSupplier<>(TRUST_MANAGER_CAPABILITY, TrustManager.class, serviceBuilder, - context, trustManagerName); + if (!trustManagerObject.isDefined()) { + LOGGER.missingTrustManagerDefinition(); + } + trustManagerInjector = createTrustManager(serviceBuilder, context, trustManagerObject, providersInjector); } */ - trustManagerSupplier = new SSLContextExceptionSupplier<>(TRUST_MANAGER_CAPABILITY, TrustManager.class, serviceBuilder, context, trustManagerName); - - final SSLContextExceptionSupplier finalKeyManagerSupplier = keyManagerSupplier; - final SSLContextExceptionSupplier finalTrustManagerSupplier = trustManagerSupplier; return () -> { - X509ExtendedKeyManager keyManager = getX509KeyManager(finalKeyManagerSupplier.get()); - X509ExtendedTrustManager trustManager = getX509TrustManager(finalTrustManagerSupplier.get()); - Provider[] providers = filterProviders(providersSupplier.get(), providerName); + X509ExtendedKeyManager keyManager = getX509KeyManager(keyManagerInjector.getOptionalValue()); + X509ExtendedTrustManager trustManager = getX509TrustManager(trustManagerInjector.getOptionalValue()); + Provider[] providers = filterProviders(providersInjector.getOptionalValue(), providerName); DomainlessSSLContextBuilder builder = new DomainlessSSLContextBuilder(); if (keyManager != null) builder.setKeyManager(keyManager); @@ -1103,8 +1102,6 @@ protected void installedForResource(ServiceController serviceControl static ResourceDefinition getServerSSLContextDefinition(boolean serverOrHostController) { - final ObjectTypeAttributeDefinition credentialReferenceDefinition = CredentialReference.getAttributeDefinition(true); - final SimpleAttributeDefinition providersDefinition = new SimpleAttributeDefinitionBuilder(PROVIDERS) .setCapabilityReference(PROVIDERS_CAPABILITY, SSL_CONTEXT_CAPABILITY) .setRestartAllServices() @@ -1120,16 +1117,14 @@ static ResourceDefinition getServerSSLContextDefinition(boolean serverOrHostCont providersDefinition, WANT_CLIENT_AUTH, NEED_CLIENT_AUTH, AUTHENTICATION_OPTIONAL, USE_CIPHER_SUITES_ORDER, MAXIMUM_SESSION_CACHE_SIZE, SESSION_TIMEOUT, WRAP}; - AbstractAddStepHandler add = new TrivialAddHandler(SSLContext.class, ServiceController.Mode.ACTIVE, ServiceController.Mode.PASSIVE, attributes, SSL_CONTEXT_RUNTIME_CAPABILITY) { @Override protected ValueSupplier getValueSupplier(ServiceBuilder serviceBuilder, - OperationContext context, ModelNode model) throws OperationFailedException { + OperationContext context, ModelNode model) throws OperationFailedException { final String providerName = PROVIDER_NAME.resolveModelAttribute(context, model).asStringOrNull(); - final String providersName = PROVIDERS.resolveModelAttribute(context, model).asStringOrNull(); final List protocols = PROTOCOLS.unwrap(context, model); final String cipherSuiteFilter = CIPHER_SUITE_FILTER.resolveModelAttribute(context, model).asString(); // has default value, can't be null final String cipherSuiteNames = CIPHER_SUITE_NAMES.resolveModelAttribute(context, model).asStringOrNull(); // doesn't have a default value yet since we are disabling TLS 1.3 by default @@ -1140,40 +1135,41 @@ protected ValueSupplier getValueSupplier(ServiceBuilder final int maximumSessionCacheSize = MAXIMUM_SESSION_CACHE_SIZE.resolveModelAttribute(context, model).asInt(); final int sessionTimeout = SESSION_TIMEOUT.resolveModelAttribute(context, model).asInt(); final boolean wrap = WRAP.resolveModelAttribute(context, model).asBoolean(); - - Supplier providersSupplier = addRequirement(PROVIDERS_CAPABILITY, Provider[].class, serviceBuilder, - context, providersName); - Supplier pathManagerSupplier = serviceBuilder.requires(PATH_MANAGER_CAPABILITY.getCapabilityServiceName()); - SSLContextExceptionSupplier keyManagerSupplier; - SSLContextExceptionSupplier trustManagerSupplier; - - final String keyManagerName = keyManagerDefinition.resolveModelAttribute(context, model).asStringOrNull(); - /* final ModelNode keyManagerObject = KEY_MANAGER_OBJECT.resolveModelAttribute(context, model); - if (keyManagerObject.isDefined()) { - keyManagerSupplier = (SSLContextExceptionSupplier) createKeyManager(serviceBuilder, context, keyManagerObject, pathManagerSupplier, providersSupplier); + + final InjectedValue providersInjector = addSSLContextDependency(PROVIDERS_CAPABILITY, providersDefinition, Provider[].class, serviceBuilder, context, model); + InjectedValue keyManagerInjector = addSSLContextDependency(KEY_MANAGER_CAPABILITY, KEY_MANAGER, KeyManager.class, serviceBuilder, context, model); + InjectedValue trustManagerInjector = addSSLContextDependency(TRUST_MANAGER_CAPABILITY, TRUST_MANAGER, TrustManager.class, serviceBuilder, context, model);; + // final ModelNode keyManagerObject = KEY_MANAGER_OBJECT.resolveModelAttribute(context, model); + // final ModelNode trustManagerObject = TRUST_MANAGER_OBJECT.resolveModelAttribute(context, model); + + /* if (keyManagerName != null) { + if (keyManagerObject.isDefined()) { + throw LOGGER.multipleKeyManagerDefinitions(); + } + keyManagerInjector = addSSLContextDependency(KEY_MANAGER_CAPABILITY, KEY_MANAGER, KeyManager.class, serviceBuilder, context, model); } else { // Use reference - keyManagerSupplier = new SSLContextExceptionSupplier<>(KEY_MANAGER_CAPABILITY, KeyManager.class, serviceBuilder, - context, keyManagerName); - } */ - keyManagerSupplier = new SSLContextExceptionSupplier<>(KEY_MANAGER_CAPABILITY, KeyManager.class, serviceBuilder, context, keyManagerName); - - final String trustManagerName = TRUST_MANAGER.resolveModelAttribute(context, model).asStringOrNull(); - /* final ModelNode trustManagerObject = TRUST_MANAGER_OBJECT.resolveModelAttribute(context, model); - if (trustManagerObject.isDefined()) { - trustManagerSupplier = (SSLContextExceptionSupplier) createTrustManager(serviceBuilder, context, keyManagerObject, pathManagerSupplier, providersSupplier); + if (!keyManagerObject.isDefined()) { + throw LOGGER.missingKeyManagerDefinition(); + } + keyManagerInjector = createKeyManager(serviceBuilder, context, keyManagerObject, providersInjector); + } + + if (trustManagerName != null) { + if (trustManagerObject.isDefined()) { + throw LOGGER.multipleTrustManagerDefinitions(); + } + trustManagerInjector = addSSLContextDependency(TRUST_MANAGER_CAPABILITY, TRUST_MANAGER, TrustManager.class, serviceBuilder, context, model); } else { - trustManagerSupplier = new SSLContextExceptionSupplier<>(TRUST_MANAGER_CAPABILITY, TrustManager.class, serviceBuilder, - context, trustManagerName); + if (!keyManagerObject.isDefined()) { + throw LOGGER.missingKeyManagerDefinition(); + } + trustManagerInjector = createTrustManager(serviceBuilder, context, keyManagerObject, providersInjector); } */ - trustManagerSupplier = new SSLContextExceptionSupplier<>(TRUST_MANAGER_CAPABILITY, TrustManager.class, serviceBuilder, context, trustManagerName); - - final SSLContextExceptionSupplier finalKeyManagerSupplier = keyManagerSupplier; - final SSLContextExceptionSupplier finalTrustManagerSupplier = trustManagerSupplier; return () -> { - X509ExtendedKeyManager keyManager = getX509KeyManager(finalKeyManagerSupplier.get()); - X509ExtendedTrustManager trustManager = getX509TrustManager(finalTrustManagerSupplier.get()); - Provider[] providers = filterProviders(providersSupplier.get(), providerName); + X509ExtendedKeyManager keyManager = getX509KeyManager(keyManagerInjector.getOptionalValue()); + X509ExtendedTrustManager trustManager = getX509TrustManager(trustManagerInjector.getOptionalValue()); + Provider[] providers = filterProviders(providersInjector.getOptionalValue(), providerName); DomainlessSSLContextBuilder builder = new DomainlessSSLContextBuilder(); if (keyManager != null) builder.setKeyManager(keyManager); @@ -1234,75 +1230,122 @@ protected void installedForResource(ServiceController serviceControl return createSSLContextDefinition(Constants.SERVER_SSL_CONTEXT, true, add, attributes, serverOrHostController); } + // TODO: Add SNI + /* static ResourceDefinition getServerSNISSLContextDefinition() { - private static ExceptionSupplier createTrustManager(ServiceBuilder serviceBuilder, OperationContext context, ModelNode model, - Supplier pathManager, - Supplier providersSupplier) throws OperationFailedException { - final String algorithmName = ALGORITHM.resolveModelAttribute(context, model).asStringOrNull(); - final String aliasFilter = ALIAS_FILTER.resolveModelAttribute(context, model).asStringOrNull(); - final String providerName = PROVIDER_NAME.resolveModelAttribute(context, model).asStringOrNull(); - - final ModelNode keyStoreObject = keystoreTMObjectDefinition.resolveModelAttribute(context, model); - final String keyStoreName = keystoreTMDefinition.resolveModelAttribute(context, model).asStringOrNull(); - ExceptionSupplier keyStoreSupplier; + AttributeDefinition[] attributes = new AttributeDefinition[] { DEFAULT_SSL_CONTEXT, HOST_CONTEXT_MAP }; - if (keyStoreName != null) { - if (keyStoreObject != null) { - throw LOGGER.multipleKeystoreDefinitions(); - } - keyStoreSupplier = new SSLContextExceptionSupplier<>(KEY_STORE_CAPABILITY, KeyStore.class, serviceBuilder, context, keyStoreName); - } else { - if (keyStoreObject == null) { - throw LOGGER.missingKeyStoreDefinition(); - } - keyStoreSupplier = createKeyStore(serviceBuilder, context, keyStoreObject, pathManager, providersSupplier); - } + AbstractAddStepHandler add = new TrivialAddHandler(SSLContext.class, attributes, SSL_CONTEXT_RUNTIME_CAPABILITY) { - final String algorithm = algorithmName != null ? algorithmName : TrustManagerFactory.getDefaultAlgorithm(); + @Override + protected ValueSupplier getValueSupplier(ServiceBuilder serviceBuilder, + OperationContext context, ModelNode model) throws OperationFailedException { - if (model.hasDefined(CERTIFICATE_REVOCATION_LIST.getName()) || model.hasDefined(OCSP.getName()) || model.hasDefined(CERTIFICATE_REVOCATION_LISTS.getName())) { - return createX509RevocationTrustManager(serviceBuilder, context, model, algorithm, providerName, keyStoreSupplier, aliasFilter, pathManager); - } + final InjectedValue defaultContext = new InjectedValue<>(); - DelegatingTrustManager delegatingTrustManager = new DelegatingTrustManager(); - return () -> { - Provider[] providers = providersSupplier.get(); - - TrustManagerFactory trustManagerFactory = createTrustManagerFactory(providers, providerName, algorithm); - KeyStore keyStore = keyStoreSupplier.get(); + ModelNode defaultContextName = DEFAULT_SSL_CONTEXT.resolveModelAttribute(context, model); + serviceBuilder.addDependency(SSL_CONTEXT_RUNTIME_CAPABILITY.getCapabilityServiceName(defaultContextName.asString()), SSLContext.class, defaultContext); - try { - if (aliasFilter != null) { - keyStore = FilteringKeyStore.filteringKeyStore(keyStore, AliasFilter.fromString(aliasFilter)); - } + ModelNode hostContextMap = HOST_CONTEXT_MAP.resolveModelAttribute(context, model); - if (LOGGER.isTraceEnabled()) { - LOGGER.tracef( - "TrustManager supplying: providers = %s provider = %s algorithm = %s trustManagerFactory = %s keyStoreName = %s keyStore = %s aliasFilter = %s keyStoreSize = %d", - Arrays.toString(providers), providerName, algorithm, trustManagerFactory, keyStoreName, keyStore, aliasFilter, keyStore.size() - ); - } - - trustManagerFactory.init(keyStoreSupplier.get()); - } catch (Exception e) { - throw new StartException(e); - } + Set keys; + if (hostContextMap.isDefined() && !(keys = hostContextMap.keys()).isEmpty()) { + final Map> sslContextMap = new HashMap<>(keys.size()); + for (String host : keys) { + String sslContextName = hostContextMap.require(host).asString(); + final InjectedValue injector = new InjectedValue<>(); + serviceBuilder.addDependency(SSL_CONTEXT_RUNTIME_CAPABILITY.getCapabilityServiceName(sslContextName), SSLContext.class, injector); + sslContextMap.put(host, injector); + } - TrustManager[] trustManagers = trustManagerFactory.getTrustManagers(); - for (TrustManager trustManager : trustManagers) { - if (trustManager instanceof X509ExtendedTrustManager) { - delegatingTrustManager.setTrustManager((X509ExtendedTrustManager) trustManager); - return delegatingTrustManager; - } - } - throw LOGGER.noTypeFound(X509ExtendedKeyManager.class.getSimpleName()); + return () -> { + SNIContextMatcher.Builder builder = new SNIContextMatcher.Builder(); + for(Map.Entry> e : sslContextMap.entrySet()) { + builder.addMatch(e.getKey(), e.getValue().getValue()); + } + return new SNISSLContext(builder + .setDefaultContext(defaultContext.getValue()) + .build()); + }; + return () -> defaultContext.getValue(); }; + + Builder builder = TrivialResourceDefinition.builder() + .setPathKey(ElytronDescriptionConstants.SERVER_SSL_SNI_CONTEXT) + .setAddHandler(add) + .setAttributes(attributes) + .setRuntimeCapabilities(SSL_CONTEXT_RUNTIME_CAPABILITY); + return builder.build(); + } */ + + private static ExceptionSupplier createTrustManager(ServiceBuilder serviceBuilder, OperationContext context, ModelNode model, + InjectedValue providersInjector) throws OperationFailedException { + final String algorithmName = ALGORITHM.resolveModelAttribute(context, model).asStringOrNull(); + final String aliasFilter = ALIAS_FILTER.resolveModelAttribute(context, model).asStringOrNull(); + final String providerName = PROVIDER_NAME.resolveModelAttribute(context, model).asStringOrNull(); + + // final ModelNode keyStoreObject = keystoreTMObjectDefinition.resolveModelAttribute(context, model); + final String keyStoreName = keystoreTMDefinition.resolveModelAttribute(context, model).asStringOrNull(); + InjectedValue keyStoreInjector = new InjectedValue<>(); + + if (keyStoreName != null) { + /* if (keyStoreObject.isDefined()) { + throw LOGGER.multipleKeyStoreDefinitions(); + } */ + serviceBuilder.addDependency(context.getCapabilityServiceName( + buildDynamicCapabilityName(KEY_STORE_CAPABILITY, keyStoreName), KeyStore.class), + KeyStore.class, keyStoreInjector); + /* } else { + if (!keyStoreObject.isDefined()) { + LOGGER.missingKeyStoreDefinition(); + } + keyStoreInjector = createKeyStore(serviceBuilder, context, keyStoreObject, providersInjector); */ + } + + final String algorithm = algorithmName != null ? algorithmName : TrustManagerFactory.getDefaultAlgorithm(); + + if (model.hasDefined(CERTIFICATE_REVOCATION_LIST.getName()) || model.hasDefined(OCSP.getName()) || model.hasDefined(CERTIFICATE_REVOCATION_LISTS.getName())) { + return createX509RevocationTrustManager(serviceBuilder, context, model, algorithm, providerName, providersInjector, keyStoreInjector, aliasFilter); + } + + DelegatingTrustManager delegatingTrustManager = new DelegatingTrustManager(); + return () -> { + Provider[] providers = providersInjector.getOptionalValue(); + + TrustManagerFactory trustManagerFactory = createTrustManagerFactory(providers, providerName, algorithm); + KeyStore keyStore = keyStoreInjector.getOptionalValue(); + + try { + if (aliasFilter != null) { + keyStore = FilteringKeyStore.filteringKeyStore(keyStore, AliasFilter.fromString(aliasFilter)); + } + + if (LOGGER.isTraceEnabled()) { + LOGGER.tracef( + "TrustManager supplying: providers = %s provider = %s algorithm = %s trustManagerFactory = %s keyStoreName = %s keyStore = %s aliasFilter = %s keyStoreSize = %d", + Arrays.toString(providers), providerName, algorithm, trustManagerFactory, keyStoreName, keyStore, aliasFilter, keyStore.size() + ); + } + + trustManagerFactory.init(keyStoreInjector.getOptionalValue()); + } catch (Exception e) { + throw new StartException(e); + } + + TrustManager[] trustManagers = trustManagerFactory.getTrustManagers(); + for (TrustManager trustManager : trustManagers) { + if (trustManager instanceof X509ExtendedTrustManager) { + delegatingTrustManager.setTrustManager((X509ExtendedTrustManager) trustManager); + return delegatingTrustManager; + } + } + throw LOGGER.noTypeFound(X509ExtendedKeyManager.class.getSimpleName()); + }; } private static ExceptionSupplier createX509RevocationTrustManager(ServiceBuilder serviceBuilder, OperationContext context, - ModelNode model, String algorithm, String providerName, ExceptionSupplier keyStoreSupplier, - String aliasFilter, Supplier pathManager) throws OperationFailedException { - + ModelNode model, String algorithm, String providerName, InjectedValue providersInjector, + InjectedValue keyStoreInjector, String aliasFilter) throws OperationFailedException { ModelNode crlNode = CERTIFICATE_REVOCATION_LIST.resolveModelAttribute(context, model); ModelNode ocspNode = OCSP.resolveModelAttribute(context, model); ModelNode multipleCrlsNode = CERTIFICATE_REVOCATION_LISTS.resolveModelAttribute(context, model); @@ -1310,8 +1353,20 @@ private static ExceptionSupplier createX509RevocationTr boolean onlyLeafCert = ONLY_LEAF_CERT.resolveModelAttribute(context, model).asBoolean(); Integer maxCertPath = MAXIMUM_CERT_PATH.resolveModelAttribute(context, model).asIntOrNull(); + //BW compatibility, max cert path is now in trust-manager + @Deprecated + Integer crlCertPath = MAXIMUM_CERT_PATH_CRL.resolveModelAttribute(context, crlNode).asIntOrNull(); + if (crlCertPath != null) { + LOGGER.warn("maximum-cert-path in certificate-revocation-list is for legacy support. Please use only the one in trust-manager!"); + if (maxCertPath != null) { + throw LOGGER.multipleMaximumCertPathDefinitions(); + } + maxCertPath = crlCertPath; + } + String crlPath; String crlRelativeTo; + InjectedValue pathManagerInjector = new InjectedValue<>(); List crlFiles = new ArrayList<>(); if (crlNode.isDefined()) { @@ -1319,14 +1374,24 @@ private static ExceptionSupplier createX509RevocationTr crlRelativeTo = RELATIVE_TO.resolveModelAttribute(context, crlNode).asStringOrNull(); if (crlPath != null) { - crlFiles.add(new CrlFile(crlPath, crlRelativeTo, pathManager)); + if (crlRelativeTo != null) { + serviceBuilder.addDependency(PathManagerService.SERVICE_NAME, PathManager.class, pathManagerInjector); + serviceBuilder.requires(pathName(crlRelativeTo)); + } + crlFiles.add(new CrlFile(crlPath, crlRelativeTo, pathManagerInjector)); } } else if (multipleCrlsNode.isDefined()) { + // certificate-revocation-lists and certificate-revocation-list are mutually exclusive for (ModelNode crl : multipleCrlsNode.asList()) { crlPath = PATH.resolveModelAttribute(context, crl).asStringOrNull(); crlRelativeTo = RELATIVE_TO.resolveModelAttribute(context, crl).asStringOrNull(); + pathManagerInjector = new InjectedValue<>(); if (crlPath != null) { - crlFiles.add(new CrlFile(crlPath, crlRelativeTo, pathManager)); + if (crlRelativeTo != null) { + serviceBuilder.addDependency(PathManagerService.SERVICE_NAME, PathManager.class, pathManagerInjector); + serviceBuilder.requires(pathName(crlRelativeTo)); + } + crlFiles.add(new CrlFile(crlPath, crlRelativeTo, pathManagerInjector)); } } } @@ -1334,11 +1399,15 @@ private static ExceptionSupplier createX509RevocationTr boolean preferCrls = PREFER_CRLS.resolveModelAttribute(context, ocspNode).asBoolean(false); String responder = RESPONDER.resolveModelAttribute(context, ocspNode).asStringOrNull(); String responderCertAlias = RESPONDER_CERTIFICATE.resolveModelAttribute(context, ocspNode).asStringOrNull(); - String responderKeystoreName = RESPONDER_KEYSTORE.resolveModelAttribute(context, ocspNode).asStringOrNull(); + String responderKeystore = RESPONDER_KEYSTORE.resolveModelAttribute(context, ocspNode).asStringOrNull(); - final ExceptionSupplier responderStoreSupplier = (responderKeystoreName != null) - ? new SSLContextExceptionSupplier<>(KEY_STORE_CAPABILITY, KeyStore.class, serviceBuilder, context, responderKeystoreName) - : keyStoreSupplier; + final InjectedValue responderStoreInjector = responderKeystore != null ? new InjectedValue<>() : keyStoreInjector; + + if (responderKeystore != null) { + serviceBuilder.addDependency(context.getCapabilityServiceName( + buildDynamicCapabilityName(KEY_STORE_CAPABILITY, responderKeystore), KeyStore.class), + KeyStore.class, responderStoreInjector); + } URI responderUri; try { @@ -1371,8 +1440,8 @@ private static ExceptionSupplier createX509RevocationTr } final List finalCrlFiles = crlFiles; return () -> { - TrustManagerFactory trustManagerFactory = createTrustManagerFactory(Security.getProviders(), providerName, algorithm); - KeyStore keyStore = keyStoreSupplier.get(); + TrustManagerFactory trustManagerFactory = createTrustManagerFactory(providersInjector.getOptionalValue(), providerName, algorithm); + KeyStore keyStore = keyStoreInjector.getOptionalValue(); if (aliasFilter != null) { try { @@ -1383,7 +1452,7 @@ private static ExceptionSupplier createX509RevocationTr } if (responderCertAlias != null) { - KeyStore responderStore = responderStoreSupplier.get(); + KeyStore responderStore = responderStoreInjector.getOptionalValue(); try { builder.setOcspResponderCert((X509Certificate) responderStore.getCertificate(responderCertAlias)); } catch (KeyStoreException e) { @@ -1407,7 +1476,7 @@ private static List getCrlStreams(List crlFiles) throws St List crlStreams = new ArrayList<>(); for (CrlFile crl : crlFiles) { try { - crlStreams.add(new FileInputStream(resolveFileLocation(crl.getCrlPath(), crl.getRelativeTo(), crl.getPathManagerSupplier()))); + crlStreams.add(new FileInputStream(resolveFileLocation(crl.getCrlPath(), crl.getRelativeTo(), crl.getPathManagerInjector()))); } catch (FileNotFoundException e) { throw LOGGER.unableToAccessCRL(e); } @@ -1415,10 +1484,10 @@ private static List getCrlStreams(List crlFiles) throws St return crlStreams; } - private static File resolveFileLocation(String path, String relativeTo, Supplier pathManagerSupplier) { + private static File resolveFileLocation(String path, String relativeTo, InjectedValue pathManagerInjector) { final File resolvedPath; if (relativeTo != null) { - PathManager pathManager = pathManagerSupplier.get(); + PathManager pathManager = pathManagerInjector.getValue(); resolvedPath = new File(pathManager.resolveRelativePathEntry(path, relativeTo)); } else { resolvedPath = new File(path); @@ -1504,35 +1573,36 @@ public X509Certificate[] getAcceptedIssuers() { } private static ExceptionSupplier createKeyManager(ServiceBuilder serviceBuilder, OperationContext context, - ModelNode model, Supplier pathManagerSupplier, - Supplier providersSupplier) throws OperationFailedException { + ModelNode model, InjectedValue providersInjector) throws OperationFailedException { final ExceptionSupplier credentialSourceSupplier = CredentialReference.getCredentialSourceSupplier(context, CREDENTIAL_REFERENCE, model, serviceBuilder); final String algorithmName = ALGORITHM.resolveModelAttribute(context, model).asStringOrNull(); final String aliasFilter = ALIAS_FILTER.resolveModelAttribute(context, model).asStringOrNull(); final String generateSelfSignedCertificateHost = GENERATE_SELF_SIGNED_CERTIFICATE_HOST.resolveModelAttribute(context, model).asStringOrNull(); final String providerName = PROVIDER_NAME.resolveModelAttribute(context, model).asStringOrNull(); - final ModelNode keyStoreObject = keystoreKMObjectDefinition.resolveModelAttribute(context, model); + // final ModelNode keyStoreObject = keystoreKMObjectDefinition.resolveModelAttribute(context, model); final String keyStoreName = keystoreKMDefinition.resolveModelAttribute(context, model).asStringOrNull(); final ModifiableKeyStoreService keyStoreService = getModifiableKeyStoreService(context, keyStoreName); - ExceptionSupplier keyStoreSupplier; + InjectedValue keyStoreInjector = new InjectedValue<>(); if (keyStoreName != null) { - if (keyStoreObject != null) { - throw LOGGER.multipleKeystoreDefinitions(); - } - keyStoreSupplier = new SSLContextExceptionSupplier<>(KEY_STORE_CAPABILITY, KeyStore.class, serviceBuilder, context, keyStoreName); - } else { - if (keyStoreObject == null) { + /* if (keyStoreObject.isDefined()) { + throw LOGGER.multipleKeyStoreDefinitions(); + } */ + serviceBuilder.addDependency(context.getCapabilityServiceName( + buildDynamicCapabilityName(KEY_STORE_CAPABILITY, keyStoreName), KeyStore.class), + KeyStore.class, keyStoreInjector); + /* } else { + if (!keyStoreObject.isDefined()) { throw LOGGER.missingKeyStoreDefinition(); } - keyStoreSupplier = createKeyStore(serviceBuilder, context, keyStoreObject, pathManagerSupplier, providersSupplier); + keyStoreInjector = createKeyStore(serviceBuilder, context, keyStoreObject, providersInjector); */ } final String algorithm = algorithmName == null ? algorithmName : KeyManagerFactory.getDefaultAlgorithm(); DelegatingKeyManager delegatingKeyManager = new DelegatingKeyManager(); return () -> { - Provider[] providers = providersSupplier.get(); + Provider[] providers = providersInjector.getOptionalValue(); KeyManagerFactory keyManagerFactory = null; if (providers != null) { for (Provider current : providers) { @@ -1554,14 +1624,15 @@ private static ExceptionSupplier createKeyManager(Service } } - KeyStore keyStore = keyStoreSupplier.get(); + KeyStore keyStore = keyStoreInjector.getOptionalValue(); char[] password; try { CredentialSource cs = credentialSourceSupplier.get(); if (cs != null) { password = cs.getCredential(PasswordCredential.class).getPassword(ClearPassword.class).getPassword(); } else { - throw new StartException(LOGGER.keyStorePasswordCannotBeResolved(keyStoreName == null ? keyStoreObject.asStringOrNull() : keyStoreName)); + // throw new StartException(LOGGER.keyStorePasswordCannotBeResolved(keyStoreName == null ? keyStoreObject.asStringOrNull() : keyStoreName)); + throw new StartException(LOGGER.keyStorePasswordCannotBeResolved(keyStoreName)); } if (LOGGER.isTraceEnabled()) { LOGGER.tracef( @@ -1621,7 +1692,14 @@ private static X509ExtendedKeyManager getX509KeyManager(KeyManager keyManager) t return null; } if (keyManager instanceof X509ExtendedKeyManager) { - return (X509ExtendedKeyManager) keyManager; + X509ExtendedKeyManager x509KeyManager = (X509ExtendedKeyManager) keyManager; + // TODO: add FIPS + /* if (x509KeyManager instanceof DelegatingKeyManager && IS_FIPS.getAsBoolean()) { + LOGGER.trace("FIPS enabled on JVM, unwrapping KeyManager"); + // If FIPS is enabled unwrap the KeyManager + x509KeyManager = ((DelegatingKeyManager) x509KeyManager).delegating.get(); + } */ + return x509KeyManager; } throw LOGGER.invalidTypeInjected(X509ExtendedKeyManager.class.getSimpleName()); } @@ -1734,13 +1812,18 @@ private static X509ExtendedTrustManager getX509TrustManager(TrustManager trustMa if (trustManager == null) { return null; } - if (trustManager instanceof X509ExtendedTrustManager) { - return (X509ExtendedTrustManager) trustManager; + if (trustManager instanceof X509ExtendedKeyManager) { + X509ExtendedTrustManager x509TrustManager = (X509ExtendedTrustManager) trustManager; + // TODO: add FIPS + /* if (x509TrustManager instanceof DelegatingTrustManager && IS_FIPS.getAsBoolean()) { + ROOT_LOGGER.trace("FIPS enabled on JVM, unwrapping TrustManager"); + x509TrustManager = ((DelegatingTrustManager)x509TrustManager).delegating.get(); + } */ + return x509TrustManager; } throw LOGGER.invalidTypeInjected(X509ExtendedTrustManager.class.getSimpleName()); } - private abstract static class ReloadableX509ExtendedTrustManager extends X509ExtendedTrustManager { abstract void reload(); } @@ -1838,121 +1921,47 @@ public String chooseEngineServerAlias(String keyType, Principal[] issuers, SSLEn } } + //TODO: correctly implement creating new key stores private static ExceptionSupplier createKeyStore(ServiceBuilder serviceBuilder, OperationContext context, - ModelNode model, Supplier pathManager, - Supplier providersSupplier) throws OperationFailedException { - final String providerName = PROVIDER_NAME.resolveModelAttribute(context, model).asStringOrNull(); - final String type = TYPE.resolveModelAttribute(context, model).asStringOrNull(); - final String aliasFilter = ALIAS_FILTER.resolveModelAttribute(context, model).asStringOrNull(); - final String path = PATH.resolveModelAttribute(context, model).asStringOrNull(); - final String relativeTo = RELATIVE_TO.resolveModelAttribute(context, model).asStringOrNull(); - final boolean required = REQUIRED.resolveModelAttribute(context, model).asBoolean(false); - final ExceptionSupplier credentialSourceSupplier = CredentialReference.getCredentialSourceSupplier(context, CREDENTIAL_REFERENCE, model, serviceBuilder); - - return () -> { - AtomicLoadKeyStore keyStore = null; - FileAttributeDefinitions.PathResolver pathResolver; - File resolvedPath = null; - Provider provider = null; - - if (type != null) { - provider = resolveProviders(providerName, KeyStore.class, type, providersSupplier.get()); - keyStore = AtomicLoadKeyStore.newInstance(type, provider); - } - - if (path != null) { - pathResolver = pathResolver(); - pathResolver.path(path); - if (relativeTo != null) { - pathResolver.relativeTo(relativeTo, pathManager.get()); - } - resolvedPath = pathResolver.resolve(); - } + ModelNode model, InjectedValue providersInjector) throws OperationFailedException { return null; } - if (resolvedPath != null && ! resolvedPath.exists()) { - if (required) { - if (type == null) { - throw LOGGER.nonexistingKeyStoreMissingType(); - } else { - throw LOGGER.keyStoreFileNotExists(resolvedPath.getAbsolutePath()); - } - } else { - LOGGER.keyStoreFileNotExistsButIgnored(resolvedPath.getAbsolutePath()); - } - } - - try (FileInputStream is = (resolvedPath != null && resolvedPath.exists()) ? new FileInputStream(resolvedPath) : null) { - CredentialSource cs = credentialSourceSupplier != null ? credentialSourceSupplier.get() : null; - if (cs == null) { - throw LOGGER.keyStorePasswordCannotBeResolved(path); - } - PasswordCredential credential = cs.getCredential(PasswordCredential.class); - if (credential == null) { - throw LOGGER.keyStorePasswordCannotBeResolved(path); - } - ClearPassword clearPassword = credential.getPassword(ClearPassword.class); - if (clearPassword == null) { - throw LOGGER.keyStorePasswordCannotBeResolved(path); - } - - char[] password = clearPassword.getPassword(); - - LOGGER.tracef( - "starting: type = %s provider = %s path = %s resolvedPath = %s password = %b aliasFilter = %s", - type, provider, path, resolvedPath, password != null, aliasFilter - ); - - if (is != null) { - if (type != null) { - keyStore.load(is, password); - } else { - Provider[] resolvedProviders = providersSupplier.get(); - Provider[] finalProviders = resolvedProviders == null ? Security.getProviders() : resolvedProviders; - KeyStore detected = KeyStoreUtil.loadKeyStore(() -> finalProviders, providerName, is, resolvedPath.getPath(), password); - - if (detected == null) { - throw LOGGER.unableToDetectKeyStore(resolvedPath.getPath()); - } - - keyStore = AtomicLoadKeyStore.atomize(detected); - } - } else { - if (keyStore == null) { - String defaultType = KeyStore.getDefaultType(); - LOGGER.debugf("KeyStore: provider = %s path = %s resolvedPath = %s password = %b aliasFilter = %s does not exist. New keystore of %s type will be created.", - provider, path, resolvedPath, password != null, aliasFilter, defaultType - ); - keyStore = AtomicLoadKeyStore.newInstance(defaultType); - } - - synchronized (EmptyProvider.getInstance()) { - keyStore.load(null, password); - } - } - } - return keyStore; - }; + // Derives dynamic name from provided attribute + private static InjectedValue addSSLContextDependency(String baseName, SimpleAttributeDefinition attribute, + Class type, ServiceBuilder serviceBuilder, OperationContext context, ModelNode model) throws OperationFailedException { + String dynamicNameElement = attribute.resolveModelAttribute(context, model).asStringOrNull(); + InjectedValue injectedValue = new InjectedValue<>(); + if (dynamicNameElement != null) { + serviceBuilder.addDependency(context.getCapabilityServiceName( + buildDynamicCapabilityName(baseName, dynamicNameElement), type), + type, injectedValue); + } + return injectedValue; } - private static Provider resolveProviders(String name, Class type, String alg, Provider[] candidates) throws StartException { - Supplier resolveProvidersSupplier = () -> candidates == null ? Security.getProviders() : candidates; - Provider provider = ProviderUtil.findProvider(resolveProvidersSupplier, name, type, alg); - if (provider == null) { - throw LOGGER.noSuitableProvider(alg); + private static InjectedValue addKeyManagerDependency(String baseName, SimpleAttributeDefinition attribute, + Class type, ServiceBuilder serviceBuilder, OperationContext context, ModelNode model) throws OperationFailedException { + String dynamicNameElement = attribute.resolveModelAttribute(context, model).asStringOrNull(); + InjectedValue injectedValue = new InjectedValue<>(); + + if (dynamicNameElement != null) { + serviceBuilder.addDependency(context.getCapabilityServiceName( + buildDynamicCapabilityName(baseName, dynamicNameElement), type), + type, injectedValue); } - return provider; + return injectedValue; } - // Derives dynamic name from provided attribute - private static Supplier addRequirement(String baseName, Class type, ServiceBuilder serviceBuilder, - OperationContext context, String dynamicNameElement) { - Supplier supplier = () -> null; + private static InjectedValue addTrustManagerDependency(String baseName, SimpleAttributeDefinition attribute, + Class type, ServiceBuilder serviceBuilder, OperationContext context, ModelNode model) throws OperationFailedException { + String dynamicNameElement = attribute.resolveModelAttribute(context, model).asStringOrNull(); + InjectedValue injectedValue = new InjectedValue<>(); if (dynamicNameElement != null) { - supplier = serviceBuilder.requires(context.getCapabilityServiceName( - buildDynamicCapabilityName(baseName, dynamicNameElement), type)); + serviceBuilder.addDependency(context.getCapabilityServiceName( + buildDynamicCapabilityName(baseName, dynamicNameElement), type), + type, injectedValue); } - return supplier; + return injectedValue; } private static Provider[] filterProviders(Provider[] all, String provider) { @@ -1966,25 +1975,6 @@ private static Provider[] filterProviders(Provider[] all, String provider) { return list.toArray(new Provider[0]); } - /** - * A supplier that throws exceptions, and can be constructed from {@link ServiceBuilder} or {@link ExceptionSupplier}. - */ - private static class SSLContextExceptionSupplier implements ExceptionSupplier { - private final Supplier supplier; - private final ExceptionSupplier exceptionSupplier; - - SSLContextExceptionSupplier (String baseName, Class type, ServiceBuilder serviceBuilder, - OperationContext context, String dynamicModelElement) { - this.supplier = addRequirement(baseName, type, serviceBuilder, context, dynamicModelElement); - this.exceptionSupplier = this.supplier::get; - } - - @Override - public T get() throws E { - return exceptionSupplier.get(); - } - } - abstract static class SSLContextRuntimeHandler extends ElytronRuntimeOnlyHandler { @Override protected void executeRuntimeStep(OperationContext context, ModelNode operation) throws OperationFailedException { @@ -2004,6 +1994,31 @@ protected void executeRuntimeStep(OperationContext context, ModelNode operation) protected abstract ServiceUtil getSSLContextServiceUtil(); } + // TODO: add FIPS + /* private static BooleanSupplier getFipsSupplier() { + try { + final Class providerClazz = SSLDefinitions.class.getClassLoader().loadClass("com.sun.net.ssl.internal.ssl.Provider"); + final Method isFipsMethod = providerClazz.getMethod("isFIPS", new Class[0]); + + Object isFips; + try { + isFips = isFipsMethod.invoke(null, new Object[0]); + if ((isFips instanceof Boolean)) { + return () -> (boolean) isFips; + } else { + return () -> false; + } + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + LOGGER.trace("Unable to invoke com.sun.net.ssl.internal.ssl.Provider.isFIPS() method.", e); + return () -> false; + } + } catch (ClassNotFoundException | NoSuchMethodException | SecurityException e) { + LOGGER.trace("Unable to find com.sun.net.ssl.internal.ssl.Provider.isFIPS() method.", e); + } + + return () -> new SecureRandom().getProvider().getName().toLowerCase().contains("fips"); + } */ + static ModifiableKeyStoreService getModifiableKeyStoreService(OperationContext context, String keyStoreName) { ServiceRegistry serviceRegistry = context.getServiceRegistry(true); RuntimeCapability runtimeCapability = KEY_STORE_RUNTIME_CAPABILITY.fromBaseCapability(keyStoreName); @@ -2012,15 +2027,19 @@ static ModifiableKeyStoreService getModifiableKeyStoreService(OperationContext c return (ModifiableKeyStoreService) serviceContainer.getService(); } + /** + * CrlFile contains the necessary information to create a + * CRL File Input Stream + */ static class CrlFile { private final String crlPath; private final String relativeTo; - private final Supplier pathManagerSupplier; + private final InjectedValue pathManagerInjector; - public CrlFile(final String crlPath, final String relativeTo, Supplier pathManagerSupplier) { + public CrlFile(final String crlPath, final String relativeTo, InjectedValue pathManagerInjector) { this.crlPath = crlPath; this.relativeTo = relativeTo; - this.pathManagerSupplier = pathManagerSupplier; + this.pathManagerInjector = pathManagerInjector; } public String getCrlPath() { @@ -2031,8 +2050,8 @@ public String getRelativeTo() { return relativeTo; } - public Supplier getPathManagerSupplier() { - return pathManagerSupplier; + public InjectedValue getPathManagerInjector() { + return pathManagerInjector; } } diff --git a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/SecretKeyCredentialStoreDefinition.java b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/SecretKeyCredentialStoreDefinition.java index 01bc163..ac839c1 100644 --- a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/SecretKeyCredentialStoreDefinition.java +++ b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/SecretKeyCredentialStoreDefinition.java @@ -16,7 +16,6 @@ package org.wildfly.extension.elytron.tls.subsystem; -import static org.jboss.as.controller.AbstractControllerService.PATH_MANAGER_CAPABILITY; import static org.wildfly.extension.elytron.tls.subsystem.Capabilities.CREDENTIAL_STORE_API_CAPABILITY; import static org.wildfly.extension.elytron.tls.subsystem.Capabilities.CREDENTIAL_STORE_RUNTIME_CAPABILITY; import static org.wildfly.extension.elytron.tls.subsystem.ElytronTlsExtension.isServerOrHostController; @@ -30,6 +29,7 @@ import java.security.GeneralSecurityException; import java.util.HashMap; import java.util.Map; +import java.util.function.Supplier; import javax.crypto.SecretKey; @@ -49,6 +49,7 @@ import org.jboss.as.controller.descriptions.StandardResourceDescriptionResolver; import org.jboss.as.controller.registry.ManagementResourceRegistration; import org.jboss.as.controller.registry.OperationEntry; +import org.jboss.as.controller.services.path.PathManagerService; import org.jboss.dmr.ModelNode; import org.jboss.dmr.ModelType; import org.jboss.msc.service.StartException; @@ -236,13 +237,14 @@ protected void resolveRuntime(ModelNode model, OperationContext context) throws @Override protected ExceptionSupplier prepareServiceSupplier(OperationContext context, - CapabilityServiceBuilder serviceBuilder) { + CapabilityServiceBuilder serviceBuilder) { + final Supplier pathManager; if (relativeTo != null) { - pathManagerSupplier = serviceBuilder.requires(PATH_MANAGER_CAPABILITY.getCapabilityServiceName()); + pathManager = serviceBuilder.requires(PathManagerService.SERVICE_NAME); serviceBuilder.requires(pathName(relativeTo)); } else { - pathManagerSupplier = null; + pathManager = null; } return new ExceptionSupplier() { @@ -253,7 +255,7 @@ public CredentialStore get() throws StartException { PathResolver pathResolver = pathResolver(); pathResolver.path(path); if (relativeTo != null) { - pathResolver.relativeTo(relativeTo, pathManagerSupplier.get()); + pathResolver.relativeTo(relativeTo, pathManager.get()); } File resolved = pathResolver.resolve(); pathResolver.clear(); diff --git a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/SecurityPropertiesWriteHandler.java b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/SecurityPropertiesWriteHandler.java index 423ecc9..416509e 100644 --- a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/SecurityPropertiesWriteHandler.java +++ b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/SecurityPropertiesWriteHandler.java @@ -32,7 +32,7 @@ /** * @author Tomaz Cerar (c) 2017 Red Hat Inc. */ -class SecurityPropertiesWriteHandler extends AbstractWriteAttributeHandler{ +class SecurityPropertiesWriteHandler extends AbstractWriteAttributeHandler { private final PropertiesAttributeDefinition securityProperties; SecurityPropertiesWriteHandler(PropertiesAttributeDefinition attributeDefinition) { @@ -64,7 +64,7 @@ private static void removeProperty(OperationContext context, String name) { } @Override - protected boolean applyUpdateToRuntime(OperationContext context, ModelNode operation, String attributeName, ModelNode resolvedValue, ModelNode currentValue, HandbackHolder handbackHolder) throws OperationFailedException { + protected boolean applyUpdateToRuntime(OperationContext context, ModelNode operation, String attributeName, ModelNode resolvedValue, ModelNode currentValue, HandbackHolder handbackHolder) throws OperationFailedException { Map newProps = securityProperties.unwrap(context, resolvedValue); Map oldProps = securityProperties.unwrap(context, currentValue); setProperties(context, newProps, oldProps); @@ -92,7 +92,7 @@ private void setProperties(final OperationContext context, Map n } @Override - protected void revertUpdateToRuntime(OperationContext context, ModelNode operation, String attributeName, ModelNode valueToRestore, ModelNode valueToRevert, Void handback) throws OperationFailedException { + protected void revertUpdateToRuntime(OperationContext context, ModelNode operation, String attributeName, ModelNode valueToRestore, ModelNode valueToRevert, Object handback) throws OperationFailedException { Map newProps = securityProperties.unwrap(context, valueToRestore); Map oldProps = securityProperties.unwrap(context, valueToRevert); setProperties(context, newProps, oldProps); diff --git a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/SecurityPropertyService.java b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/SecurityPropertyService.java index c06a0f9..77a0073 100644 --- a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/SecurityPropertyService.java +++ b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/SecurityPropertyService.java @@ -27,7 +27,7 @@ import java.util.Map; import java.util.Properties; -import org.jboss.msc.Service; +import org.jboss.msc.service.Service; import org.jboss.msc.service.ServiceName; import org.jboss.msc.service.StartContext; import org.jboss.msc.service.StartException; @@ -41,7 +41,7 @@ * * @author Darran Lofthouse */ -class SecurityPropertyService implements Service { +class SecurityPropertyService implements Service { static final ServiceName SERVICE_NAME = ElytronTlsExtension.BASE_SERVICE_NAME.append(Constants.SECURITY_PROPERTIES); @@ -86,6 +86,11 @@ public synchronized void stop(StopContext context) { started = false; } + @Override + public Void getValue() throws IllegalStateException, IllegalArgumentException { + return null; + } + private void restoreProperty(String name, String restorationValue) { if (restorationValue == null) { try { diff --git a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/TrivialService.java b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/TrivialService.java index 85dc497..43a4f68 100644 --- a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/TrivialService.java +++ b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/TrivialService.java @@ -58,11 +58,7 @@ void setValueSupplier(ValueSupplier valueSupplier) { @Override public void start(StartContext context) throws StartException { - try { - value = checkNotNullParam("valueSupplier", valueSupplier).get(); - } catch (Exception e) { - throw new StartException(e); - } + value = checkNotNullParam("valueSupplier", valueSupplier).get(); if (valueConsumer != null) { valueConsumer.accept(value); } @@ -86,7 +82,7 @@ public T getValue() throws IllegalStateException, IllegalArgumentException { @FunctionalInterface interface ValueSupplier { - T get() throws Exception; + T get() throws StartException; default void dispose() {} diff --git a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/TrustManagerBuilder.java b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/TrustManagerBuilder.java deleted file mode 100644 index 9c4310b..0000000 --- a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/TrustManagerBuilder.java +++ /dev/null @@ -1,51 +0,0 @@ - /* - * Copyright 2022 Red Hat, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.wildfly.extension.elytron.tls.subsystem; - -import java.security.KeyStore; - -import javax.net.ssl.TrustManager; - -import org.wildfly.common.function.ExceptionSupplier; - -public class TrustManagerBuilder { - private ExceptionSupplier keyStoreSupplier; - private String keyStoreReferenceName; - private String aliasFilter; - private String algorithm; - private int maximumCertPath; - private boolean onlyLeafCert; - private boolean softFail; - private String providerName; - - private String ocspResponder; - private boolean preferCrls; - private String responderCertificate; - private ExceptionSupplier responderKeyStore; - - - public TrustManagerBuilder() { - - } - - public TrustManager build() { - - - return null; - } - -} diff --git a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/Validators.java b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/Validators.java index 9040f6a..7c81eba 100644 --- a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/Validators.java +++ b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/subsystem/Validators.java @@ -18,8 +18,12 @@ import static org.wildfly.extension.elytron.tls.subsystem._private.ElytronTLSLogger.LOGGER; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + import org.jboss.as.controller.OperationFailedException; import org.jboss.as.controller.operations.validation.ModelTypeValidator; +import org.jboss.as.controller.operations.validation.ParameterValidator; import org.jboss.dmr.ModelNode; import org.jboss.dmr.ModelType; import org.wildfly.security.ssl.CipherSuiteSelector; @@ -63,4 +67,31 @@ public void validateParameter(String parameterName, ModelNode value) throws Oper } } } + + static class HostContextMapValidator implements ParameterValidator { + // Hostnames can contain ASCII letters a-z (case-insensitive), digits 0-9, hyphens and dots. + // This pattern allows also [,],*,? characters to make regular expressions possible. Non-escaped dot represents any character, escaped dot is delimeter. + static Pattern hostnameRegexPattern = Pattern.compile("[0-9a-zA-Z\\[.*]" + // first character can be digit, letter, left square bracket, non-escaped dot or asterisk + "([0-9a-zA-Z*.\\[\\]?^-]" + // any combination of digits, letters, asterisks, non-escaped dots, square brackets, question marks, hyphens and carets + "|" + // OR + "(? nodes = assertSuccess(services.executeOperation(operation)).get(ClientConstants.RESULT).asList(); assertEquals(2, nodes.size()); operation = new ModelNode(); operation.get(ClientConstants.OPERATION_HEADERS).get("allow-resource-service-restart").set(Boolean.TRUE); - operation.get(ClientConstants.OP_ADDR).add("subsystem","elytron").add("key-store","ModifiedKeyStore"); + operation.get(ClientConstants.OP_ADDR).add("subsystem","elytron-tls").add("key-store","ModifiedKeyStore"); operation.get(ClientConstants.OP).set(Constants.REMOVE_ALIAS); operation.get(Constants.ALIAS).set("ca"); assertSuccess(services.executeOperation(operation)); operation = new ModelNode(); - operation.get(ClientConstants.OP_ADDR).add("subsystem","elytron").add("key-store","ModifiedKeyStore"); + operation.get(ClientConstants.OP_ADDR).add("subsystem","elytron-tls").add("key-store","ModifiedKeyStore"); operation.get(ClientConstants.OP).set(Constants.READ_ALIASES); nodes = assertSuccess(services.executeOperation(operation)).get(ClientConstants.RESULT).asList(); assertEquals(1, nodes.size()); operation = new ModelNode(); // remove keystore operation.get(ClientConstants.OPERATION_HEADERS).get("allow-resource-service-restart").set(Boolean.TRUE); - operation.get(ClientConstants.OP_ADDR).add("subsystem","elytron").add("key-store","ModifiedKeyStore"); + operation.get(ClientConstants.OP_ADDR).add("subsystem","elytron-tls").add("key-store","ModifiedKeyStore"); operation.get(ClientConstants.OP).set(ClientConstants.REMOVE_OPERATION); assertSuccess(services.executeOperation(operation)); } @@ -439,7 +439,7 @@ public void testKeystoreReadVerbose() throws Exception { ModelNode operation = new ModelNode(); // add keystore operation.get(ClientConstants.OPERATION_HEADERS).get("allow-resource-service-restart").set(Boolean.TRUE); - operation.get(ClientConstants.OP_ADDR).add("subsystem","elytron").add("key-store", "ModifiedKeyStore"); + operation.get(ClientConstants.OP_ADDR).add("subsystem","elytron-tls").add("key-store", "ModifiedKeyStore"); operation.get(ClientConstants.OP).set(ClientConstants.ADD); operation.get(Constants.PATH).set(resources + "/firefly-copy.keystore"); operation.get(Constants.TYPE).set("JKS"); @@ -447,7 +447,7 @@ public void testKeystoreReadVerbose() throws Exception { assertSuccess(services.executeOperation(operation)); operation = new ModelNode(); - operation.get(ClientConstants.OP_ADDR).add("subsystem","elytron").add("key-store","ModifiedKeyStore"); + operation.get(ClientConstants.OP_ADDR).add("subsystem","elytron-tls").add("key-store","ModifiedKeyStore"); operation.get(ClientConstants.OP).set(Constants.READ_ALIASES); List nodes = assertSuccess(services.executeOperation(operation)).get(ClientConstants.RESULT).asList(); assertEquals(2, nodes.size()); @@ -459,7 +459,7 @@ public void testKeystoreReadVerbose() throws Exception { validateRecursiveReadAliases(false); operation = new ModelNode(); - operation.get(ClientConstants.OP_ADDR).add("subsystem","elytron").add("key-store","ModifiedKeyStore"); + operation.get(ClientConstants.OP_ADDR).add("subsystem","elytron-tls").add("key-store","ModifiedKeyStore"); operation.get(ClientConstants.OP).set(Constants.READ_ALIAS); operation.get(Constants.ALIAS).set("firefly"); operation.get(Constants.VERBOSE).set(false); @@ -468,7 +468,7 @@ public void testKeystoreReadVerbose() throws Exception { private void validateRecursiveReadAliases(final boolean verbose) { ModelNode operation = new ModelNode(); - operation.get(ClientConstants.OP_ADDR).add("subsystem","elytron").add("key-store","ModifiedKeyStore"); + operation.get(ClientConstants.OP_ADDR).add("subsystem","elytron-tls").add("key-store","ModifiedKeyStore"); operation.get(ClientConstants.OP).set(Constants.READ_ALIASES); operation.get(Constants.VERBOSE).set(verbose); operation.get(Constants.RECURSIVE).set(true); @@ -490,7 +490,7 @@ private void validateRecursiveReadAliases(final boolean verbose) { } final ModelNode readOperation = new ModelNode(); - readOperation.get(ClientConstants.OP_ADDR).add("subsystem","elytron").add("key-store","ModifiedKeyStore"); + readOperation.get(ClientConstants.OP_ADDR).add("subsystem","elytron-tls").add("key-store","ModifiedKeyStore"); readOperation.get(ClientConstants.OP).set(Constants.READ_ALIAS); readOperation.get(Constants.VERBOSE).set(verbose); readOperation.get(Constants.ALIAS).set(alias); @@ -539,25 +539,6 @@ public void testFilteringKeystoreService() throws Exception { assertFalse(keyStore.isCertificateEntry("ca")); } - @Test - public void testFilteringKeystoreCli() throws Exception { - ModelNode operation = new ModelNode(); - operation.get(ClientConstants.OP_ADDR).add("subsystem","elytron").add(Constants.FILTERING_KEY_STORE,"FilteringKeyStore"); - operation.get(ClientConstants.OP).set(Constants.READ_ALIASES); - List nodes = assertSuccess(services.executeOperation(operation)).get(ClientConstants.RESULT).asList(); - assertEquals(1, nodes.size()); - assertEquals("firefly", nodes.get(0).asString()); - - operation = new ModelNode(); - operation.get(ClientConstants.OP_ADDR).add("subsystem","elytron").add(Constants.FILTERING_KEY_STORE,"FilteringKeyStore"); - operation.get(ClientConstants.OP).set(Constants.READ_ALIAS); - operation.get(Constants.ALIAS).set("firefly"); - ModelNode firefly = assertSuccess(services.executeOperation(operation)).get(ClientConstants.RESULT); - assertEquals("firefly", firefly.get(Constants.ALIAS).asString()); - assertEquals(KeyStore.PrivateKeyEntry.class.getSimpleName(), firefly.get(Constants.ENTRY_TYPE).asString()); - assertTrue(firefly.get(Constants.CERTIFICATE_CHAIN).isDefined()); - } - @Test public void testAutomaticKeystoreService() throws Exception { ServiceName serviceName = Capabilities.KEY_STORE_RUNTIME_CAPABILITY.getCapabilityServiceName("AutomaticKeystore"); @@ -584,17 +565,17 @@ public void testAutomaticKeystoreService() throws Exception { @Test public void testAutomaticKeystoreCli() throws Exception { ModelNode operation = new ModelNode(); - operation.get(ClientConstants.OP_ADDR).add("subsystem","elytron"); + operation.get(ClientConstants.OP_ADDR).add("subsystem","elytron-tls"); operation.get(ClientConstants.OP).set("read-resource"); System.out.println(services.executeOperation(operation).get(ClientConstants.RESULT).asString()); operation = new ModelNode(); - operation.get(ClientConstants.OP_ADDR).add("subsystem","elytron").add(Constants.KEY_STORE,"AutomaticKeystore"); + operation.get(ClientConstants.OP_ADDR).add("subsystem","elytron-tls").add(Constants.KEY_STORE,"AutomaticKeystore"); operation.get(ClientConstants.OP).set(Constants.READ_ALIASES); List nodes = assertSuccess(services.executeOperation(operation)).get(ClientConstants.RESULT).asList(); assertEquals(2, nodes.size()); operation = new ModelNode(); - operation.get(ClientConstants.OP_ADDR).add("subsystem","elytron").add(Constants.KEY_STORE,"AutomaticKeystore"); + operation.get(ClientConstants.OP_ADDR).add("subsystem","elytron-tls").add(Constants.KEY_STORE,"AutomaticKeystore"); operation.get(ClientConstants.OP).set(Constants.READ_ALIAS); operation.get(Constants.ALIAS).set("firefly"); ModelNode firefly = assertSuccess(services.executeOperation(operation)).get(ClientConstants.RESULT); @@ -603,7 +584,7 @@ public void testAutomaticKeystoreCli() throws Exception { assertTrue(firefly.get(Constants.CERTIFICATE_CHAIN).isDefined()); operation = new ModelNode(); - operation.get(ClientConstants.OP_ADDR).add("subsystem","elytron").add(Constants.KEY_STORE,"AutomaticKeystore"); + operation.get(ClientConstants.OP_ADDR).add("subsystem","elytron-tls").add(Constants.KEY_STORE,"AutomaticKeystore"); operation.get(ClientConstants.OP).set(Constants.READ_ALIAS); operation.get(Constants.ALIAS).set("ca"); ModelNode ca = assertSuccess(services.executeOperation(operation)).get(ClientConstants.RESULT); @@ -1319,7 +1300,7 @@ private void addKeyStore(String keyStoreFile, String keyStoreName, String keySto Files.copy(resources.resolve(keyStoreFile), resources.resolve("test-copy.keystore"), java.nio.file.StandardCopyOption.REPLACE_EXISTING); ModelNode operation = new ModelNode(); operation.get(ClientConstants.OPERATION_HEADERS).get("allow-resource-service-restart").set(Boolean.TRUE); - operation.get(ClientConstants.OP_ADDR).add("subsystem","elytron").add("key-store", keyStoreName); + operation.get(ClientConstants.OP_ADDR).add("subsystem","elytron-tls").add("key-store", keyStoreName); operation.get(ClientConstants.OP).set(ClientConstants.ADD); operation.get(Constants.PATH).set(resources + "/test-copy.keystore"); operation.get(Constants.TYPE).set("JKS"); @@ -1337,7 +1318,7 @@ private void addOriginalKeyStore() throws Exception { Files.copy(resources.resolve("test-original.keystore"), resources.resolve("test-copy.keystore"), java.nio.file.StandardCopyOption.REPLACE_EXISTING); ModelNode operation = new ModelNode(); operation.get(ClientConstants.OPERATION_HEADERS).get("allow-resource-service-restart").set(Boolean.TRUE); - operation.get(ClientConstants.OP_ADDR).add("subsystem","elytron").add("key-store", KEYSTORE_NAME); + operation.get(ClientConstants.OP_ADDR).add("subsystem","elytron-tls").add("key-store", KEYSTORE_NAME); operation.get(ClientConstants.OP).set(ClientConstants.ADD); operation.get(Constants.PATH).set(resources + "/test-copy.keystore"); operation.get(Constants.TYPE).set("JKS"); @@ -1347,14 +1328,14 @@ private void addOriginalKeyStore() throws Exception { private List readAliases() { ModelNode operation = new ModelNode(); - operation.get(ClientConstants.OP_ADDR).add("subsystem","elytron").add("key-store", KEYSTORE_NAME); + operation.get(ClientConstants.OP_ADDR).add("subsystem","`elytron-tls").add("key-store", KEYSTORE_NAME); operation.get(ClientConstants.OP).set(Constants.READ_ALIASES); return assertSuccess(services.executeOperation(operation)).get(ClientConstants.RESULT).asList(); } private ModelNode readAlias(String aliasName) { ModelNode operation = new ModelNode(); - operation.get(ClientConstants.OP_ADDR).add("subsystem","elytron").add("key-store", KEYSTORE_NAME); + operation.get(ClientConstants.OP_ADDR).add("subsystem","elytron-tls").add("key-store", KEYSTORE_NAME); operation.get(ClientConstants.OP).set(Constants.READ_ALIAS); operation.get(Constants.ALIAS).set(aliasName); ModelNode alias = assertSuccess(services.executeOperation(operation)).get(ClientConstants.RESULT); @@ -1377,7 +1358,7 @@ private void removeKeyStore() { private void removeKeyStore(String keyStoreName) { ModelNode operation = new ModelNode(); operation.get(ClientConstants.OPERATION_HEADERS).get("allow-resource-service-restart").set(Boolean.TRUE); - operation.get(ClientConstants.OP_ADDR).add("subsystem","elytron").add("key-store", keyStoreName); + operation.get(ClientConstants.OP_ADDR).add("subsystem","elytron-tls").add("key-store", keyStoreName); operation.get(ClientConstants.OP).set(ClientConstants.REMOVE_OPERATION); assertSuccess(services.executeOperation(operation)); } @@ -1389,7 +1370,7 @@ private ModelNode getAddKeyStoreUsingNonExistingFileOperation(boolean required, ModelNode operation = new ModelNode(); operation.get(ClientConstants.OPERATION_HEADERS).get("allow-resource-service-restart").set(Boolean.TRUE); - operation.get(ClientConstants.OP_ADDR).add("subsystem","elytron").add("key-store", KEYSTORE_NAME); + operation.get(ClientConstants.OP_ADDR).add("subsystem","elytron-tls").add("key-store", KEYSTORE_NAME); operation.get(ClientConstants.OP).set(ClientConstants.ADD); operation.get(Constants.PATH).set(resources + nonExistentFileName); operation.get(Constants.TYPE).set("JKS"); @@ -1433,7 +1414,7 @@ private void removeCertificateAuthority() { private void removeCertificateAuthorityAccount() { ModelNode operation = new ModelNode(); operation.get(ClientConstants.OPERATION_HEADERS).get("allow-resource-service-restart").set(Boolean.TRUE); - operation.get(ClientConstants.OP_ADDR).add("subsystem","elytron").add("certificate-authority-account", CERTIFICATE_AUTHORITY_ACCOUNT_NAME); + operation.get(ClientConstants.OP_ADDR).add("subsystem","elytron-tls`").add("certificate-authority-account", CERTIFICATE_AUTHORITY_ACCOUNT_NAME); operation.get(ClientConstants.OP).set(ClientConstants.REMOVE_OPERATION); assertSuccess(services.executeOperation(operation)); } diff --git a/subsystem/src/test/resources/org/wildfly/extension/elytron/tls/subsystem/account.keystore b/subsystem/src/test/resources/org/wildfly/extension/elytron/tls/subsystem/account.keystore new file mode 100644 index 0000000000000000000000000000000000000000..cc622667db23ee0c6dc9dab0ded183ee0c30db04 GIT binary patch literal 31169 zcmafb1yo&0)-~?#?ye7a4;I|r-QC?KxLdH`PH=Y%?gR+#F2U`m)7|q;_w+xrSZ}R& zE_H6zy;ZgMu5+s1>*?z$5D*Z^`v>v;0}KRXU}R+HV(ZM}%KUCx?V~dj0|9{p0Rq9E z0SFK8w-CJ#YyOCQ>^Rz?FIYsa-Q3?mNp(PN4R zyKXjZVEMlVZ`w9-8WlgU@W|&qcy+5UiFBG~f{h{ZwJ}^ZsqgP-&sg<+!@>PbSoq)^ zIGFdWynW4Na2HmZ*BR7OA-G8$PITBM(OY>u8yk@HX%C-Vnt@ouqH?Kgmx}Cm=;z|( z1gverEzS%Bx@`UVA!?76ml|@a*{#n|uu7aI>yOU(*B3T8ct9_OO_{w5l=>WyW?Qb2 zi8JKx&)1ZN2Ig&N{031+M9_BaaevL3tAGOVA5{c=hHaQ>r?h*0K?n4dZKmbVQqv1r zW)v^9DPO*BBEY*)+nLy}wtYy7Y4D^pR6vh*`wpp}MkzQWd6`3f^0LB~tUV%6Pc2x# z9$aSdbWP-_1K(eNh}ao)mZo0I+E`8|O*W*v!`|hHt7;XbFHxr|)&G=U-^FuE?c!ia zh{fQWs*q|!83o)f6W}FVA4P7nB3$UMLiZ5jXTlemZ)oJz0OBh4(>@j+!apL=f{iZb z3o!`B*%XQW)YkfUhBOSb?xxUn& zd1MXG`wRHa07UAl)p1a-28wX}2fF0YzAcTbV)AhKV*cd%w0M>Dm*3clBhp^i&v{A- z3ucw3LY&`3)whzj5n;ZTr&^A<7aD$RP(KHk6$h~@Utc2~;n@;p*}+;E@Zs#Gx&DFS zP@cGcfsu&TBCVLS@$BugYYeeoLv}~WeuH2~#+qU#v@wLw;dfK~U7|l8gPJh{Lh`dY zI=0gVKcz1j5-u$h3=?E<3FSI?CGxchk0xa*c=Tgr;B|PrC5ZEm|1);0EWuvobd{hj z%dYX(%&cPamEJW&5+kjU=QUVw&fDtpMN)y2`X;^exy#mO`V}75lVvssuIbH2Hh}rOB z@MGqVLp-~2N5%v|z*W7Z2ek@V>ud0`u~raXX%RHILr}c=Lhi<>;U`WF3hDJbhnYGX zuVdgLm4OHnsZj3+vvvH~OVUQLu-2C?y?jRi=3RN4@9tYeD<=gCeA1~K6Ne92FpLSQ z(A(&g>7liAWoNpV1kXY~>7MzZxkEq1EvoFo9dEHPyNyP8(a;Bly4nEnNbV^yWTv)G za=nz&{@B#*fe$0%5J=z2tZ^j1J8N`VK~^;^t{*4!ev>K=c$yng!N3egGpNaBD8ij9NIj!IZ1;=83ou992nW;x zReVtsMDvxEbgK2Y+fkvj{XioTqm4|q!~0VNl$J*#R%~`4&HL|T7Fmri3j#BHIkTFO za-|MQI+)kHTytNxa;)EE#CB)f9ILI32g_95W3Zy@pm3Qv640@wvwLu*9k4$HJ%XA= zF21<#c36bz&g@dtw+&Axd6@3ht-abBH0rvcmN$V_f%0-V)4}H8YA1lRd=$&kDwotq z-BB78)=L{l$z*`pY{ECLemtcE_E2;8m0ydpbF=Dh{e_L->I`fEu6MMY2Lysl0|J3t zazR0WK|sK`grWTa@DR{6p%S5Y@W8;Z?|_NTgb6^009644MMd~OOl7b#@cncqzS*B|D8a}5M0`S*(6Q5ZB381WsRfnh)bfq{WO2Rp*AQz;)X zNvP1hs%sfWH=)}@j0=O^t|&uH*`IAzC@o1Q<-}Rh6jtAvOg$0Xr8pRkKsHSKfQk4C zZ)ps1R?Lrb>TrOs`3fRcQY#u(@p=F%wwvi>m%6z{R{6CyOk5(^*c~(nf*Z7UQ++w; z9;9OpA#|QjK)@3@qc$|`K5eMJa0q!1fXQ>Ud|8nLr(|67&bZ9`PTWiz>AaujgD7A` zwdZC1eN3R1xH6bLoq!#?&6ZGm*<7Y~j7`P=$tYrLr2vDoRPXE4!f7ICoG^2GmOLUcwT2&(-A7Og@`%8T9t@oD*3?ztO?Vw=NdxL2rjO8Tg zHQ*j#SN+wN_>=Pa(fX;b4k&>>T=imJhIUrF!u~xKEo_9Tdi6GD zDzYXnvbd@rR(jS($7}oOw8GeZ$Bi86@q7>x;ZJzs6=SWZsFRmcslW9zr+)QrOZJf# z4mAU1Jei;G(8dwA4FBp|YjCETFIiG;D9rWcOod z2LW<-0Y0FdFmcAK?+G3YnR{egA1Ro}EeS^HwkoKye5~$w{&*QNBE#&ga?;eb6o+ zRrsBr}HGD*tU`b?5|GZ5FOt0l1I2{Kmx`*8O(1V=%8+o1)elRUzDQt|h0{{y1lAN6kOeoffR0PTw5OjqJpkKS#SHJ+n-$I*nB!?-#k04X2?#4sq4GiAM zp;qq@mZvm|qaA{>6C)d4yWb&>^8(FF8QQZ^z?eygqM>aEKZey>G4pgt?>H#vXql5fb=BH;GpX5Q)>kEX>q@D`tHEi#xo zJ6nh?=m``%4us4NgK%S_I0kc&a6&|K>%7Q!Q8$CzX1KGS48H|VU-{q~G?S*&JDUYl zghLX7ispV~a#Mi{FbBosq3$V~FZ#^N?fnAx^9+WkY*PG8i5JVMqOgO`xw_M2C*DLC z0&-^hmIIA}JLW6Gc`?LWalnYaV>~*~xYt2v;bThFJM^8OH+5D{(1sTykc@97wej=p z6vQ|=JD1l59t}Rwqp)k@<-sJ4>s{k25_{@KBS8T;l~Q3W0M?I*+THl;&`0A)Lt9(& z2H#FO2OeX+oBc?X#m=Wdqa{|B1b^UkZsb3%$BM}{mnqJ%b~|_SU8fru2Rfc}d!^)G zeEnJHh$Y7e4D=w3M6yna7u-ix{V`j>o}=la+v4u@?em>#TD!VtT~|vH;od~UJWOh< ztTrvSm*V*L9^@y!+G2Jt%1(C)(+396h1=obj)RcKeJchVhFtIoo178hb3x#PK#A($ zxkdF%?Er!UA??kOJ75>WnV)x^O2@Pavxj8eu5<-V2QJqP@)2qGD4#aC^_nTYYk9_Xrx?k!!>*gX)9Ho z?hIY=q4!MHIDKQ(VCWG^V{4krGgXul1-7+}l>eL?M0w6L2tyMR8hu;DLd-c|kO#># z{-Vi<51M{8W9_*QF9)Mh-1a;#KmtQ zXRrg+{DMa_carh!dB1a}kh@lc2z#WdOm-3+FUv&5?Nt~jeI&p22ku6FQKwBiE*@!~ ze(EM+DeWmbQMsiM(&rC`xYo4S5lt&n5q8~6j{{-npj32 zHRC@TC?ulg7v$q|0<1Sk%@jUHHlsfQ1x#8a7%zR_q_&Md!tWZ8*N2;23&zS1J)=HV z#6R*;S2LJjSn69MTmSGJxnVvx{q0M?tXN_5g@w)$2EH|&36`yMqmg%FZPwbgAfDg%OU7G+FY?*zXD-RAo!-FM~ua)@$2EglcCR*^maU0}n}Z zU-qYA;EjMJzGTmu8NtyUN5Zz_XzkS9$md`Gg?s)(`a!!(Tm4N;{5J~ucj?Co;P?ys zyqo{c^?ymfJW(eQs#;X(sdcJ5-sZaUBaP3g-3bAEWrTV`SWbChM9tc8tOYOZ>6H> zB||BCP2;5=HP!35s#_!q!r1F`fe#nRH}bi?(+6fe{DR;x)Q?lJ2)#UnUxy%T zF9(ZoLyLi9*tz056R^BgkxasPn)#*uh`MP)mF6M#@PktFzOv54vI9-g@Oh zfQQIy^H0)`6%0GvFVsdmy!3nO^Z;mV>@Z;BZ@u+P`dJXhCefL-)+Dsygc_aVC*`b4 zu+S1d{JgKJ99EK1kMeF524!|xgKJ@h7*|vehE`5{#BSlSt(X(%j}MJBjq%;wy13-k zwWvAjQWAo;R4A%2fGh1&XNF1630HzG2GFAfwq*NpRJZbD`YY9zK5pITH2Id=snwo2En7QVK4^`!BUtQ|@^ zUh#W(mcj;g?rU-{_orrAEMWzXslTu_jA#ezbTtzLw(opmjRZRrK9H)MT1x9+xnmZ= z_Zlc`b=TSXxocx^B0Y#!-sb>57X=*@x5O`5uKgP0n2si{c2*{C7S865CI(J+wg%P~ z22Q^Vf~RNr=XXH>{2m8-`3FI8hz6F9Z@XZ9g~gY$Coid|!d%IMSa>&_A9#x|jO4@P zQ>i0-Bq{ijf7t#i=U$hF+=_Ykh_%WDis{~q0=?tRd*PG6WZqkVxi_2{(A`)$$EwDhBvZeo7pUC`d&lGS9r(-n zAA!_w=tdtGDoY+$qNPwFT<2=1zGMdw*+$o6yJN;ZM-Q7G2cTMGT{WvRF_*%B^R>FBPV@C4GEnJPW%f?)h|Sq~w0p`APZp6tD0{o3 ztoyH~uqll$`9Hy22I*E2foLCp73**%FBB%X8TB%Xk2yBO zo?>!kr`o`It?t|y>Qu|?dCbfQ-?vKQ9}xC4TP3&ZPwe{2XIXk4&Qv@J?!DY&BO7|C zV7JNp`h29k5uG+9mZ8wWl9<;5Hk>0YS|Z6voEg>Kj3Dn|*#Fo}dL)EtsA#|$t7X00_bstg|Rz4<|-SJVe#`;I&g!>*5eBRTar9psg1Wu z-x8G37L@4*WKwa=fnval8j!zj?~N4xRVg2HISZ6w@<6>fQ(~+;rkxTfPrF9J@R)F= zq~z!m^~>V5ov7!RV)1M`5A(Xiz~rfyJ&8N!RNPleL@=I#1jpJgz8hzPBOflR=ZIH2 z1sxo&7r!3Hd4{7z$zz#3orXe9qec{1J7?8LL4Ph&4D-e>O)|V85l3`Q3g2o7pwzW0 zna>bq&2?>mq%=wog5R)?ScInYgy)u$kZYf1CT2cIkU~TOos8ynjV6cY*nZry8pJx9=fJS&BSCi|=sz0({b zZxEDVLT#-vbviz*BhHfgC(MuvDBYURhd7HLgpeEx~cB%RUaoYJImC<=GQUe#)KW z9&)1AEid1+2~U<|yZrWvH6WEf3KP|vP*<0%G-bhXl`O(6L9)7IhS+4(Xen5J#H6`z zJ9Yd9J@<$h5{a5I`&WX%OA#A7{F)&kZoNb4>eO6=x!ei;$S<%}L2&xc2~i=M3)Z)ntX-Df~X-A!S6^30`zAf2wd`gfh78liS)lO zMNxs?U|i`}s`=MHO=ptPZ}V~~asQ2O0EA5V0Nh`3AviR1W_x=NB6H^V^|m9CsezRV zk%-X0qC@OV?-8P35`l?}3BbhqhY28H!UN#^9#}%Pu{AcawlcOgG_tU^GdE)}va@+# z8~^tZQFwpVgL+;7t+h7D2Ep^f1V$?jcv3Ca&4*i9ZK9etY~pDr6_eU0@)o$=w!xt_ zsFJpUAi;C@AMT%2Z^DU&#ofkljU1<1$AL$9KYHL6XF?>On2H9&@6dtJn)ZW;L`Vtd ze<~)J;4bKMch;8cJ8O&H2E}_=IRHoLZ@Oeid%`mDJ&QlpWP^aaVhLef688U??%mWv zeQ7$lFa0b!aY^|pxt$B}0ZT&vOLT&{C6~PU7V!iIS~(J@HA+oi$LQ-e!Z-J|AD2wV z*_{m7vULffHwIlHFF(a8#xXT2B}k_&=CA4e>0)wuo#Emq@%h}1j-|EI9R(*paoyZj z6Sw`Y69Pdz-h+59?_BmCCPD-Tegpe0a*+Fb*oYhq1Aqnr^`7hi2ZscGU+e$z4di_h z{$3pQx8fiGpnr=o0nVM|rfazJIYy8Lp?7VI1qAUL0ffI5CI!O+VECgwxyzwE=%WYG z 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 literal 0 HcmV?d00001 diff --git a/subsystem/src/test/resources/org/wildfly/extension/elytron/tls/subsystem/test-original.keystore b/subsystem/src/test/resources/org/wildfly/extension/elytron/tls/subsystem/test-original.keystore new file mode 100644 index 0000000000000000000000000000000000000000..d6f215cb4fac314595f1d60852445f6f7f56d229 GIT binary patch literal 2811 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 - - - - - - - - @@ -151,4 +143,12 @@ trust-manager="CaTrustManager" providers="ManagerProviderLoader"/> + + + + + + + + diff --git a/subsystem/src/test/resources/org/wildfly/extension/elytron/tls/subsystem/tls-oracle13plus.xml b/subsystem/src/test/resources/org/wildfly/extension/elytron/tls/subsystem/tls-oracle13plus.xml index b6e5d8c..df5b0b1 100644 --- a/subsystem/src/test/resources/org/wildfly/extension/elytron/tls/subsystem/tls-oracle13plus.xml +++ b/subsystem/src/test/resources/org/wildfly/extension/elytron/tls/subsystem/tls-oracle13plus.xml @@ -4,14 +4,6 @@ - - - - - - - - @@ -155,4 +147,12 @@ trust-manager="CaTrustManager" providers="ManagerProviderLoader"/> + + + + + + + + diff --git a/subsystem/src/test/resources/org/wildfly/extension/elytron/tls/subsystem/tls-sun.xml b/subsystem/src/test/resources/org/wildfly/extension/elytron/tls/subsystem/tls-sun.xml index 49fa533..928a3c4 100644 --- a/subsystem/src/test/resources/org/wildfly/extension/elytron/tls/subsystem/tls-sun.xml +++ b/subsystem/src/test/resources/org/wildfly/extension/elytron/tls/subsystem/tls-sun.xml @@ -4,14 +4,6 @@ - - - - - - - - @@ -155,4 +147,12 @@ trust-manager="CaTrustManager" providers="ManagerProviderLoader"/> + + + + + + + + diff --git a/subsystem/src/test/resources/org/wildfly/extension/elytron/tls/subsystem/tls.xml b/subsystem/src/test/resources/org/wildfly/extension/elytron/tls/subsystem/tls.xml index 304c3fe..cacb7cc 100644 --- a/subsystem/src/test/resources/org/wildfly/extension/elytron/tls/subsystem/tls.xml +++ b/subsystem/src/test/resources/org/wildfly/extension/elytron/tls/subsystem/tls.xml @@ -2,27 +2,6 @@ - - - - - - - - - - - - - - - - - - - @@ -102,6 +81,27 @@ provider-name="first" /> + + + + + + + + + + + + + + + + + + +