/* * JBoss, Home of Professional Open Source. * Copyright 2012, Red Hat, Inc., and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.as.domain.management.audit; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.AUTHENTICATION; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.CLIENT_CERT_STORE; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP_ADDR; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.PROTOCOL; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.TRUSTSTORE; import java.util.List; import java.util.Locale; import java.util.Set; import org.jboss.as.controller.AbstractAddStepHandler; import org.jboss.as.controller.AbstractRemoveStepHandler; import org.jboss.as.controller.AttributeDefinition; import org.jboss.as.controller.ModelVersion; 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.SimpleResourceDefinition; import org.jboss.as.controller.audit.ManagedAuditLogger; import org.jboss.as.controller.audit.SyslogAuditLogHandler; import org.jboss.as.controller.descriptions.ModelDescriptionConstants; import org.jboss.as.controller.descriptions.ResourceDescriptionResolver; import org.jboss.as.controller.operations.common.Util; import org.jboss.as.controller.registry.ManagementResourceRegistration; import org.jboss.as.controller.registry.Resource; import org.jboss.as.controller.registry.Resource.ResourceEntry; import org.jboss.as.controller.services.path.PathManagerService; import org.jboss.as.domain.management._private.DomainManagementResolver; import org.jboss.as.domain.management.logging.DomainManagementLogger; import org.jboss.as.domain.management.security.KeystoreAttributes; import org.jboss.dmr.ModelNode; import org.jboss.dmr.ModelType; /** * * @author <a href="kabir.khan@jboss.com">Kabir Khan</a> */ public abstract class SyslogAuditLogProtocolResourceDefinition extends SimpleResourceDefinition { public static final SimpleAttributeDefinition HOST = new SimpleAttributeDefinitionBuilder(ModelDescriptionConstants.HOST, ModelType.STRING) .setAllowNull(true) .setDefaultValue(new ModelNode("localhost")) .setAllowExpression(true) .setMinSize(1) .build(); public static final SimpleAttributeDefinition PORT = new SimpleAttributeDefinitionBuilder(ModelDescriptionConstants.PORT, ModelType.INT) .setAllowNull(true) .setDefaultValue(new ModelNode(514)) .setAllowExpression(true) .build(); protected final ManagedAuditLogger auditLogger; protected final PathManagerService pathManager; protected final EnvironmentNameReader environmentReader; protected final AttributeDefinition[] attributes; SyslogAuditLogProtocolResourceDefinition(ManagedAuditLogger auditLogger, PathManagerService pathManager, AttributeDefinition[] attributes, PathElement pathElement, ResourceDescriptionResolver resolver, EnvironmentNameReader environmentReader) { super( pathElement, resolver, new ProtocolConfigAddHandler(auditLogger, pathManager, attributes, environmentReader), new ProtocolConfigRemoveHandler(auditLogger, pathManager, environmentReader)); this.auditLogger = auditLogger; this.pathManager = pathManager; this.attributes = attributes; this.environmentReader = environmentReader; setDeprecated(ModelVersion.create(1, 7)); } @Override public void registerAttributes(ManagementResourceRegistration resourceRegistration) { OperationStepHandler handler = new SyslogAuditLogHandlerResourceDefinition.HandlerWriteAttributeHandler(auditLogger, pathManager, environmentReader, attributes); for (AttributeDefinition def : attributes){ resourceRegistration.registerReadWriteAttribute(def, null, handler); } } public static void createServerAddOperations(final List<ModelNode> addOps, final PathAddress protocolAddress, final ModelNode protocol) { addOps.add(createProtocolAddOperation(protocolAddress, protocol)); final SyslogAuditLogHandler.Transport transport = SyslogAuditLogHandler.Transport.valueOf(protocolAddress.getLastElement().getValue().toUpperCase(Locale.ENGLISH)); if (transport == SyslogAuditLogHandler.Transport.TLS){ if (protocol.hasDefined(AUTHENTICATION)){ final ModelNode auth = protocol.get(AUTHENTICATION); if (auth.hasDefined(TRUSTSTORE)){ addOps.add(createKeystoreAddOperation(protocolAddress.append(AUTHENTICATION, TRUSTSTORE), protocol.get(AUTHENTICATION, TRUSTSTORE))); } if (auth.hasDefined(CLIENT_CERT_STORE)){ addOps.add(createKeystoreAddOperation(protocolAddress.append(AUTHENTICATION, CLIENT_CERT_STORE), protocol.get(AUTHENTICATION, CLIENT_CERT_STORE))); } } } } public static ModelNode createProtocolAddOperation(final PathAddress protocolAddress, final ModelNode protocol){ ModelNode protocolAdd = Util.createAddOperation(protocolAddress); protocolAdd.get(HOST.getName()).set(protocol.get(HOST.getName())); protocolAdd.get(PORT.getName()).set(protocol.get(PORT.getName())); SyslogAuditLogHandler.Transport transport = SyslogAuditLogHandler.Transport.valueOf(protocolAddress.getLastElement().getValue().toUpperCase(Locale.ENGLISH)); if (transport != SyslogAuditLogHandler.Transport.UDP){ protocolAdd.get(Tcp.MESSAGE_TRANSFER.getName()).set(protocol.get(Tcp.MESSAGE_TRANSFER.getName())); } return protocolAdd; } public static ModelNode createKeystoreAddOperation(final PathAddress storeAddress, final ModelNode store){ ModelNode storeAdd = Util.createAddOperation(storeAddress); for (AttributeDefinition def : TlsKeyStore.CLIENT_CERT_ATTRIBUTES){ storeAdd.get(def.getName()).set(store.get(def.getName())); } return storeAdd; } public static class Udp extends SyslogAuditLogProtocolResourceDefinition { public static final PathElement PATH_ELEMENT = PathElement.pathElement(PROTOCOL, ModelDescriptionConstants.UDP); private static final AttributeDefinition[] ATTRIBUTES = new AttributeDefinition[]{HOST, PORT}; Udp(ManagedAuditLogger auditLogger, PathManagerService pathManager, EnvironmentNameReader environmentReader) { super(auditLogger, pathManager, ATTRIBUTES, PATH_ELEMENT, DomainManagementResolver.getDeprecatedResolver(AccessAuditResourceDefinition.DEPRECATED_MESSAGE_CATEGORY, "core.management.syslog-udp"), environmentReader); } Udp(ManagedAuditLogger auditLogger, PathManagerService pathManager, AttributeDefinition[] attributes, PathElement pathElement, ResourceDescriptionResolver resolver, EnvironmentNameReader environmentReader) { super(auditLogger, pathManager, attributes, pathElement, resolver, environmentReader); } } public static class Tcp extends Udp { public static final PathElement PATH_ELEMENT = PathElement.pathElement(PROTOCOL, ModelDescriptionConstants.TCP); public static final SimpleAttributeDefinition MESSAGE_TRANSFER = new SimpleAttributeDefinitionBuilder(ModelDescriptionConstants.MESSAGE_TRANSFER, ModelType.STRING) .setAllowNull(true) .setDefaultValue(new ModelNode(SyslogAuditLogHandler.MessageTransfer.NON_TRANSPARENT_FRAMING.name())) .setAllowExpression(true) .build(); public static final SimpleAttributeDefinition RECONNECT_TIMEOUT = new SimpleAttributeDefinitionBuilder(ModelDescriptionConstants.RECONNECT_TIMEOUT, ModelType.INT) .setAllowNull(true) .setDefaultValue(new ModelNode(-1)) .setAllowExpression(true) .build(); private static final AttributeDefinition[] ATTRIBUTES = new AttributeDefinition[]{HOST, PORT, MESSAGE_TRANSFER, RECONNECT_TIMEOUT}; Tcp(ManagedAuditLogger auditLogger, PathManagerService pathManager, EnvironmentNameReader environmentReader) { super(auditLogger, pathManager, ATTRIBUTES, PATH_ELEMENT, DomainManagementResolver.getDeprecatedResolver(AccessAuditResourceDefinition.DEPRECATED_MESSAGE_CATEGORY, "core.management.syslog-tcp"), environmentReader); } Tcp(ManagedAuditLogger auditLogger, PathManagerService pathManager, AttributeDefinition[] attributes, PathElement pathElement, ResourceDescriptionResolver resolver, EnvironmentNameReader environmentReader) { super(auditLogger, pathManager, attributes, pathElement, resolver, environmentReader); } } public static class Tls extends Tcp { public static final PathElement PATH_ELEMENT = PathElement.pathElement(PROTOCOL, ModelDescriptionConstants.TLS); private static final AttributeDefinition[] ATTRIBUTES = new AttributeDefinition[]{HOST, PORT, MESSAGE_TRANSFER, RECONNECT_TIMEOUT}; Tls(ManagedAuditLogger auditLogger, PathManagerService pathManager, EnvironmentNameReader environmentReader) { super(auditLogger, pathManager, ATTRIBUTES, PATH_ELEMENT, DomainManagementResolver.getDeprecatedResolver(AccessAuditResourceDefinition.DEPRECATED_MESSAGE_CATEGORY, "core.management.syslog-tls"), environmentReader); } @Override public void registerChildren(ManagementResourceRegistration resourceRegistration) { resourceRegistration.registerSubModel(TlsKeyStore.createTrustStore(auditLogger, pathManager, environmentReader)); resourceRegistration.registerSubModel(TlsKeyStore.createClientCertStore(auditLogger, pathManager, environmentReader)); } } public static class TlsKeyStore extends SimpleResourceDefinition { public static final PathElement TRUSTSTORE_ELEMENT = PathElement.pathElement(AUTHENTICATION, TRUSTSTORE); public static final PathElement CLIENT_CERT_ELEMENT = PathElement.pathElement(AUTHENTICATION, CLIENT_CERT_STORE); public static final SimpleAttributeDefinition KEYSTORE_PASSWORD = KeystoreAttributes.KEYSTORE_PASSWORD; public static final SimpleAttributeDefinition KEYSTORE_PATH = KeystoreAttributes.KEYSTORE_PATH; public static final SimpleAttributeDefinition KEYSTORE_RELATIVE_TO = KeystoreAttributes.KEYSTORE_RELATIVE_TO; public static final SimpleAttributeDefinition KEY_PASSWORD = KeystoreAttributes.KEY_PASSWORD; private static final AttributeDefinition[] CLIENT_CERT_ATTRIBUTES = new AttributeDefinition[]{ KEYSTORE_PASSWORD, KEYSTORE_PATH, KEYSTORE_RELATIVE_TO, KEY_PASSWORD}; private static final AttributeDefinition[] TRUSTSTORE_ATTRIBUTES = new AttributeDefinition[]{ KEYSTORE_PASSWORD, KEYSTORE_PATH, KEYSTORE_RELATIVE_TO}; private final ManagedAuditLogger auditLogger; private final PathManagerService pathManager; private final AttributeDefinition[] attributes; private final EnvironmentNameReader environmentReader; private TlsKeyStore(ManagedAuditLogger auditLogger, PathManagerService pathManager, PathElement pathElement, ResourceDescriptionResolver resolver, AttributeDefinition[] attributes, EnvironmentNameReader environmentReader) { super(pathElement, resolver, new TlsKeyStoreAddHandler(auditLogger, pathManager, attributes, environmentReader), new ProtocolConfigRemoveHandler(auditLogger, pathManager, environmentReader)); this.auditLogger = auditLogger; this.pathManager = pathManager; this.attributes = attributes; this.environmentReader = environmentReader; } static TlsKeyStore createTrustStore(ManagedAuditLogger auditLogger, PathManagerService pathManager, EnvironmentNameReader environmentReader) { return new TlsKeyStore(auditLogger, pathManager, TRUSTSTORE_ELEMENT, DomainManagementResolver.getResolver("core.management.syslog-truststore"), TRUSTSTORE_ATTRIBUTES, environmentReader); } static TlsKeyStore createClientCertStore(ManagedAuditLogger auditLogger, PathManagerService pathManager, EnvironmentNameReader environmentReader) { return new TlsKeyStore(auditLogger, pathManager, CLIENT_CERT_ELEMENT, DomainManagementResolver.getResolver("core.management.syslog-client-cert-store"), CLIENT_CERT_ATTRIBUTES, environmentReader); } @Override public void registerAttributes(ManagementResourceRegistration resourceRegistration) { OperationStepHandler handler = new SyslogAuditLogHandlerResourceDefinition.HandlerWriteAttributeHandler(auditLogger, pathManager, environmentReader, CLIENT_CERT_ATTRIBUTES); for (AttributeDefinition attr : attributes){ resourceRegistration.registerReadWriteAttribute(attr, null, handler); } } } /** * Attribute writes on the handler or sub-resources, as well as protocol removes might/should be done as a composite, * which means that we might get to the runtime part several times. So if this is an update validate what we have * with the original handler to make sure that only the first update takes effect */ private static class ProtocolConfigRemoveHandler extends AbstractRemoveStepHandler { private final ManagedAuditLogger auditLogger; private final PathManagerService pathManager; private final EnvironmentNameReader environmentReader; public ProtocolConfigRemoveHandler(ManagedAuditLogger auditLogger, PathManagerService pathManager, EnvironmentNameReader environmentReader) { this.pathManager = pathManager; this.auditLogger = auditLogger; this.environmentReader = environmentReader; } protected boolean requiresRuntime(OperationContext context){ return true; } @Override protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException { PathAddress handlerAddress = SyslogAuditLogHandlerResourceDefinition.getAffectedHandlerAddress(context); try { Resource handleResource = context.readResourceFromRoot(handlerAddress); String name = Util.getNameFromAddress(handlerAddress); auditLogger.getUpdater().updateHandler(SyslogAuditLogHandlerResourceDefinition.createHandler(pathManager, context, name, handleResource, environmentReader)); } catch (Resource.NoSuchResourceException ignored) { // WFCORE-810 handler resource has been removed in this same op, so we do nothing } } @Override protected void recoverServices(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException { auditLogger.getUpdater().rollbackChanges(); } } private static class ProtocolConfigAddHandler extends AbstractAddStepHandler { private final ManagedAuditLogger auditLogger; private final PathManagerService pathManager; private final AttributeDefinition[] attributes; private final EnvironmentNameReader environmentReader; ProtocolConfigAddHandler(ManagedAuditLogger auditLogger, PathManagerService pathManager, AttributeDefinition[] attributes, EnvironmentNameReader environmentReader){ this.auditLogger = auditLogger; this.pathManager = pathManager; this.attributes = attributes; this.environmentReader = environmentReader; } @Override protected void populateModel(OperationContext context, ModelNode operation, Resource resource) throws OperationFailedException { checkNoOtherProtocol(context, operation); ModelNode model = resource.getModel(); for (AttributeDefinition def: attributes){ def.validateAndSet(operation, model); } } private void checkNoOtherProtocol(OperationContext context, ModelNode operation) throws OperationFailedException { PathAddress opAddr = PathAddress.pathAddress(operation.require(OP_ADDR)); PathAddress addr = opAddr.subAddress(0, opAddr.size() - 1); Resource resource = context.readResourceFromRoot(addr); Set<ResourceEntry> existing = resource.getChildren(PROTOCOL); if (existing.size() > 1) { for (ResourceEntry entry : existing) { PathElement mine = addr.getLastElement(); if (!entry.getPathElement().equals(mine)) { throw DomainManagementLogger.ROOT_LOGGER.sysLogProtocolAlreadyConfigured(addr.append(mine)); } } } } @Override protected boolean requiresRuntime(OperationContext context) { //On boot, the parent add will pick up these changes return !context.isBooting(); } @Override protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException { auditLogger.getUpdater().updateHandler(SyslogAuditLogHandlerResourceDefinition.createHandler(pathManager, context, environmentReader)); } @Override protected void rollbackRuntime(OperationContext context, ModelNode operation, Resource resource) { auditLogger.getUpdater().rollbackChanges(); } } private static class TlsKeyStoreAddHandler extends AbstractAddStepHandler { private final ManagedAuditLogger auditLogger; private final PathManagerService pathManager; private final AttributeDefinition[] attributes; private final EnvironmentNameReader environmentReader; TlsKeyStoreAddHandler(ManagedAuditLogger auditLogger, PathManagerService pathManager, AttributeDefinition[] attributes, EnvironmentNameReader environmentReader) { this.auditLogger = auditLogger; this.pathManager = pathManager; this.attributes = attributes; this.environmentReader = environmentReader; } @Override protected void populateModel(ModelNode operation, ModelNode model) throws OperationFailedException { for (AttributeDefinition def : attributes){ def.validateAndSet(operation, model); } } @Override protected boolean requiresRuntime(OperationContext context) { //On boot, the parent add will pick up these changes return !context.isBooting(); } @Override protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException { auditLogger.getUpdater().updateHandler(SyslogAuditLogHandlerResourceDefinition.createHandler(pathManager, context, environmentReader)); } @Override protected void rollbackRuntime(OperationContext context, ModelNode operation, Resource resource) { auditLogger.getUpdater().rollbackChanges(); } } }