Skip to content

Commit

Permalink
[WFCORE-5101] SSLContext to support delegation to alternate instances…
Browse files Browse the repository at this point in the history
… based on peer information.
  • Loading branch information
Skyllarr committed Apr 9, 2021
1 parent dc9d42f commit c3bfb6d
Show file tree
Hide file tree
Showing 20 changed files with 368 additions and 1 deletion.
4 changes: 4 additions & 0 deletions core-feature-pack/common/pom.xml
Expand Up @@ -321,6 +321,10 @@
<groupId>org.wildfly.security</groupId>
<artifactId>wildfly-elytron-digest</artifactId>
</dependency>
<dependency>
<groupId>org.wildfly.security</groupId>
<artifactId>wildfly-elytron-dynamic-ssl</artifactId>
</dependency>
<dependency>
<groupId>org.wildfly.security</groupId>
<artifactId>wildfly-elytron-encryption</artifactId>
Expand Down
Expand Up @@ -1302,6 +1302,17 @@
</license>
</licenses>
</dependency>
<dependency>
<groupId>org.wildfly.security</groupId>
<artifactId>wildfly-elytron-dynamic-ssl</artifactId>
<licenses>
<license>
<name>Apache License 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0</url>
<distribution>repo</distribution>
</license>
</licenses>
</dependency>
<dependency>
<groupId>org.wildfly.security</groupId>
<artifactId>wildfly-elytron-encryption</artifactId>
Expand Down
Expand Up @@ -52,6 +52,7 @@
<artifact name="${org.wildfly.security:wildfly-elytron-credential-source-impl}"/>
<artifact name="${org.wildfly.security:wildfly-elytron-credential-store}"/>
<artifact name="${org.wildfly.security:wildfly-elytron-digest}"/>
<artifact name="${org.wildfly.security:wildfly-elytron-dynamic-ssl}"/>
<artifact name="${org.wildfly.security:wildfly-elytron-encryption}"/>
<artifact name="${org.wildfly.security:wildfly-elytron-http}"/>
<artifact name="${org.wildfly.security:wildfly-elytron-http-basic}"/>
Expand Down
Expand Up @@ -28,6 +28,7 @@
import static org.wildfly.extension.elytron.Capabilities.SECURITY_DOMAIN_CAPABILITY;
import static org.wildfly.extension.elytron.Capabilities.SECURITY_FACTORY_CREDENTIAL_CAPABILITY;
import static org.wildfly.extension.elytron.Capabilities.SSL_CONTEXT_CAPABILITY;
import static org.wildfly.extension.elytron.ElytronDefinition.commonRequirements;
import static org.wildfly.extension.elytron._private.ElytronSubsystemMessages.ROOT_LOGGER;

import java.util.HashMap;
Expand Down Expand Up @@ -55,6 +56,8 @@
import org.jboss.dmr.ModelNode;
import org.jboss.dmr.ModelType;
import org.jboss.msc.service.ServiceBuilder;
import org.jboss.msc.service.ServiceController;
import org.jboss.msc.service.ServiceTarget;
import org.jboss.msc.value.InjectedValue;
import org.wildfly.common.function.ExceptionSupplier;
import org.wildfly.extension.elytron.TrivialService.ValueSupplier;
Expand Down Expand Up @@ -429,7 +432,6 @@ protected ValueSupplier<AuthenticationContext> getValueSupplier(ServiceBuilder<A
serviceBuilder.addDependency(context.getCapabilityServiceName(
RuntimeCapability.buildDynamicCapabilityName(AUTHENTICATION_CONTEXT_CAPABILITY, parent), AuthenticationContext.class),
AuthenticationContext.class, parentInjector);

parentSupplier = parentInjector::getValue;
} else {
parentSupplier = AuthenticationContext::empty;
Expand Down Expand Up @@ -505,6 +507,18 @@ protected ValueSupplier<AuthenticationContext> getValueSupplier(ServiceBuilder<A
return () -> finalContext.apply(parentSupplier.get());
}

@Override
protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
commonRequirements(installService(context, model)).setInitialMode(ServiceController.Mode.ACTIVE).install();
}

ServiceBuilder<AuthenticationContext> installService(OperationContext context, ModelNode model) throws OperationFailedException {
ServiceTarget serviceTarget = context.getServiceTarget();
ServiceBuilder<AuthenticationContext> serviceBuilder =
(ServiceBuilder<AuthenticationContext>)context.getCapabilityServiceTarget().addCapability(AUTHENTICATION_CONTEXT_RUNTIME_CAPABILITY);
TrivialService<AuthenticationContext> authenticationContextTrivialService = new TrivialService<AuthenticationContext>(getValueSupplier(serviceBuilder, context, model));
return serviceTarget.addService(AUTHENTICATION_CONTEXT_RUNTIME_CAPABILITY.getCapabilityServiceName(context.getCurrentAddressValue()), authenticationContextTrivialService);
}
};

return new TrivialResourceDefinition(ElytronDescriptionConstants.AUTHENTICATION_CONTEXT, add, attributes,
Expand Down
Expand Up @@ -299,6 +299,7 @@ public void registerChildren(ManagementResourceRegistration resourceRegistration
resourceRegistration.registerSubModel(SSLDefinitions.getServerSNISSLContextDefinition());
resourceRegistration.registerSubModel(new CertificateAuthorityDefinition());
resourceRegistration.registerSubModel(new CertificateAuthorityAccountDefinition());
resourceRegistration.registerSubModel(SSLDefinitions.getDynamicClientSSLContextDefinition(serverOrHostController));

// Credential Store Block
resourceRegistration.registerSubModel(new CredentialStoreResourceDefinition());
Expand Down
Expand Up @@ -182,6 +182,8 @@ interface ElytronDescriptionConstants {
String DISTINGUISHED_NAME = "distinguished-name";
String DISTRIBUTED_REALM = "distributed-realm";
String DOMAIN_NAMES = "domain-names";
String DYNAMIC_CLIENT_SSL_CONTEXT = "dynamic-client-ssl-context";
String DYNAMIC_CLIENT_SSL_CONTEXTS = "dynamic-client-ssl-contexts";

String ELYTRON_SECURITY = "elytron-security";
String ENABLE_CONNECTION_POOLING = "enable-connection-pooling";
Expand Down
Expand Up @@ -39,3 +39,4 @@ PersistentResourceXMLDescription getRealmParser() {
}
}


Expand Up @@ -153,6 +153,8 @@ private static void from11(ChainedTransformationDescriptionBuilder chainedBuilde
ResourceTransformationDescriptionBuilder builder = chainedBuilder.createBuilder(ELYTRON_11_0_0, ELYTRON_10_0_0);
builder.rejectChildResource(PathElement.pathElement(ElytronDescriptionConstants.DISTRIBUTED_REALM));
builder.rejectChildResource(PathElement.pathElement(ElytronDescriptionConstants.FAILOVER_REALM));
builder.rejectChildResource(PathElement.pathElement(ElytronDescriptionConstants.DYNAMIC_CLIENT_SSL_CONTEXTS));
builder.rejectChildResource(PathElement.pathElement(ElytronDescriptionConstants.DYNAMIC_CLIENT_SSL_CONTEXT));
}

private static void from10(ChainedTransformationDescriptionBuilder chainedBuilder) {
Expand Down
Expand Up @@ -34,6 +34,7 @@
import org.jboss.msc.service.ServiceController;
import org.jboss.msc.service.ServiceController.State;
import org.wildfly.common.iteration.ByteIterator;
import org.wildfly.security.dynamic.ssl.DynamicSSLContext;

/**
* A {@link Resource} to represent a server-ssl-context/client-ssl-context, the majority is actually model
Expand Down Expand Up @@ -142,6 +143,9 @@ public Resource clone() {
*/
private boolean hasActiveSessions() {
final SSLContext sslContext = getSSLContext(sslContextServiceController);
if (sslContext instanceof DynamicSSLContext) {
return false;
}
if (sslContext == null) return false;
SSLSessionContext sslSessionContext = server ? sslContext.getServerSessionContext() : sslContext.getClientSessionContext();
return sslSessionContext.getIds().hasMoreElements();
Expand Down
Expand Up @@ -21,6 +21,8 @@
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;
import static org.wildfly.extension.elytron.Capabilities.AUTHENTICATION_CONTEXT_CAPABILITY;
import static org.wildfly.extension.elytron.Capabilities.AUTHENTICATION_CONTEXT_RUNTIME_CAPABILITY;
import static org.wildfly.extension.elytron.Capabilities.KEY_MANAGER_CAPABILITY;
import static org.wildfly.extension.elytron.Capabilities.KEY_MANAGER_RUNTIME_CAPABILITY;
import static org.wildfly.extension.elytron.Capabilities.KEY_STORE_CAPABILITY;
Expand All @@ -33,6 +35,7 @@
import static org.wildfly.extension.elytron.Capabilities.SSL_CONTEXT_RUNTIME_CAPABILITY;
import static org.wildfly.extension.elytron.Capabilities.TRUST_MANAGER_CAPABILITY;
import static org.wildfly.extension.elytron.Capabilities.TRUST_MANAGER_RUNTIME_CAPABILITY;
import static org.wildfly.extension.elytron.ElytronDefinition.commonRequirements;
import static org.wildfly.extension.elytron.ElytronExtension.getRequiredService;
import static org.wildfly.extension.elytron.FileAttributeDefinitions.PATH;
import static org.wildfly.extension.elytron.FileAttributeDefinitions.RELATIVE_TO;
Expand Down Expand Up @@ -109,6 +112,7 @@
import org.jboss.as.controller.services.path.PathManagerService;
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.State;
Expand All @@ -121,12 +125,16 @@
import org.wildfly.extension.elytron.TrivialService.ValueSupplier;
import org.wildfly.extension.elytron._private.ElytronSubsystemMessages;
import org.wildfly.extension.elytron.capabilities.PrincipalTransformer;
import org.wildfly.security.auth.client.AuthenticationContext;
import org.wildfly.security.auth.client.DynamicSSLContextImpl;
import org.wildfly.security.auth.server.MechanismConfiguration;
import org.wildfly.security.auth.server.MechanismConfigurationSelector;
import org.wildfly.security.auth.server.RealmMapper;
import org.wildfly.security.auth.server.SecurityDomain;
import org.wildfly.security.credential.PasswordCredential;
import org.wildfly.security.credential.source.CredentialSource;
import org.wildfly.security.dynamic.ssl.DynamicSSLContext;
import org.wildfly.security.dynamic.ssl.DynamicSSLContextException;
import org.wildfly.security.keystore.AliasFilter;
import org.wildfly.security.keystore.FilteringKeyStore;
import org.wildfly.security.password.interfaces.ClearPassword;
Expand Down Expand Up @@ -156,6 +164,12 @@ class SSLDefinitions {
.setRestartAllServices()
.build();

static final SimpleAttributeDefinition AUTHENTICATION_CONTEXT_ATTRIBUTE = new SimpleAttributeDefinitionBuilder(ElytronDescriptionConstants.AUTHENTICATION_CONTEXT, ModelType.STRING, true)
.setMinSize(1)
.setCapabilityReference(AUTHENTICATION_CONTEXT_CAPABILITY, SSL_CONTEXT_CAPABILITY)
.setRestartAllServices()
.build();

static final SimpleAttributeDefinition PROVIDER_NAME = new SimpleAttributeDefinitionBuilder(ElytronDescriptionConstants.PROVIDER_NAME, ModelType.STRING, true)
.setAllowExpression(true)
.setMinSize(1)
Expand Down Expand Up @@ -1479,6 +1493,56 @@ protected void installedForResource(ServiceController<SSLContext> serviceControl
return createSSLContextDefinition(ElytronDescriptionConstants.CLIENT_SSL_CONTEXT, false, add, attributes, serverOrHostController);
}

private static final AttributeDefinition[] DYNAMIC_SSL_CONTEXT_ATTRIBUTES = new AttributeDefinition[]{AUTHENTICATION_CONTEXT_ATTRIBUTE};

static ResourceDefinition getDynamicClientSSLContextDefinition(boolean serverOrHostController) {
return createSSLContextDefinition(ElytronDescriptionConstants.DYNAMIC_CLIENT_SSL_CONTEXT, false, new DynamicSSLContextAddHandler(), DYNAMIC_SSL_CONTEXT_ATTRIBUTES, serverOrHostController);
}

private static class DynamicSSLContextAddHandler extends BaseAddHandler {
private DynamicSSLContextAddHandler() {
super(SSL_CONTEXT_RUNTIME_CAPABILITY, DYNAMIC_SSL_CONTEXT_ATTRIBUTES);
}

@Override
protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
ServiceBuilder<SSLContext> serviceBuilder = installService(context, model);
ServiceName authenticationContextServiceName =
AUTHENTICATION_CONTEXT_RUNTIME_CAPABILITY.getCapabilityServiceName(AUTHENTICATION_CONTEXT_ATTRIBUTE.resolveModelAttribute(context, model).asString());
serviceBuilder.requires(authenticationContextServiceName);
commonRequirements(serviceBuilder).setInitialMode(ServiceController.Mode.ACTIVE).install();
}

ServiceBuilder<SSLContext> installService(OperationContext context, ModelNode model) throws OperationFailedException {
ServiceName dynamicSslContextServiceName = SSL_CONTEXT_RUNTIME_CAPABILITY.getCapabilityServiceName(context.getCurrentAddressValue());
return context.getServiceTarget().addService(dynamicSslContextServiceName, new TrivialService<>(getValueSupplier(dynamicSslContextServiceName, context, model)));
}

protected ValueSupplier<SSLContext> getValueSupplier(ServiceName dynamicSSLContextName, OperationContext context, ModelNode model) throws OperationFailedException {
String authenticationContextName = AUTHENTICATION_CONTEXT_ATTRIBUTE.resolveModelAttribute(context, model).asString();
ServiceRegistry serviceRegistry = context.getServiceRegistry(true);
return () -> {
ServiceController<?> dynamicSSLContextService = serviceRegistry.getRequiredService(dynamicSSLContextName);
State dynamicSSLContextServiceState = dynamicSSLContextService.getState();
if (!dynamicSSLContextServiceState.equals(State.UP)) {
dynamicSSLContextService.setMode(ServiceController.Mode.ACTIVE);
}
try {
return new DynamicSSLContext(new DynamicSSLContextImpl(getAuthenticationContextService(serviceRegistry, authenticationContextName).getValue()));
} catch (GeneralSecurityException | DynamicSSLContextException e) {
throw new StartException(e);
}
};
}

static Service<AuthenticationContext> getAuthenticationContextService(ServiceRegistry serviceRegistry, String authenticationContextName) {
RuntimeCapability<Void> authenticationContextRuntimeCapability = AUTHENTICATION_CONTEXT_RUNTIME_CAPABILITY.fromBaseCapability(authenticationContextName);
ServiceName serviceName = authenticationContextRuntimeCapability.getCapabilityServiceName();
ServiceController<AuthenticationContext> serviceContainer = getRequiredService(serviceRegistry, serviceName, AuthenticationContext.class);
return serviceContainer.getService();
}
}

private static Provider[] filterProviders(Provider[] all, String provider) {
if (provider == null || all == null) return all;
List<Provider> list = new ArrayList<>();
Expand Down
Expand Up @@ -26,6 +26,8 @@
import static org.wildfly.extension.elytron.ElytronDescriptionConstants.CERTIFICATE_AUTHORITY_ACCOUNTS;
import static org.wildfly.extension.elytron.ElytronDescriptionConstants.CLIENT_SSL_CONTEXT;
import static org.wildfly.extension.elytron.ElytronDescriptionConstants.CLIENT_SSL_CONTEXTS;
import static org.wildfly.extension.elytron.ElytronDescriptionConstants.DYNAMIC_CLIENT_SSL_CONTEXT;
import static org.wildfly.extension.elytron.ElytronDescriptionConstants.DYNAMIC_CLIENT_SSL_CONTEXTS;
import static org.wildfly.extension.elytron.ElytronDescriptionConstants.FILTERING_KEY_STORE;
import static org.wildfly.extension.elytron.ElytronDescriptionConstants.HOST;
import static org.wildfly.extension.elytron.ElytronDescriptionConstants.SNI_MAPPING;
Expand Down Expand Up @@ -194,6 +196,10 @@ class TlsParser {
.addAttribute(SSLDefinitions.PROVIDERS)
.addAttribute(SSLDefinitions.PROVIDER_NAME);

private PersistentResourceXMLBuilder dynamicClientSslContextParser = PersistentResourceXMLDescription.builder(PathElement.pathElement(DYNAMIC_CLIENT_SSL_CONTEXT))
.setXmlWrapperElement(DYNAMIC_CLIENT_SSL_CONTEXTS)
.addAttribute(SSLDefinitions.AUTHENTICATION_CONTEXT_ATTRIBUTE);

private PersistentResourceXMLBuilder certificateAuthorityParser = PersistentResourceXMLDescription.builder(PathElement.pathElement(CERTIFICATE_AUTHORITY))
.setXmlWrapperElement(CERTIFICATE_AUTHORITIES)
.addAttribute(CertificateAuthorityDefinition.URL)
Expand Down Expand Up @@ -319,6 +325,7 @@ public void marshallSingleElement(AttributeDefinition attribute, ModelNode mappi
.addChild(serverSslSniContextParser)
.build();


final PersistentResourceXMLDescription tlsParser_12_0 = decorator(TLS)
.addChild(decorator(KEY_STORES)
.addChild(keyStoreParser)
Expand All @@ -332,5 +339,6 @@ public void marshallSingleElement(AttributeDefinition attribute, ModelNode mappi
.addChild(certificateAuthorityParser)
.addChild(certificateAuthorityAccountParser)
.addChild(serverSslSniContextParser)
.addChild(dynamicClientSslContextParser) // new
.build();
}
Expand Up @@ -1384,6 +1384,15 @@ elytron.client-ssl-context.ssl-session.peer-certificates.version=The certificate
# Operations
elytron.client-ssl-context.ssl-session.invalidate=Invalidate the SSLSession (Note: This does not terminate current connections, only prevents future connections from joining or resuming this session).

elytron.dynamic-client-ssl-context=An Dynamic SSLContext for use on the client side of a connection. It allows to choose ssl context based on peer's host and port information
# operations
elytron.dynamic-client-ssl-context.add=Add the Dynamic Client SSLContext definition.
elytron.dynamic-client-ssl-context.remove=Remove the Dynamic Client SSLContext definition.
#Attributes
elytron.dynamic-client-ssl-context.authentication-context=The authentication context that will be queried for ssl context based on peer information.
elytron.dynamic-client-ssl-context.active-session-count=The count of current active sessions.
elytron.dynamic-client-ssl-context.ssl-session=The ssl session of dynamic ssl context is always undefined.

elytron.server-ssl-context=An SSLContext for use on the server side of a connection.
# operations
elytron.server-ssl-context.add=Add the SSLContext definition.
Expand Down

0 comments on commit c3bfb6d

Please sign in to comment.