/* * Copyright 2016 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.jboss.as.security; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.CODE; import static org.jboss.as.security.Constants.*; import static org.jboss.as.security.elytron.ElytronIntegrationResourceDefinitions.LEGACY_JAAS_CONFIG; import static org.jboss.as.security.elytron.ElytronIntegrationResourceDefinitions.LEGACY_JSSE_CONFIG; import java.util.List; import java.util.Set; import javax.xml.stream.XMLStreamException; import org.jboss.as.controller.persistence.SubsystemMarshallingContext; import org.jboss.dmr.ModelNode; import org.jboss.dmr.Property; import org.jboss.staxmapper.XMLElementWriter; import org.jboss.staxmapper.XMLExtendedStreamWriter; /** * A {@link XMLElementWriter} that is responsible for writing the configuration of the legacy security subsystem. The * subsystem is written according to the current (latest) version of the schema. * * @author <a href="mailto:sguilhen@redhat.com">Stefan Guilhen</a> */ public class SecuritySubsystemPersister implements XMLElementWriter<SubsystemMarshallingContext> { public static final SecuritySubsystemPersister INSTANCE = new SecuritySubsystemPersister(); protected SecuritySubsystemPersister() { } @Override public void writeContent(XMLExtendedStreamWriter writer, SubsystemMarshallingContext context) throws XMLStreamException { context.startSubsystemElement(Namespace.CURRENT.getUriString(), false); ModelNode node = context.getModelNode(); if (SecuritySubsystemRootResourceDefinition.DEEP_COPY_SUBJECT_MODE.isMarshallable(node) || SecuritySubsystemRootResourceDefinition.INITIALIZE_JACC.isMarshallable(node)) { writer.writeEmptyElement(Element.SECURITY_MANAGEMENT.getLocalName()); if (SecuritySubsystemRootResourceDefinition.DEEP_COPY_SUBJECT_MODE.isMarshallable(node)) { SecuritySubsystemRootResourceDefinition.DEEP_COPY_SUBJECT_MODE.marshallAsAttribute(node, writer); } if (SecuritySubsystemRootResourceDefinition.INITIALIZE_JACC.isMarshallable(node)) { SecuritySubsystemRootResourceDefinition.INITIALIZE_JACC.marshallAsAttribute(node, writer); } } if (node.hasDefined(SECURITY_DOMAIN) && node.get(SECURITY_DOMAIN).asInt() > 0) { writer.writeStartElement(Element.SECURITY_DOMAINS.getLocalName()); ModelNode securityDomains = node.get(SECURITY_DOMAIN); for (String policy : securityDomains.keys()) { writer.writeStartElement(Element.SECURITY_DOMAIN.getLocalName()); writer.writeAttribute(Attribute.NAME.getLocalName(), policy); ModelNode policyDetails = securityDomains.get(policy); SecurityDomainResourceDefinition.CACHE_TYPE.marshallAsAttribute(policyDetails, writer); writeSecurityDomainContent(writer, policyDetails); writer.writeEndElement(); } writer.writeEndElement(); } if (node.hasDefined(Constants.VAULT)) { ModelNode vault = node.get(Constants.VAULT, Constants.CLASSIC); writer.writeStartElement(Element.VAULT.getLocalName()); VaultResourceDefinition.CODE.marshallAsAttribute(vault, writer); if (vault.hasDefined(Constants.VAULT_OPTIONS)) { ModelNode properties = vault.get(Constants.VAULT_OPTIONS); for (Property prop : properties.asPropertyList()) { writer.writeEmptyElement(Element.VAULT_OPTION.getLocalName()); writer.writeAttribute(Attribute.NAME.getLocalName(), prop.getName()); writer.writeAttribute(Attribute.VALUE.getLocalName(), prop.getValue().asString()); } } writer.writeEndElement(); } writeElytronIntegration(writer, node); writer.writeEndElement(); } private void writeSecurityDomainContent(XMLExtendedStreamWriter writer, ModelNode policyDetails) throws XMLStreamException { Set<String> keys = policyDetails.keys(); keys.remove(NAME); keys.remove(CACHE_TYPE); for (String key : keys) { Element element = Element.forName(key); switch (element) { case AUTHENTICATION: { ModelNode kind = policyDetails.get(AUTHENTICATION); for (Property prop : kind.asPropertyList()) { if (CLASSIC.equals(prop.getName())) { writeAuthentication(writer, prop.getValue()); } else if (JASPI.equals(prop.getName())) { writeAuthenticationJaspi(writer, prop.getValue()); } } break; } case AUTHORIZATION: { writeAuthorization(writer, policyDetails.get(AUTHORIZATION, CLASSIC)); break; } case ACL: { writeACL(writer, policyDetails.get(ACL, CLASSIC)); break; } case AUDIT: { writeAudit(writer, policyDetails.get(AUDIT, CLASSIC)); break; } case IDENTITY_TRUST: { writeIdentityTrust(writer, policyDetails.get(IDENTITY_TRUST, CLASSIC)); break; } case MAPPING: { writeMapping(writer, policyDetails.get(MAPPING, CLASSIC)); break; } case JSSE: { writeJSSE(writer, policyDetails.get(JSSE, CLASSIC)); break; } } } } private void writeAuthentication(XMLExtendedStreamWriter writer, ModelNode modelNode) throws XMLStreamException { if (modelNode.isDefined() && modelNode.asInt() > 0) { writer.writeStartElement(Element.AUTHENTICATION.getLocalName()); writeLoginModule(writer, modelNode, Constants.LOGIN_MODULE); writer.writeEndElement(); } } private void writeAuthorization(XMLExtendedStreamWriter writer, ModelNode modelNode) throws XMLStreamException { if (modelNode.isDefined() && modelNode.asInt() > 0) { writer.writeStartElement(Element.AUTHORIZATION.getLocalName()); writeLoginModule(writer, modelNode, Constants.POLICY_MODULE, Element.POLICY_MODULE.getLocalName()); writer.writeEndElement(); } } private void writeACL(XMLExtendedStreamWriter writer, ModelNode modelNode) throws XMLStreamException { if (modelNode.isDefined() && modelNode.asInt() > 0) { writer.writeStartElement(Element.ACL.getLocalName()); writeLoginModule(writer, modelNode, Constants.ACL_MODULE, Element.ACL_MODULE.getLocalName()); writer.writeEndElement(); } } private void writeAudit(XMLExtendedStreamWriter writer, ModelNode modelNode) throws XMLStreamException { if (modelNode.isDefined() && modelNode.asInt() > 0) { writer.writeStartElement(Element.AUDIT.getLocalName()); writeLoginModule(writer, modelNode, Constants.PROVIDER_MODULE, Element.PROVIDER_MODULE.getLocalName()); writer.writeEndElement(); } } private void writeIdentityTrust(XMLExtendedStreamWriter writer, ModelNode modelNode) throws XMLStreamException { if (modelNode.isDefined() && modelNode.asInt() > 0) { writer.writeStartElement(Element.IDENTITY_TRUST.getLocalName()); writeLoginModule(writer, modelNode, Constants.TRUST_MODULE, Element.TRUST_MODULE.getLocalName()); writer.writeEndElement(); } } private void writeMapping(XMLExtendedStreamWriter writer, ModelNode modelNode) throws XMLStreamException { if (modelNode.isDefined() && modelNode.asInt() > 0) { writer.writeStartElement(Element.MAPPING.getLocalName()); writeLoginModule(writer, modelNode, Constants.MAPPING_MODULE, Constants.MAPPING_MODULE); writer.writeEndElement(); } } private void writeAuthenticationJaspi(XMLExtendedStreamWriter writer, ModelNode modelNode) throws XMLStreamException { if (modelNode.isDefined() && modelNode.asInt() > 0) { writer.writeStartElement(Element.AUTHENTICATION_JASPI.getLocalName()); ModelNode moduleStack = modelNode.get(LOGIN_MODULE_STACK); writeLoginModuleStack(writer, moduleStack); writeLoginModule(writer, modelNode, Constants.AUTH_MODULE, Element.AUTH_MODULE.getLocalName()); writer.writeEndElement(); } } private void writeLoginModuleStack(XMLExtendedStreamWriter writer, ModelNode modelNode) throws XMLStreamException { if (modelNode.isDefined() && modelNode.asInt() > 0) { List<Property> stacks = modelNode.asPropertyList(); for (Property stack : stacks) { writer.writeStartElement(Element.LOGIN_MODULE_STACK.getLocalName()); writer.writeAttribute(Attribute.NAME.getLocalName(), stack.getName()); writeLoginModule(writer, stack.getValue(), Constants.LOGIN_MODULE); writer.writeEndElement(); } } } private void writeLoginModule(XMLExtendedStreamWriter writer, ModelNode modelNode, String key) throws XMLStreamException { writeLoginModule(writer, modelNode, key, Element.LOGIN_MODULE.getLocalName()); } private void writeLoginModule(XMLExtendedStreamWriter writer, ModelNode modelNode, String key, final String elementName) throws XMLStreamException { if (!modelNode.hasDefined(key)){ return; } final ModelNode modules = modelNode.get(key); for (Property moduleProp : modules.asPropertyList()) { ModelNode module = moduleProp.getValue(); writer.writeStartElement(elementName); if (!moduleProp.getName().equals(module.get(CODE).asString())) { writer.writeAttribute(NAME, moduleProp.getName()); } LoginModuleResourceDefinition.CODE.marshallAsAttribute(module, writer); LoginModuleResourceDefinition.FLAG.marshallAsAttribute(module, writer); MappingModuleDefinition.TYPE.marshallAsAttribute(module, writer); JASPIMappingModuleDefinition.LOGIN_MODULE_STACK_REF.marshallAsAttribute(module, writer); LoginModuleResourceDefinition.MODULE.marshallAsAttribute(module, false, writer); if (module.hasDefined(Constants.MODULE_OPTIONS)) { for (ModelNode option : module.get(Constants.MODULE_OPTIONS).asList()) { writer.writeEmptyElement(Element.MODULE_OPTION.getLocalName()); writer.writeAttribute(Attribute.NAME.getLocalName(), option.asProperty().getName()); writer.writeAttribute(Attribute.VALUE.getLocalName(), option.asProperty().getValue().asString()); } } writer.writeEndElement(); } } private void writeJSSE(XMLExtendedStreamWriter writer, ModelNode modelNode) throws XMLStreamException { if (modelNode.isDefined() && modelNode.asInt() > 0) { writer.writeStartElement(Element.JSSE.getLocalName()); JSSEResourceDefinition.KEYSTORE.marshallAsAttribute(modelNode, false, writer); JSSEResourceDefinition.TRUSTSTORE.marshallAsAttribute(modelNode, false, writer); JSSEResourceDefinition.KEYMANAGER.marshallAsAttribute(modelNode, false, writer); JSSEResourceDefinition.TRUSTMANAGER.marshallAsAttribute(modelNode, false, writer); JSSEResourceDefinition.CIPHER_SUITES.marshallAsAttribute(modelNode, false, writer); JSSEResourceDefinition.SERVER_ALIAS.marshallAsAttribute(modelNode, false, writer); JSSEResourceDefinition.SERVICE_AUTH_TOKEN.marshallAsAttribute(modelNode, false, writer); JSSEResourceDefinition.CLIENT_ALIAS.marshallAsAttribute(modelNode, false, writer); JSSEResourceDefinition.CLIENT_AUTH.marshallAsAttribute(modelNode, false, writer); JSSEResourceDefinition.PROTOCOLS.marshallAsAttribute(modelNode, false, writer); JSSEResourceDefinition.ADDITIONAL_PROPERTIES.marshallAsElement(modelNode, writer); writer.writeEndElement(); } } private void writeElytronIntegration(final XMLExtendedStreamWriter writer, final ModelNode modelNode) throws XMLStreamException { boolean integrationStarted = false; integrationStarted = integrationStarted | writeSecurityRealms(writer, modelNode, integrationStarted); integrationStarted = integrationStarted | writeTLS(writer, modelNode, integrationStarted); if (integrationStarted) { writer.writeEndElement(); } } private boolean writeSecurityRealms(final XMLExtendedStreamWriter writer, final ModelNode modelNode, final boolean integrationStarted) throws XMLStreamException { if (modelNode.hasDefined(ELYTRON_REALM)) { if (integrationStarted == false) { writer.writeStartElement(ELYTRON_INTEGRATION); } writer.writeStartElement(SECURITY_REALMS); ModelNode elytronRealms = modelNode.require(ELYTRON_REALM); for (String realmName : elytronRealms.keys()) { writer.writeStartElement(ELYTRON_REALM); writer.writeAttribute(NAME, realmName); LEGACY_JAAS_CONFIG.marshallAsAttribute(elytronRealms.require(realmName), writer); writer.writeEndElement(); } writer.writeEndElement(); return true; } return false; } private boolean writeTLS(final XMLExtendedStreamWriter writer, final ModelNode modelNode, final boolean integrationStarted) throws XMLStreamException { if (modelNode.hasDefined(ELYTRON_KEY_STORE) || modelNode.hasDefined(ELYTRON_TRUST_STORE) || modelNode.hasDefined(ELYTRON_KEY_MANAGER) || modelNode.hasDefined(ELYTRON_TRUST_MANAGER)) { if (integrationStarted == false) { writer.writeStartElement(ELYTRON_INTEGRATION); } writer.writeStartElement(TLS); writeTLSEntity(writer, modelNode, ELYTRON_KEY_STORE); writeTLSEntity(writer, modelNode, ELYTRON_TRUST_STORE); writeTLSEntity(writer, modelNode, ELYTRON_KEY_MANAGER); writeTLSEntity(writer, modelNode, ELYTRON_TRUST_MANAGER); writer.writeEndElement(); return true; } return false; } private void writeTLSEntity(final XMLExtendedStreamWriter writer, final ModelNode modelNode, final String tlsEntityName) throws XMLStreamException { if (modelNode.hasDefined(tlsEntityName)) { ModelNode tlsEntities = modelNode.require(tlsEntityName); for (String entityName : tlsEntities.keys()) { writer.writeStartElement(tlsEntityName); writer.writeAttribute(NAME, entityName); LEGACY_JSSE_CONFIG.marshallAsAttribute(tlsEntities.require(entityName), writer); writer.writeEndElement(); } } } }