diff --git a/pom.xml b/pom.xml index c7c4382..fb6db1f 100644 --- a/pom.xml +++ b/pom.xml @@ -42,7 +42,7 @@ 26.1.1.Final 18.1.1.Final 1.6.0.Final - 1.20.1.CR1-SNAPSHOT + 1.20.1.Final @@ -198,17 +198,6 @@ - - ${project.groupId} - elytron-tls-dependency - ${project.version} - - - * - * - - - ${project.groupId} elytron-tls-subsystem @@ -264,61 +253,56 @@ wildfly-checkstyle-config ${version.org.wildfly.checkstyle-config} - + + org.wildfly.core + wildfly-elytron-integration + ${version.org.wildfly.core} + org.wildfly.security wildfly-elytron-asn1 ${version.org.wildfly.security.elytron} - org.wildfly.security wildfly-elytron-base ${version.org.wildfly.security.elytron} - org.wildfly.security wildfly-elytron-credential ${version.org.wildfly.security.elytron} - org.wildfly.security wildfly-elytron-provider-util ${version.org.wildfly.security.elytron} - org.wildfly.security wildfly-elytron-ssl-common ${version.org.wildfly.security.elytron} - org.wildfly.security wildfly-elytron-x500 ${version.org.wildfly.security.elytron} - org.wildfly.security wildfly-elytron-x500-cert ${version.org.wildfly.security.elytron} - org.wildfly.security wildfly-elytron-x500-cert-acme ${version.org.wildfly.security.elytron} - org.wildfly.security wildfly-elytron-x500-cert-util ${version.org.wildfly.security.elytron} - org.wildfly.security wildfly-elytron-x500-principal @@ -410,6 +394,7 @@ org.jmockit jmockit + test ${version.org.jmockit} diff --git a/subsystem/pom.xml b/subsystem/pom.xml index d6e9767..90d1928 100644 --- a/subsystem/pom.xml +++ b/subsystem/pom.xml @@ -33,88 +33,72 @@ jakarta.json jakarta.json-api - org.glassfish jakarta.json - org.jboss.logging jboss-logging-annotations - org.jboss.logging jboss-logging-processor - provided true - org.wildfly.core wildfly-controller - + + org.wildfly.core + wildfly-elytron-integration + org.wildfly.core wildfly-server - org.wildfly.checkstyle wildfly-checkstyle-config - org.wildfly.security wildfly-elytron-asn1 - org.wildfly.security wildfly-elytron-base - org.wildfly.security wildfly-elytron-credential - org.wildfly.security wildfly-elytron-provider-util - org.wildfly.security wildfly-elytron-ssl-common - org.wildfly.security wildfly-elytron-x500 - org.wildfly.security wildfly-elytron-x500-cert - org.wildfly.security wildfly-elytron-x500-cert-acme - org.wildfly.security wildfly-elytron-x500-cert-util - org.wildfly.security wildfly-elytron-x500-principal @@ -124,7 +108,6 @@ junit junit - test org.bouncycastle @@ -137,12 +120,10 @@ org.mock-server mockserver-netty - test org.jmockit jmockit - test org.wildfly.core diff --git a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/AbstractCredentialStoreResourceDefinition.java b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/AbstractCredentialStoreResourceDefinition.java deleted file mode 100644 index ef7aad6..0000000 --- a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/AbstractCredentialStoreResourceDefinition.java +++ /dev/null @@ -1,362 +0,0 @@ - /* - * Copyright 2021 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; - -import static org.wildfly.extension.elytron.tls.Capabilities.CREDENTIAL_STORE_API_CAPABILITY; -import static org.wildfly.extension.elytron.tls.Capabilities.CREDENTIAL_STORE_RUNTIME_CAPABILITY; -import static org.wildfly.extension.elytron.tls.ElytronTlsExtension.isServerOrHostController; -import static org.wildfly.extension.elytron.tls.ServiceStateDefinition.STATE; -import static org.wildfly.extension.elytron.tls.ServiceStateDefinition.populateResponse; -import static org.wildfly.extension.elytron.tls._private.ElytronTLSMessages.LOGGER; -import static org.wildfly.security.encryption.SecretKeyUtil.exportSecretKey; -import static org.wildfly.security.encryption.SecretKeyUtil.generateSecretKey; -import static org.wildfly.security.encryption.SecretKeyUtil.importSecretKey; - -import java.security.GeneralSecurityException; -import java.security.NoSuchAlgorithmException; -import java.security.spec.InvalidKeySpecException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.logging.Level; - -import javax.crypto.SecretKey; - -import org.jboss.as.controller.AbstractWriteAttributeHandler; -import org.jboss.as.controller.AttributeDefinition; -import org.jboss.as.controller.OperationContext; -import org.jboss.as.controller.OperationFailedException; -import org.jboss.as.controller.OperationStepHandler; -import org.jboss.as.controller.PathAddress; -import org.jboss.as.controller.SimpleAttributeDefinition; -import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; -import org.jboss.as.controller.SimpleOperationDefinition; -import org.jboss.as.controller.SimpleOperationDefinitionBuilder; -import org.jboss.as.controller.SimpleResourceDefinition; -import org.jboss.as.controller.descriptions.ModelDescriptionConstants; -import org.jboss.as.controller.descriptions.StandardResourceDescriptionResolver; -import org.jboss.as.controller.registry.ManagementResourceRegistration; -import org.jboss.dmr.ModelNode; -import org.jboss.dmr.ModelType; -import org.jboss.msc.service.ServiceController; -import org.jboss.msc.service.ServiceName; -import org.wildfly.common.function.ExceptionFunction; -import org.wildfly.security.credential.Credential; -import org.wildfly.security.credential.PasswordCredential; -import org.wildfly.security.credential.SecretKeyCredential; -import org.wildfly.security.credential.store.CredentialStore; -import org.wildfly.security.credential.store.CredentialStoreException; -import org.wildfly.security.credential.store.UnsupportedCredentialTypeException; -import org.wildfly.security.password.PasswordFactory; -import org.wildfly.security.password.interfaces.ClearPassword; -import org.wildfly.security.password.spec.ClearPasswordSpec; - -/** - * A common base for resource definitions representing credential stores. - * - * @author Darran Lofthouse - */ -abstract class AbstractCredentialStoreResourceDefinition extends SimpleResourceDefinition { - - static final ServiceUtil CREDENTIAL_STORE_UTIL = ServiceUtil.newInstance(CREDENTIAL_STORE_RUNTIME_CAPABILITY, Constants.CREDENTIAL_STORE, CredentialStore.class); - - protected ServiceUtil getCredentialStoreUtil() { - return CREDENTIAL_STORE_UTIL; - } - - // Operations - - static final StandardResourceDescriptionResolver OPERATION_RESOLVER = ElytronTlsExtension - .getResourceDescriptionResolver(Constants.CREDENTIAL_STORE, - Constants.OPERATIONS); - - static final SimpleOperationDefinition READ_ALIASES = new SimpleOperationDefinitionBuilder(Constants.READ_ALIASES, OPERATION_RESOLVER) - .setRuntimeOnly() - .setReadOnly() - .build(); - - static final SimpleAttributeDefinition ALIAS = new SimpleAttributeDefinitionBuilder(Constants.ALIAS, ModelType.STRING, false) - .setMinSize(1) - .build(); - - static final SimpleAttributeDefinition KEY = new SimpleAttributeDefinitionBuilder(Constants.KEY, ModelType.STRING, false) - .setMinSize(1) - .build(); - - static final SimpleOperationDefinition EXPORT_SECRET_KEY = new SimpleOperationDefinitionBuilder(Constants.EXPORT_SECRET_KEY, OPERATION_RESOLVER) - .setParameters(ALIAS) - .setRuntimeOnly() - .build(); - - static final SimpleOperationDefinition IMPORT_SECRET_KEY = new SimpleOperationDefinitionBuilder(Constants.IMPORT_SECRET_KEY, OPERATION_RESOLVER) - .setParameters(ALIAS, KEY) - .setRuntimeOnly() - .build(); - - static final SimpleOperationDefinition RELOAD = new SimpleOperationDefinitionBuilder(Constants.RELOAD, OPERATION_RESOLVER) - .setRuntimeOnly() - .build(); - - static final OperationStepHandler RELOAD_HANDLER = new CredentialStoreReloadHandler(); - - protected AbstractCredentialStoreResourceDefinition(Parameters parameters) { - super(parameters); - } - - @Override - public void registerAttributes(ManagementResourceRegistration resourceRegistration) { - AttributeDefinition[] configAttributes = getAttributeDefinitions(); - AbstractWriteAttributeHandler write = new ElytronReloadRequiredWriteAttributeHandler(configAttributes); - for (AttributeDefinition current : configAttributes) { - resourceRegistration.registerReadWriteAttribute(current, null, write); - } - if (isServerOrHostController(resourceRegistration)) { - resourceRegistration.registerReadOnlyAttribute(STATE, new ElytronRuntimeOnlyHandler() { - - @Override - protected void executeRuntimeStep(OperationContext context, ModelNode operation) { - ServiceName credentialStoreClientServiceName = getCredentialStoreUtil().serviceName(operation); - ServiceController serviceController = context.getServiceRegistry(false).getRequiredService(credentialStoreClientServiceName); - - populateResponse(context.getResult(), serviceController); - } - - }); - } - } - - protected abstract AttributeDefinition[] getAttributeDefinitions(); - - protected void readAliasesOperation(OperationContext context, ModelNode operation, CredentialStore credentialStore) throws OperationFailedException { - try { - try { - List list = new ArrayList<>(); - Set aliases = credentialStore.getAliases(); - for (String s : aliases) { - ModelNode modelNode = new ModelNode(s); - list.add(modelNode); - } - context.getResult().set(list); - } catch (CredentialStoreException e) { - throw LOGGER.unableToCompleteOperation(e, dumpCause(e)); - } - } catch (RuntimeException e) { - e.printStackTrace(); - throw new OperationFailedException(e); - } - } - - protected void removeAliasOperation(OperationContext context, ModelNode operation, CredentialStore credentialStore, Class credentialType) throws OperationFailedException { - try { - try { - String alias = ALIAS.resolveModelAttribute(context, operation).asString(); - - Credential retrieved = credentialStore.retrieve(alias, credentialType); - if (retrieved == null) { - throw LOGGER.credentialDoesNotExist(alias, credentialType.getSimpleName()); - } - credentialStore.remove(alias, credentialType); - context.addResponseWarning(Level.WARNING, LOGGER.updateDependantServices(alias)); - try { - credentialStore.flush(); - } catch (CredentialStoreException e) { - // the operation fails, return removed entry back to the store to avoid an inconsistency - // between the store on the FS and in the memory - credentialStore.store(alias, retrieved); - throw e; - } - } catch (CredentialStoreException e) { - throw LOGGER.unableToCompleteOperation(e, dumpCause(e)); - } - } catch (RuntimeException e) { - throw new OperationFailedException(e); - } - } - - protected void exportSecretKeyOperation(OperationContext context, ModelNode operation, CredentialStore credentialStore) - throws OperationFailedException { - try { - String alias = ALIAS.resolveModelAttribute(context, operation).asString(); - - SecretKeyCredential credential = credentialStore.retrieve(alias, SecretKeyCredential.class); - if (credential == null) { - throw LOGGER.credentialDoesNotExist(alias, SecretKeyCredential.class.getSimpleName()); - } - - SecretKey secretKey = credential.getSecretKey(); - String exportedKey = exportSecretKey(secretKey); - - ModelNode result = context.getResult(); - result.get(Constants.KEY).set(exportedKey); - } catch (GeneralSecurityException e) { - throw LOGGER.secretKeyOperationFailed(Constants.EXPORT_SECRET_KEY, dumpCause(e), e); - } - } - - protected void importSecretKeyOperation(OperationContext context, ModelNode operation, CredentialStore credentialStore) - throws OperationFailedException { - try { - String alias = ALIAS.resolveModelAttribute(context, operation).asString(); - String rawKey = KEY.resolveModelAttribute(context, operation).asString(); - - if (credentialStore.exists(alias, SecretKeyCredential.class)) { - throw LOGGER.credentialAlreadyExists(alias, SecretKeyCredential.class.getName()); - } - - SecretKey secretKey = importSecretKey(rawKey); - - storeSecretKey(credentialStore, alias, secretKey); - - } catch (GeneralSecurityException e) { - throw LOGGER.secretKeyOperationFailed(Constants.IMPORT_SECRET_KEY, dumpCause(e), e); - } - } - - protected void generateSecretKeyOperation(OperationContext context, ModelNode operation, CredentialStore credentialStore, - int keySize) throws OperationFailedException { - try { - String alias = ALIAS.resolveModelAttribute(context, operation).asString(); - - if (credentialStore.exists(alias, SecretKeyCredential.class)) { - throw LOGGER.credentialAlreadyExists(alias, SecretKeyCredential.class.getName()); - } - - SecretKey secretKey = generateSecretKey(keySize); - storeSecretKey(credentialStore, alias, secretKey); - - } catch (GeneralSecurityException e) { - throw LOGGER.secretKeyOperationFailed(Constants.GENERATE_SECRET_KEY, dumpCause(e), e); - } - } - - /** - * Convert {@code char[]} password to {@code PasswordCredential} - * @param password to convert - * @return new {@code PasswordCredential} - * @throws UnsupportedCredentialTypeException should never happen as we have only supported types and algorithms - */ - protected static PasswordCredential createCredentialFromPassword(char[] password) throws UnsupportedCredentialTypeException { - try { - PasswordFactory passwordFactory = PasswordFactory.getInstance(ClearPassword.ALGORITHM_CLEAR); - return new PasswordCredential(passwordFactory.generatePassword(new ClearPasswordSpec(password))); - } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { - throw new UnsupportedCredentialTypeException(e); - } - } - - protected static void storeSecret(CredentialStore credentialStore, String alias, String secretValue) throws CredentialStoreException { - char[] secret = secretValue != null ? secretValue.toCharArray() : new char[0]; - storeCredential(credentialStore, alias, createCredentialFromPassword(secret)); - } - - protected static void storeSecretKey(CredentialStore credentialStore, String alias, SecretKey secretKey) throws CredentialStoreException { - storeCredential(credentialStore, alias, new SecretKeyCredential(secretKey)); - } - - protected static void storeCredential(CredentialStore credentialStore, String alias, Credential credential) throws CredentialStoreException { - credentialStore.store(alias, credential); - try { - credentialStore.flush(); - } catch (CredentialStoreException e) { - // operation fails, remove the entry from the store, to avoid an inconsistency between - // the store on the FS and in the memory - credentialStore.remove(alias, PasswordCredential.class); - throw e; - } - } - - protected static String dumpCause(Throwable e) { - StringBuffer sb = new StringBuffer().append(e.getLocalizedMessage()); - Throwable c = e.getCause(); - int depth = 0; - while(c != null && depth++ < 10) { - sb.append("->").append(c.getLocalizedMessage()); - c = c.getCause() == c ? null : c.getCause(); - } - return sb.toString(); - } - - protected abstract static class AbstractCredentialStoreDoohickey extends ElytronDoohickey { - - protected AbstractCredentialStoreDoohickey(PathAddress resourceAddress) { - super(resourceAddress); - } - - protected abstract void reload(OperationContext context) throws GeneralSecurityException, OperationFailedException; - - } - - protected static class CredentialStoreRuntimeHandler extends ElytronRuntimeOnlyHandler { - - private final Map definedOperations; - - protected CredentialStoreRuntimeHandler(final Map definedOperations) { - this.definedOperations = definedOperations; - } - - @Override - protected void executeRuntimeStep(OperationContext context, ModelNode operation) throws OperationFailedException { - final String operationName = operation.require(ModelDescriptionConstants.OP).asString(); - CredentialStoreRuntimeOperation operationMethod = definedOperations.get(operationName); - if (operationMethod == null) { - throw LOGGER.invalidOperationName(operationName, getExpectedOperationNames()); - } - - CredentialStore credentialStore = getCredentialStore(context); - operationMethod.handle(context, operation, credentialStore); - } - - private String[] getExpectedOperationNames() { - return definedOperations.keySet().toArray(new String[definedOperations.size()]); - } - - protected CredentialStore getCredentialStore(OperationContext context) throws OperationFailedException { - final ExceptionFunction credentialStoreApi = context - .getCapabilityRuntimeAPI(CREDENTIAL_STORE_API_CAPABILITY, context.getCurrentAddressValue(), ExceptionFunction.class); - - return credentialStoreApi.apply(context); - } - - } - - static class CredentialStoreReloadHandler extends ElytronRuntimeOnlyHandler { - - @Override - protected void executeRuntimeStep(OperationContext context, ModelNode operation) throws OperationFailedException { - final ExceptionFunction credentialStoreApi = context - .getCapabilityRuntimeAPI(CREDENTIAL_STORE_API_CAPABILITY, context.getCurrentAddressValue(), ExceptionFunction.class); - - AbstractCredentialStoreDoohickey doohickey = (AbstractCredentialStoreDoohickey) credentialStoreApi; - - try { - doohickey.reload(context); - } catch (GeneralSecurityException e) { - throw LOGGER.unableToReloadCredentialStore(e); - } - - } - - } - - @FunctionalInterface - interface CredentialStoreRuntimeOperation { - - void handle(OperationContext context, ModelNode operation, CredentialStore credentialStore) throws OperationFailedException; - - } -} diff --git a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/CredentialStoreResourceDefinition.java b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/CredentialStoreResourceDefinition.java deleted file mode 100644 index f0038aa..0000000 --- a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/CredentialStoreResourceDefinition.java +++ /dev/null @@ -1,643 +0,0 @@ -/* - * JBoss, Home of Professional Open Source. - * Copyright 2015 Red Hat, Inc., and individual contributors - * as indicated by the @author tags. - * - * 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; - -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; -import static org.wildfly.extension.elytron.tls.Capabilities.CREDENTIAL_STORE_API_CAPABILITY; -import static org.wildfly.extension.elytron.tls.Capabilities.CREDENTIAL_STORE_CAPABILITY; -import static org.wildfly.extension.elytron.tls.Capabilities.CREDENTIAL_STORE_RUNTIME_CAPABILITY; -import static org.wildfly.extension.elytron.tls.Capabilities.PROVIDERS_API_CAPABILITY; -import static org.wildfly.extension.elytron.tls.Capabilities.PROVIDERS_CAPABILITY; -import static org.wildfly.extension.elytron.tls.ElytronTlsExtension.isServerOrHostController; -import static org.wildfly.extension.elytron.tls.FileAttributeDefinitions.pathName; -import static org.wildfly.extension.elytron.tls.FileAttributeDefinitions.pathResolver; -import static org.wildfly.extension.elytron.tls._private.ElytronTLSMessages.LOGGER; - -import java.io.File; -import java.io.IOException; -import java.security.GeneralSecurityException; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.Provider; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.function.Supplier; -import java.util.logging.Level; - -import org.jboss.as.controller.AttributeDefinition; -import org.jboss.as.controller.CapabilityServiceBuilder; -import org.jboss.as.controller.ModelVersion; -import org.jboss.as.controller.ObjectTypeAttributeDefinition; -import org.jboss.as.controller.OperationContext; -import org.jboss.as.controller.OperationFailedException; -import org.jboss.as.controller.OperationStepHandler; -import org.jboss.as.controller.PathAddress; -import org.jboss.as.controller.PathElement; -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.SimpleOperationDefinition; -import org.jboss.as.controller.SimpleOperationDefinitionBuilder; -import org.jboss.as.controller.SimpleResourceDefinition; -import org.jboss.as.controller.capability.RuntimeCapability; -import org.jboss.as.controller.descriptions.ModelDescriptionConstants; -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.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; -import org.jboss.msc.service.StartException; -import org.wildfly.common.function.ExceptionFunction; -import org.wildfly.common.function.ExceptionRunnable; -import org.wildfly.common.function.ExceptionSupplier; -import org.wildfly.extension.elytron.tls.FileAttributeDefinitions.PathResolver; -import org.wildfly.security.EmptyProvider; -import org.wildfly.security.auth.server.IdentityCredentials; -import org.wildfly.security.credential.Credential; -import org.wildfly.security.credential.PasswordCredential; -import org.wildfly.security.credential.SecretKeyCredential; -import org.wildfly.security.credential.source.CredentialSource; -import org.wildfly.security.credential.store.CredentialStore; -import org.wildfly.security.credential.store.CredentialStore.CredentialSourceProtectionParameter; -import org.wildfly.security.credential.store.CredentialStoreException; -import org.wildfly.security.credential.store.impl.KeyStoreCredentialStore; - -/** - * A {@link ResourceDefinition} for a CredentialStore. - * - * @author Peter Skopek - */ -final class CredentialStoreResourceDefinition extends AbstractCredentialStoreResourceDefinition { - - // KeyStore backed credential store supported attributes - private static final String CS_KEY_STORE_TYPE_ATTRIBUTE = "keyStoreType"; - private static final List filebasedKeystoreTypes = Collections.unmodifiableList(Arrays.asList("JKS", "JCEKS", "PKCS12")); - - static final SimpleAttributeDefinition LOCATION = new SimpleAttributeDefinitionBuilder(Constants.LOCATION, ModelType.STRING, true) - .setAttributeGroup(Constants.IMPLEMENTATION) - .setAllowExpression(true) - .setMinSize(1) - .setRestartAllServices() - .setDeprecated(ModelVersion.create(13)) - .setAlternatives(Constants.PATH) - .build(); - - static final SimpleAttributeDefinition MODIFIABLE = new SimpleAttributeDefinitionBuilder(Constants.MODIFIABLE, ModelType.BOOLEAN, true) - .setAttributeGroup(Constants.IMPLEMENTATION) - .setDefaultValue(ModelNode.TRUE) - .setAllowExpression(false) - .setRestartAllServices() - .build(); - - static final SimpleAttributeDefinition CREATE = new SimpleAttributeDefinitionBuilder(Constants.CREATE, ModelType.BOOLEAN, true) - .setAttributeGroup(Constants.IMPLEMENTATION) - .setAllowExpression(false) - .setDefaultValue(ModelNode.FALSE) - .setRestartAllServices() - .build(); - - static final SimpleMapAttributeDefinition IMPLEMENTATION_PROPERTIES = new SimpleMapAttributeDefinition.Builder(Constants.IMPLEMENTATION_PROPERTIES, ModelType.STRING, true) - .setAttributeGroup(Constants.IMPLEMENTATION) - .setAllowExpression(true) - .setRestartAllServices() - .build(); - - static final ObjectTypeAttributeDefinition CREDENTIAL_REFERENCE = CredentialReference.getAttributeDefinition(true); - - static final SimpleAttributeDefinition TYPE = new SimpleAttributeDefinitionBuilder(Constants.TYPE, ModelType.STRING, true) - .setAttributeGroup(Constants.IMPLEMENTATION) - .setAllowExpression(true) - .setMinSize(1) - .setRestartAllServices() - .build(); - - static final SimpleAttributeDefinition PROVIDER_NAME = new SimpleAttributeDefinitionBuilder(Constants.PROVIDER_NAME, ModelType.STRING, true) - .setAttributeGroup(Constants.IMPLEMENTATION) - .setAllowExpression(true) - .setMinSize(1) - .setRestartAllServices() - .build(); - - static final SimpleAttributeDefinition PROVIDERS = new SimpleAttributeDefinitionBuilder(Constants.PROVIDERS, ModelType.STRING, true) - .setAttributeGroup(Constants.IMPLEMENTATION) - .setAllowExpression(false) - .setMinSize(1) - .setRestartAllServices() - .setCapabilityReference(PROVIDERS_CAPABILITY, CREDENTIAL_STORE_CAPABILITY) - .build(); - - static final SimpleAttributeDefinition OTHER_PROVIDERS = new SimpleAttributeDefinitionBuilder(Constants.OTHER_PROVIDERS, ModelType.STRING, true) - .setAttributeGroup(Constants.IMPLEMENTATION) - .setAllowExpression(false) - .setMinSize(1) - .setRestartAllServices() - .setCapabilityReference(PROVIDERS_CAPABILITY, CREDENTIAL_STORE_CAPABILITY) - .build(); - - static final SimpleAttributeDefinition RELATIVE_TO = new SimpleAttributeDefinitionBuilder(Constants.RELATIVE_TO, ModelType.STRING, true) - .setAllowExpression(false) - .setMinSize(1) - .setAttributeGroup(Constants.FILE) - .setRestartAllServices() - .build(); - - static final SimpleAttributeDefinition PATH = new SimpleAttributeDefinitionBuilder(Constants.PATH, ModelType.STRING, true) - .setAllowExpression(true) - .setMinSize(1) - .setAttributeGroup(Constants.FILE) - .setRestartAllServices() - .setAlternatives(Constants.LOCATION) - .build(); - - // Resource Resolver - private static final StandardResourceDescriptionResolver RESOURCE_RESOLVER = ElytronTlsExtension.getResourceDescriptionResolver(Constants.CREDENTIAL_STORE); - - // Operations parameters - - - static final SimpleAttributeDefinition KEY_SIZE = new SimpleAttributeDefinitionBuilder(Constants.KEY_SIZE, ModelType.INT, true) - .setMinSize(1) - .setDefaultValue(new ModelNode(256)) - .setAllowedValues(128, 192, 256) - .build(); - - static final SimpleAttributeDefinition ADD_ENTRY_TYPE; - static final SimpleAttributeDefinition REMOVE_ENTRY_TYPE; - - static { - String[] addEntryTypes = new String[] { PasswordCredential.class.getCanonicalName() }; - ADD_ENTRY_TYPE = new SimpleAttributeDefinitionBuilder(Constants.ENTRY_TYPE, ModelType.STRING, true) - .setAllowedValues(addEntryTypes) - .build(); - String[] removeEntryTypes = new String[] { PasswordCredential.class.getCanonicalName(), PasswordCredential.class.getSimpleName(), - SecretKeyCredential.class.getCanonicalName(), SecretKeyCredential.class.getSimpleName()}; - REMOVE_ENTRY_TYPE = new SimpleAttributeDefinitionBuilder(Constants.ENTRY_TYPE, ModelType.STRING, true) - .setAllowedValues(removeEntryTypes) - .setDefaultValue(new ModelNode(PasswordCredential.class.getSimpleName())) - .build(); - } - - static final SimpleAttributeDefinition SECRET_VALUE = new SimpleAttributeDefinitionBuilder(Constants.SECRET_VALUE, ModelType.STRING, true) - .setMinSize(0) - .build(); - - // Operations - - private static final SimpleOperationDefinition ADD_ALIAS = new SimpleOperationDefinitionBuilder(Constants.ADD_ALIAS, OPERATION_RESOLVER) - .setParameters(ALIAS, ADD_ENTRY_TYPE, SECRET_VALUE) - .setRuntimeOnly() - .build(); - - private static final SimpleOperationDefinition REMOVE_ALIAS = new SimpleOperationDefinitionBuilder(Constants.REMOVE_ALIAS, OPERATION_RESOLVER) - .setParameters(ALIAS, REMOVE_ENTRY_TYPE) - .setRuntimeOnly() - .build(); - - private static final SimpleOperationDefinition SET_SECRET = new SimpleOperationDefinitionBuilder(Constants.SET_SECRET, OPERATION_RESOLVER) - .setParameters(ALIAS, ADD_ENTRY_TYPE, SECRET_VALUE) - .setRuntimeOnly() - .build(); - - private static final SimpleOperationDefinition GENERATE_SECRET_KEY = new SimpleOperationDefinitionBuilder(Constants.GENERATE_SECRET_KEY, OPERATION_RESOLVER) - .setParameters(ALIAS, KEY_SIZE) - .setRuntimeOnly() - .build(); - - private static final AttributeDefinition[] CONFIG_ATTRIBUTES = new AttributeDefinition[] {LOCATION, PATH, CREATE, MODIFIABLE, IMPLEMENTATION_PROPERTIES, CREDENTIAL_REFERENCE, TYPE, PROVIDER_NAME, PROVIDERS, OTHER_PROVIDERS, RELATIVE_TO}; - - private static final CredentialStoreAddHandler ADD = new CredentialStoreAddHandler(); - private static final OperationStepHandler REMOVE = new TrivialCapabilityServiceRemoveHandler(ADD, CREDENTIAL_STORE_RUNTIME_CAPABILITY); - - - CredentialStoreResourceDefinition() { - super(new SimpleResourceDefinition.Parameters(PathElement.pathElement(Constants.CREDENTIAL_STORE), RESOURCE_RESOLVER) - .setAddHandler(ADD) - .setRemoveHandler(REMOVE) - .setAddRestartLevel(OperationEntry.Flag.RESTART_NONE) - .setRemoveRestartLevel(OperationEntry.Flag.RESTART_NONE) - .setCapabilities(CREDENTIAL_STORE_RUNTIME_CAPABILITY) - ); - } - - @Override - protected AttributeDefinition[] getAttributeDefinitions() { - return CONFIG_ATTRIBUTES; - } - - @Override - public void registerOperations(ManagementResourceRegistration resourceRegistration) { - super.registerOperations(resourceRegistration); // Always needed to register add / remove. - - boolean isServerOrHostController = isServerOrHostController(resourceRegistration); - Map operationMethods = new HashMap<>(); - - operationMethods.put(Constants.READ_ALIASES, this::readAliasesOperation); - if (isServerOrHostController) { - operationMethods.put(Constants.ADD_ALIAS, this::addAliasOperation); - operationMethods.put(Constants.REMOVE_ALIAS, this::removeAliasOperation); - operationMethods.put(Constants.SET_SECRET, this::setSecretOperation); - operationMethods.put(Constants.EXPORT_SECRET_KEY, this::exportSecretKeyOperation); - operationMethods.put(Constants.GENERATE_SECRET_KEY, this::generateSecretKeyOperation); - operationMethods.put(Constants.IMPORT_SECRET_KEY, this::importSecretKeyOperation); - } - - OperationStepHandler operationHandler = new CredentialStoreRuntimeHandler(operationMethods); - resourceRegistration.registerOperationHandler(READ_ALIASES, operationHandler); // MAPPED - if (isServerOrHostController) { - resourceRegistration.registerOperationHandler(ADD_ALIAS, operationHandler); // Mapped - resourceRegistration.registerOperationHandler(REMOVE_ALIAS, operationHandler); // Mapped - resourceRegistration.registerOperationHandler(SET_SECRET, operationHandler); // Mapped - resourceRegistration.registerOperationHandler(GENERATE_SECRET_KEY, operationHandler); - resourceRegistration.registerOperationHandler(EXPORT_SECRET_KEY, operationHandler); - resourceRegistration.registerOperationHandler(IMPORT_SECRET_KEY, operationHandler); - resourceRegistration.registerOperationHandler(RELOAD, RELOAD_HANDLER); - } - } - - /* - * Operation Handler Methods - */ - - void addAliasOperation(OperationContext context, ModelNode operation, CredentialStore credentialStore) throws OperationFailedException { - try { - try { - String alias = ALIAS.resolveModelAttribute(context, operation).asString(); - String entryType = ADD_ENTRY_TYPE.resolveModelAttribute(context, operation).asStringOrNull(); - String secretValue = SECRET_VALUE.resolveModelAttribute(context, operation).asStringOrNull(); - if (entryType == null || entryType.equals(PasswordCredential.class.getCanonicalName())) { - if (credentialStore.exists(alias, PasswordCredential.class)) { - throw LOGGER.credentialAlreadyExists(alias, PasswordCredential.class.getName()); - } - storeSecret(credentialStore, alias, secretValue); - } else { - String credentialStoreName = CredentialStoreResourceDefinition.credentialStoreName(operation); - throw LOGGER.credentialStoreEntryTypeNotSupported(credentialStoreName, entryType); - } - } catch (CredentialStoreException e) { - throw LOGGER.unableToCompleteOperation(e, dumpCause(e)); - } - } catch (RuntimeException e) { - throw new OperationFailedException(e); - } - } - - void removeAliasOperation(OperationContext context, ModelNode operation, CredentialStore credentialStore) throws OperationFailedException { - String entryType = REMOVE_ENTRY_TYPE.resolveModelAttribute(context, operation).asString(); - Class credentialType = fromEntryType(entryType); - - super.removeAliasOperation(context, operation, credentialStore, credentialType); - } - - void setSecretOperation(OperationContext context, ModelNode operation, CredentialStore credentialStore) throws OperationFailedException { - try { - try { - String alias = ALIAS.resolveModelAttribute(context, operation).asString(); - String entryType = ADD_ENTRY_TYPE.resolveModelAttribute(context, operation).asStringOrNull(); - String secretValue = SECRET_VALUE.resolveModelAttribute(context, operation).asStringOrNull(); - - if (entryType == null || entryType.equals(PasswordCredential.class.getCanonicalName())) { - if ( ! credentialStore.exists(alias, PasswordCredential.class)) { - throw LOGGER.credentialDoesNotExist(alias, PasswordCredential.class.getName()); - } - storeSecret(credentialStore, alias, secretValue); - context.addResponseWarning(Level.WARNING, LOGGER.reloadDependantServices()); - } else { - String credentialStoreName = CredentialStoreResourceDefinition.credentialStoreName(operation); - throw LOGGER.credentialStoreEntryTypeNotSupported(credentialStoreName, entryType); - } - } catch (CredentialStoreException e) { - throw LOGGER.unableToCompleteOperation(e, dumpCause(e)); - } - } catch (RuntimeException e) { - throw new OperationFailedException(e); - } - } - - protected void generateSecretKeyOperation(OperationContext context, ModelNode operation, CredentialStore credentialStore) throws OperationFailedException { - final int keySize = KEY_SIZE.resolveModelAttribute(context, operation).asInt(); - - generateSecretKeyOperation(context, operation, credentialStore, keySize); - } - - static String credentialStoreName(ModelNode operation) { - String credentialStoreName = null; - PathAddress pa = PathAddress.pathAddress(operation.require(ModelDescriptionConstants.OP_ADDR)); - for (int i = pa.size() - 1; i > 0; i--) { - PathElement pe = pa.getElement(i); - if (Constants.CREDENTIAL_STORE.equals(pe.getKey())) { - credentialStoreName = pe.getValue(); - break; - } - } - - if (credentialStoreName == null) { - throw LOGGER.operationAddressMissingKey(Constants.CREDENTIAL_STORE); - } - - return credentialStoreName; - } - - private static Class fromEntryType(final String entryTyoe) { - if (PasswordCredential.class.getCanonicalName().equals(entryTyoe) || PasswordCredential.class.getSimpleName().equals(entryTyoe)) { - return PasswordCredential.class; - } else if (SecretKeyCredential.class.getCanonicalName().equals(entryTyoe) || SecretKeyCredential.class.getSimpleName().equals(entryTyoe)) { - return SecretKeyCredential.class; - } - - return null; - } - - private static class CredentialStoreAddHandler extends DoohickeyAddHandler { - - private CredentialStoreAddHandler() { - super(CREDENTIAL_STORE_RUNTIME_CAPABILITY, CONFIG_ATTRIBUTES, CREDENTIAL_STORE_API_CAPABILITY); - } - - @Override - protected void populateModel(final OperationContext context, final ModelNode operation, final Resource resource) throws OperationFailedException { - super.populateModel(context, operation, resource); - handleCredentialReferenceUpdate(context, resource.getModel()); - } - - @Override - protected ElytronDoohickey createDoohickey(PathAddress resourceAddress) { - return new CredentialStoreDoohickey(resourceAddress); - } - - @Override - protected void rollbackRuntime(OperationContext context, final ModelNode operation, final Resource resource) { - rollbackCredentialStoreUpdate(CREDENTIAL_REFERENCE, context, resource); - } - } - - static class CredentialStoreDoohickey extends AbstractCredentialStoreDoohickey { - - private final String name; - private volatile String location; - private volatile boolean modifiable; - private volatile String type; - private volatile String providers; - private volatile String otherProviders; - private volatile String providerName; - private volatile String relativeTo; - private volatile Map credentialStoreAttributes; - private volatile ModelNode model; // It would be nice to eliminate but credential reference performs resolution - // and use of values in a single step. - - private volatile ExceptionRunnable reloader; - - protected CredentialStoreDoohickey(PathAddress resourceAddress) { - super(resourceAddress); - this.name = resourceAddress.getLastElement().getValue(); - } - - @Override - protected void resolveRuntime(ModelNode model, OperationContext context) throws OperationFailedException { - location = PATH.resolveModelAttribute(context, model).asStringOrNull(); - if (location == null) { - location = LOCATION.resolveModelAttribute(context, model).asStringOrNull(); - } - credentialStoreAttributes = new HashMap<>(); - modifiable = MODIFIABLE.resolveModelAttribute(context, model).asBoolean(); - credentialStoreAttributes.put(Constants.MODIFIABLE, Boolean.toString(modifiable)); - boolean create = CREATE.resolveModelAttribute(context, model).asBoolean(); - credentialStoreAttributes.put(Constants.CREATE, Boolean.toString(create)); - ModelNode implAttrModel = IMPLEMENTATION_PROPERTIES.resolveModelAttribute(context, model); - if (implAttrModel.isDefined()) { - for (String s : implAttrModel.keys()) { - credentialStoreAttributes.put(s, implAttrModel.require(s).asString()); - } - } - type = TYPE.resolveModelAttribute(context, model).asStringOrNull(); - providers = PROVIDERS.resolveModelAttribute(context, model).asStringOrNull(); - otherProviders = OTHER_PROVIDERS.resolveModelAttribute(context, model).asStringOrNull(); - providerName = PROVIDER_NAME.resolveModelAttribute(context, model).asStringOrNull(); - relativeTo = RELATIVE_TO.resolveModelAttribute(context, model).asStringOrNull(); - if (type == null || type.equals(KeyStoreCredentialStore.KEY_STORE_CREDENTIAL_STORE)) { - credentialStoreAttributes.putIfAbsent(CS_KEY_STORE_TYPE_ATTRIBUTE, "JCEKS"); - } - - String implAttrKeyStoreType = credentialStoreAttributes.get(CS_KEY_STORE_TYPE_ATTRIBUTE); - if (location == null && implAttrKeyStoreType != null && filebasedKeystoreTypes.contains(implAttrKeyStoreType.toUpperCase(Locale.ENGLISH))) { - throw LOGGER.filebasedKeystoreLocationMissing(implAttrKeyStoreType); - } - this.model = model; - } - - @Override - protected ExceptionSupplier prepareServiceSupplier(OperationContext context, - CapabilityServiceBuilder serviceBuilder) throws OperationFailedException { - - final Supplier pathManager; - if (relativeTo != null) { - pathManager = serviceBuilder.requires(PathManagerService.SERVICE_NAME); - serviceBuilder.requires(pathName(relativeTo)); - } else { - pathManager = null; - } - - final Supplier providerSupplier; - if (providers != null) { - String providersCapabilityName = RuntimeCapability.buildDynamicCapabilityName(PROVIDERS_CAPABILITY, providers); - ServiceName providerLoaderServiceName = context.getCapabilityServiceName(providersCapabilityName, - Provider[].class); - - providerSupplier = serviceBuilder.requires(providerLoaderServiceName); - } else { - providerSupplier = null; - } - - final Supplier otherProviderSupplier; - if (otherProviders != null) { - String providersCapabilityName = RuntimeCapability.buildDynamicCapabilityName(PROVIDERS_CAPABILITY, - otherProviders); - ServiceName otherProvidersLoaderServiceName = context.getCapabilityServiceName(providersCapabilityName, - Provider[].class); - - otherProviderSupplier = serviceBuilder.requires(otherProvidersLoaderServiceName); - } else { - otherProviderSupplier = null; - } - - ExceptionSupplier credentialSourceSupplier = CredentialReference - .getCredentialSourceSupplier(context, CredentialStoreResourceDefinition.CREDENTIAL_REFERENCE, model, - serviceBuilder); - - return new ExceptionSupplier() { - - @Override - public CredentialStore get() throws StartException { - try { - if (location != null) { - PathResolver pathResolver = pathResolver(); - pathResolver.path(location); - if (relativeTo != null) { - pathResolver.relativeTo(relativeTo, pathManager.get()); - } - File resolved = pathResolver.resolve(); - pathResolver.clear(); - credentialStoreAttributes.put(Constants.LOCATION, resolved.getAbsolutePath()); - } else { - credentialStoreAttributes.put(Constants.LOCATION, null); - } - - LOGGER.tracef("starting CredentialStore: name = %s", name); - - CredentialStore cs = getCredentialStoreInstance(providerSupplier != null ? providerSupplier.get() : null); - Provider[] otherProvidersArr = otherProviderSupplier != null ? otherProviderSupplier.get() : null; - if (LOGGER.isTraceEnabled()) { - LOGGER.tracef( - "initializing CredentialStore: name = %s type = %s provider = %s otherProviders = %s attributes = %s", - name, type, providerName, Arrays.toString(otherProvidersArr), credentialStoreAttributes); - } - - CredentialSourceProtectionParameter credentialSource = resolveCredentialStoreProtectionParameter(name, - credentialSourceSupplier != null ? credentialSourceSupplier.get() : null); - reloader = new ExceptionRunnable() { - - @Override - public void run() throws GeneralSecurityException { - synchronized (EmptyProvider.getInstance()) { - cs.initialize(credentialStoreAttributes, credentialSource, otherProvidersArr); - } - } - }; - reloader.run(); - - return cs; - } catch (Exception e) { - throw LOGGER.unableToStartService(e); - } - } - - }; - - } - - @Override - protected CredentialStore createImmediately(OperationContext foreignContext) throws OperationFailedException { - File resolvedPath = null; - if (location != null) { - resolvedPath = resolveRelativeToImmediately(location, relativeTo, foreignContext); - credentialStoreAttributes.put(Constants.LOCATION, resolvedPath.getAbsolutePath()); - } - - Provider[] providers = null; - if (this.providers != null) { - ExceptionFunction providerApi = foreignContext - .getCapabilityRuntimeAPI(PROVIDERS_API_CAPABILITY, this.providers, ExceptionFunction.class); - providers = providerApi.apply(foreignContext); - } - - Provider[] otherProviders; - if (this.otherProviders != null) { - ExceptionFunction providerApi = foreignContext - .getCapabilityRuntimeAPI(PROVIDERS_API_CAPABILITY, this.otherProviders, ExceptionFunction.class); - otherProviders = providerApi.apply(foreignContext); - } else { - otherProviders = null; - } - - CredentialSource credentialSource = getCredentialSource(foreignContext, CREDENTIAL_REFERENCE, model); - - try { - CredentialStore credentialStore = getCredentialStoreInstance(providers); - - CredentialSourceProtectionParameter protectionParamter = resolveCredentialStoreProtectionParameter(name, credentialSource); - reloader = new ExceptionRunnable() { - - @Override - public void run() throws GeneralSecurityException { - synchronized (EmptyProvider.getInstance()) { - credentialStore.initialize(credentialStoreAttributes, protectionParamter, otherProviders); - } - } - }; - reloader.run(); - - return credentialStore; - } catch (GeneralSecurityException | IOException e) { - throw LOGGER.unableToInitialiseCredentialStore(e); - } - - } - - @Override - protected void reload(OperationContext context) throws GeneralSecurityException, OperationFailedException { - if (reloader != null) { - reloader.run(); - } else { - super.apply(context); - } - } - - private CredentialStore getCredentialStoreInstance(Provider[] injectedProviders) throws CredentialStoreException, NoSuchAlgorithmException, NoSuchProviderException { - String resolvedType = type != null ? type : KeyStoreCredentialStore.KEY_STORE_CREDENTIAL_STORE; - if (providerName != null) { - // directly specified provider - return CredentialStore.getInstance(resolvedType, providerName); - } - - if (LOGGER.isTraceEnabled()) { - LOGGER.tracef("obtaining CredentialStore %s from providers %s", name, Arrays.toString(injectedProviders)); - } - if (injectedProviders != null) { - // injected provider list, select the first provider with corresponding type - for (Provider p : injectedProviders) { - try { - return CredentialStore.getInstance(resolvedType, p); - } catch (NoSuchAlgorithmException ignore) { - } - } - - throw LOGGER.providerLoaderCannotSupplyProvider(providers, resolvedType); - } else { - // default provider - return CredentialStore.getInstance(resolvedType); - } - } - - private static CredentialSourceProtectionParameter resolveCredentialStoreProtectionParameter(String name, CredentialSource cs) throws IOException { - if (cs != null) { - Credential credential = cs.getCredential(PasswordCredential.class); - - LOGGER.tracef("resolving CredentialStore %s ProtectionParameter from %s", name, credential); - return credentialToCredentialSourceProtectionParameter(credential); - } else { - throw LOGGER.credentialStoreProtectionParameterCannotBeResolved(name); - } - } - - private static CredentialSourceProtectionParameter credentialToCredentialSourceProtectionParameter(Credential credential) { - return new CredentialSourceProtectionParameter(IdentityCredentials.NONE.withCredential(credential)); - } - - } -} diff --git a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/SecretKeyCredentialStoreDefinition.java b/subsystem/src/main/java/org/wildfly/extension/elytron/tls/SecretKeyCredentialStoreDefinition.java deleted file mode 100644 index eb5f49c..0000000 --- a/subsystem/src/main/java/org/wildfly/extension/elytron/tls/SecretKeyCredentialStoreDefinition.java +++ /dev/null @@ -1,320 +0,0 @@ -/* - * Copyright 2021 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; - -import static org.wildfly.extension.elytron.tls.Capabilities.CREDENTIAL_STORE_API_CAPABILITY; -import static org.wildfly.extension.elytron.tls.Capabilities.CREDENTIAL_STORE_RUNTIME_CAPABILITY; -import static org.wildfly.extension.elytron.tls.ElytronTlsExtension.isServerOrHostController; -import static org.wildfly.extension.elytron.tls.FileAttributeDefinitions.RELATIVE_TO; -import static org.wildfly.extension.elytron.tls.FileAttributeDefinitions.pathName; -import static org.wildfly.extension.elytron.tls.FileAttributeDefinitions.pathResolver; -import static org.wildfly.extension.elytron.tls._private.ElytronTLSMessages.LOGGER; -import static org.wildfly.security.encryption.SecretKeyUtil.generateSecretKey; - -import java.io.File; -import java.security.GeneralSecurityException; -import java.util.HashMap; -import java.util.Map; -import java.util.function.Supplier; - -import javax.crypto.SecretKey; - -import org.jboss.as.controller.AbstractAddStepHandler; -import org.jboss.as.controller.AttributeDefinition; -import org.jboss.as.controller.CapabilityServiceBuilder; -import org.jboss.as.controller.OperationContext; -import org.jboss.as.controller.OperationFailedException; -import org.jboss.as.controller.OperationStepHandler; -import org.jboss.as.controller.PathAddress; -import org.jboss.as.controller.PathElement; -import org.jboss.as.controller.SimpleAttributeDefinition; -import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; -import org.jboss.as.controller.SimpleOperationDefinition; -import org.jboss.as.controller.SimpleOperationDefinitionBuilder; -import org.jboss.as.controller.SimpleResourceDefinition; -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; -import org.wildfly.common.function.ExceptionRunnable; -import org.wildfly.common.function.ExceptionSupplier; -import org.wildfly.extension.elytron.tls.FileAttributeDefinitions.PathResolver; -import org.wildfly.security.credential.SecretKeyCredential; -import org.wildfly.security.credential.store.CredentialStore; - -/** - * A resource definitions for a simple credential store which just supports the storage of - * {@link SecretKey} instances stored in the clear. - * - * Whilst the keys are stored in the clear this resource allows administrators to bootstrap in - * an initial key which can be used to encrypt passwords defined within the management model. - * - * @author Darran Lofthouse - */ -class SecretKeyCredentialStoreDefinition extends AbstractCredentialStoreResourceDefinition { - - private static final String CREDENTIAL_STORE_TYPE = "PropertiesCredentialStore"; - - static final SimpleAttributeDefinition PATH = - new SimpleAttributeDefinitionBuilder(Constants.PATH, FileAttributeDefinitions.PATH) - .setAttributeGroup(Constants.FILE) - .setRequired(true) - .setRestartAllServices() - .build(); - - static final SimpleAttributeDefinition CREATE = new SimpleAttributeDefinitionBuilder(Constants.CREATE, ModelType.BOOLEAN, true) - .setAttributeGroup(Constants.IMPLEMENTATION) - .setAllowExpression(true) - .setDefaultValue(ModelNode.TRUE) - .setRestartAllServices() - .build(); - - static final SimpleAttributeDefinition POPULATE = new SimpleAttributeDefinitionBuilder(Constants.POPULATE, ModelType.BOOLEAN, true) - .setAttributeGroup(Constants.IMPLEMENTATION) - .setAllowExpression(true) - .setDefaultValue(ModelNode.TRUE) - .setRestartAllServices() - .build(); - - static final SimpleAttributeDefinition KEY_SIZE = new SimpleAttributeDefinitionBuilder(Constants.KEY_SIZE, ModelType.INT, true) - .setAttributeGroup(Constants.IMPLEMENTATION) - .setAllowExpression(true) - .setDefaultValue(new ModelNode(256)) - .setAllowedValues(128, 192, 256) - .setRestartAllServices() - .build(); - - static final SimpleAttributeDefinition DEFAULT_ALIAS = new SimpleAttributeDefinitionBuilder(Constants.DEFAULT_ALIAS, ModelType.STRING, true) - .setAttributeGroup(Constants.IMPLEMENTATION) - .setAllowExpression(true) - .setDefaultValue(new ModelNode("key")) - .setRestartAllServices() - .build(); - - // Resource Resolver - private static final StandardResourceDescriptionResolver RESOURCE_RESOLVER = ElytronTlsExtension.getResourceDescriptionResolver(Constants.SECRET_KEY_CREDENTIAL_STORE); - - static final AttributeDefinition[] CONFIG_ATTRIBUTES = new AttributeDefinition[] { RELATIVE_TO, PATH, CREATE, POPULATE, KEY_SIZE, DEFAULT_ALIAS }; - - private static final AbstractAddStepHandler ADD = new SecretKeyCredentialStoreAddHandler(); - private static final OperationStepHandler REMOVE = new TrivialCapabilityServiceRemoveHandler(ADD, CREDENTIAL_STORE_RUNTIME_CAPABILITY); - - // Operation Definitions and Parameters - - private static final SimpleOperationDefinition REMOVE_ALIAS = new SimpleOperationDefinitionBuilder(Constants.REMOVE_ALIAS, OPERATION_RESOLVER) - .setParameters(ALIAS) - .setRuntimeOnly() - .build(); - - private static final SimpleAttributeDefinition KEY_SIZE_PARAMETER = new SimpleAttributeDefinitionBuilder(Constants.KEY_SIZE, ModelType.INT, true) - .setAllowExpression(true) - .setAllowedValues(128, 192, 256) - .setRestartAllServices() - .build(); - - private static final SimpleOperationDefinition GENERATE_SECRET_KEY = new SimpleOperationDefinitionBuilder(Constants.GENERATE_SECRET_KEY, OPERATION_RESOLVER) - .setParameters(ALIAS, KEY_SIZE_PARAMETER) - .setRuntimeOnly() - .build(); - - SecretKeyCredentialStoreDefinition() { - super(new SimpleResourceDefinition.Parameters(PathElement.pathElement(Constants.SECRET_KEY_CREDENTIAL_STORE), RESOURCE_RESOLVER) - .setAddHandler(ADD) - .setRemoveHandler(REMOVE) - .setAddRestartLevel(OperationEntry.Flag.RESTART_NONE) - .setRemoveRestartLevel(OperationEntry.Flag.RESTART_NONE) - .setCapabilities(CREDENTIAL_STORE_RUNTIME_CAPABILITY) - ); - } - - @Override - protected AttributeDefinition[] getAttributeDefinitions() { - return CONFIG_ATTRIBUTES; - } - - - @Override - public void registerOperations(ManagementResourceRegistration resourceRegistration) { - super.registerOperations(resourceRegistration); // Always needed to register add / remove. - - boolean isServerOrHostController = isServerOrHostController(resourceRegistration); - Map operationMethods = new HashMap<>(); - - operationMethods.put(Constants.READ_ALIASES, this::readAliasesOperation); - if (isServerOrHostController) { - operationMethods.put(Constants.REMOVE_ALIAS, this::removeAliasOperation); - operationMethods.put(Constants.EXPORT_SECRET_KEY, this::exportSecretKeyOperation); - operationMethods.put(Constants.GENERATE_SECRET_KEY, this::generateSecretKeyOperation); - operationMethods.put(Constants.IMPORT_SECRET_KEY, this::importSecretKeyOperation); - } - - OperationStepHandler operationHandler = new CredentialStoreRuntimeHandler(operationMethods); - resourceRegistration.registerOperationHandler(READ_ALIASES, operationHandler); - if (isServerOrHostController) { - resourceRegistration.registerOperationHandler(REMOVE_ALIAS, operationHandler); - resourceRegistration.registerOperationHandler(EXPORT_SECRET_KEY, operationHandler); - resourceRegistration.registerOperationHandler(GENERATE_SECRET_KEY, operationHandler); - resourceRegistration.registerOperationHandler(IMPORT_SECRET_KEY, operationHandler); - resourceRegistration.registerOperationHandler(RELOAD, RELOAD_HANDLER); - } - } - - /* - * Operation Handler Methods. - */ - - void removeAliasOperation(OperationContext context, ModelNode operation, CredentialStore credentialStore) throws OperationFailedException { - super.removeAliasOperation(context, operation, credentialStore, SecretKeyCredential.class); - } - - protected void generateSecretKeyOperation(OperationContext context, ModelNode operation, CredentialStore credentialStore) throws OperationFailedException { - final int keySize; - ModelNode keySizeModel = KEY_SIZE_PARAMETER.resolveModelAttribute(context, operation); - if (keySizeModel.isDefined()) { - keySize = keySizeModel.asInt(); - } else { - ModelNode resourceModel = context.readResource(PathAddress.EMPTY_ADDRESS).getModel(); - keySize = KEY_SIZE.resolveModelAttribute(context, resourceModel).asInt(); - } - - generateSecretKeyOperation(context, operation, credentialStore, keySize); - } - - static class SecretKeyCredentialStoreAddHandler extends DoohickeyAddHandler { - - private SecretKeyCredentialStoreAddHandler() { - super(CREDENTIAL_STORE_RUNTIME_CAPABILITY, CONFIG_ATTRIBUTES, CREDENTIAL_STORE_API_CAPABILITY); - } - - @Override - protected ElytronDoohickey createDoohickey(PathAddress resourceAddress) { - return new SecretKeyDoohickey(resourceAddress); - } - - } - - static class SecretKeyDoohickey extends AbstractCredentialStoreDoohickey { - - private volatile String relativeTo; - private volatile String path; - private volatile boolean create; - private volatile boolean populate; - private volatile int keySize; - private volatile String defaultAlias; - - private volatile ExceptionRunnable reloader; - - protected SecretKeyDoohickey(PathAddress resourceAddress) { - super(resourceAddress); - } - - @Override - protected void resolveRuntime(ModelNode model, OperationContext context) throws OperationFailedException { - relativeTo = RELATIVE_TO.resolveModelAttribute(context, model).asStringOrNull(); - path = PATH.resolveModelAttribute(context, model).asString(); - create = CREATE.resolveModelAttribute(context, model).asBoolean(); - populate = POPULATE.resolveModelAttribute(context, model).asBoolean(); - keySize = KEY_SIZE.resolveModelAttribute(context, model).asInt(); - defaultAlias = DEFAULT_ALIAS.resolveModelAttribute(context, model).asString(); - } - - @Override - protected ExceptionSupplier prepareServiceSupplier(OperationContext context, - CapabilityServiceBuilder serviceBuilder) { - - final Supplier pathManager; - if (relativeTo != null) { - pathManager = serviceBuilder.requires(PathManagerService.SERVICE_NAME); - serviceBuilder.requires(pathName(relativeTo)); - } else { - pathManager = null; - } - - return new ExceptionSupplier() { - - @Override - public CredentialStore get() throws StartException { - try { - PathResolver pathResolver = pathResolver(); - pathResolver.path(path); - if (relativeTo != null) { - pathResolver.relativeTo(relativeTo, pathManager.get()); - } - File resolved = pathResolver.resolve(); - pathResolver.clear(); - - return createCredentialStore(resolved); - } catch (GeneralSecurityException e) { - throw LOGGER.unableToStartService(e); - } - } - }; - } - - @Override - protected CredentialStore createImmediately(OperationContext foreignContext) throws OperationFailedException { - try { - return createCredentialStore(resolveRelativeToImmediately(path, relativeTo, foreignContext)); - } catch (GeneralSecurityException e) { - throw LOGGER.unableToCreateCredentialStoreImmediately(e); - } - } - - private CredentialStore createCredentialStore(final File resolved) throws GeneralSecurityException { - CredentialStore credentialStore = CredentialStore.getInstance(CREDENTIAL_STORE_TYPE); - - final Map configuration = new HashMap<>(); - configuration.put(Constants.LOCATION, resolved.getAbsolutePath()); - if (create) { - configuration.put(Constants.CREATE, Boolean.TRUE.toString()); - } - - reloader = new ExceptionRunnable() { - - @Override - public void run() throws GeneralSecurityException { - credentialStore.initialize(configuration); - } - }; - reloader.run(); - - if (populate && !credentialStore.getAliases().contains(defaultAlias)) { - SecretKey secretKey = generateSecretKey(keySize); - SecretKeyCredential credential = new SecretKeyCredential(secretKey); - - credentialStore.store(defaultAlias, credential); - credentialStore.flush(); - } - - return credentialStore; - } - - @Override - protected void reload(OperationContext context) throws GeneralSecurityException, OperationFailedException { - if (reloader != null) { - reloader.run(); - } else { - super.apply(context); - } - } - - } - -} diff --git a/subsystem/src/test/resources/org/wildfly/extension/elytron/tls/elytron-subsys.xml.example b/subsystem/src/test/resources/org/wildfly/extension/elytron/tls/elytron-subsys.xml.example deleted file mode 100644 index 7d67ac0..0000000 --- a/subsystem/src/test/resources/org/wildfly/extension/elytron/tls/elytron-subsys.xml.example +++ /dev/null @@ -1,404 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/testsuite/integration/elytron-tls/pom.xml b/testsuite/integration/elytron-tls/pom.xml index 2ea23a1..63d5e95 100644 --- a/testsuite/integration/elytron-tls/pom.xml +++ b/testsuite/integration/elytron-tls/pom.xml @@ -40,6 +40,11 @@ elytron-tls-subsystem test + + org.wildfly.core + wildfly-elytron-integration + test + org.wildfly.core wildfly-core-test-runner