/*
* 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.OP_ADDR;
import static org.jboss.as.controller.parsing.ParseUtils.invalidAttributeValue;
import static org.jboss.as.controller.parsing.ParseUtils.missingRequired;
import static org.jboss.as.controller.parsing.ParseUtils.requireNoAttributes;
import static org.jboss.as.controller.parsing.ParseUtils.requireNoContent;
import static org.jboss.as.controller.parsing.ParseUtils.requireNoNamespaceAttribute;
import static org.jboss.as.controller.parsing.ParseUtils.unexpectedAttribute;
import static org.jboss.as.controller.parsing.ParseUtils.unexpectedElement;
import static org.jboss.as.security.Constants.ELYTRON_KEY_MANAGER;
import static org.jboss.as.security.Constants.ELYTRON_KEY_STORE;
import static org.jboss.as.security.Constants.ELYTRON_REALM;
import static org.jboss.as.security.Constants.ELYTRON_TRUST_MANAGER;
import static org.jboss.as.security.Constants.ELYTRON_TRUST_STORE;
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.EnumSet;
import java.util.List;
import javax.xml.stream.XMLStreamException;
import org.jboss.as.controller.PathAddress;
import org.jboss.as.controller.PathElement;
import org.jboss.as.controller.operations.common.Util;
import org.jboss.dmr.ModelNode;
import org.jboss.staxmapper.XMLExtendedStreamReader;
/**
* This class implements a parser for the 3.0 version of legacy security subsystem. It extends the {@link SecuritySubsystemParser}
* and adds support for the {@code elytron-integration} section of the schema.
*
* @author <a href="mailto:sguilhen@redhat.com">Stefan Guilhen</a>
*/
public class SecuritySubsystemParser_3_0 extends SecuritySubsystemParser {
protected SecuritySubsystemParser_3_0() {
}
@Override
protected void readElement(final XMLExtendedStreamReader reader, final Element element, final List<ModelNode> operations,
final PathAddress subsystemPath, final ModelNode subsystemNode) throws XMLStreamException {
switch(element) {
case ELYTRON_INTEGRATION: {
requireNoAttributes(reader);
while (reader.hasNext() && reader.nextTag() != END_ELEMENT) {
final Element innerElement = Element.forName(reader.getLocalName());
switch (innerElement) {
case SECURITY_REALMS: {
parseSecurityRealms(reader, operations, subsystemPath);
break;
}
case TLS: {
parseTLS(reader, operations, subsystemPath);
break;
}
default: {
throw unexpectedElement(reader);
}
}
}
break;
}
default: {
super.readElement(reader, element, operations, subsystemPath, subsystemNode);
}
}
}
protected void parseSecurityRealms(final XMLExtendedStreamReader reader, final List<ModelNode> operations,
final PathAddress subsystemPath) throws XMLStreamException {
requireNoAttributes(reader);
while (reader.hasNext() && reader.nextTag() != END_ELEMENT) {
final Element element = Element.forName(reader.getLocalName());
switch (element) {
case ELYTRON_REALM: {
parseElytronRealm(reader, operations, subsystemPath);
break;
}
default: {
throw unexpectedElement(reader);
}
}
}
}
protected void parseElytronRealm(final XMLExtendedStreamReader reader, final List<ModelNode> operations,
final PathAddress subsystemPath) throws XMLStreamException {
final ModelNode elytronRealmAddOperation = Util.createAddOperation();
PathElement elytronRealmPath = null;
final EnumSet<Attribute> required = EnumSet.of(Attribute.NAME, Attribute.LEGACY_JAAS_CONFIG);
final int count = reader.getAttributeCount();
for (int i = 0; i < count; i++) {
requireNoNamespaceAttribute(reader, i);
final String value = reader.getAttributeValue(i);
final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
required.remove(attribute);
switch (attribute) {
case NAME: {
if (value == null || value.length() == 0) {
throw invalidAttributeValue(reader, i);
}
elytronRealmPath = PathElement.pathElement(ELYTRON_REALM, value);
break;
}
case LEGACY_JAAS_CONFIG: {
LEGACY_JAAS_CONFIG.parseAndSetParameter(value, elytronRealmAddOperation, reader);
break;
}
default:
throw unexpectedAttribute(reader, i);
}
}
if (required.size() > 0) {
throw missingRequired(reader, required);
}
elytronRealmAddOperation.get(OP_ADDR).set(subsystemPath.append(elytronRealmPath).toModelNode());
operations.add(elytronRealmAddOperation);
requireNoContent(reader);
}
protected void parseTLS(final XMLExtendedStreamReader reader, final List<ModelNode> operations,
final PathAddress subsystemPath) throws XMLStreamException {
requireNoAttributes(reader);
while (reader.hasNext() && reader.nextTag() != END_ELEMENT) {
final Element element = Element.forName(reader.getLocalName());
switch (element) {
case ELYTRON_KEY_STORE: {
parseTLSEntity(reader, operations, subsystemPath, ELYTRON_KEY_STORE);
break;
}
case ELYTRON_TRUST_STORE: {
parseTLSEntity(reader, operations, subsystemPath, ELYTRON_TRUST_STORE);
break;
}
case ELYTRON_KEY_MANAGER: {
parseTLSEntity(reader, operations, subsystemPath, ELYTRON_KEY_MANAGER);
break;
}
case ELYTRON_TRUST_MANAGER: {
parseTLSEntity(reader, operations, subsystemPath, ELYTRON_TRUST_MANAGER);
break;
}
default: {
throw unexpectedElement(reader);
}
}
}
}
protected void parseTLSEntity(final XMLExtendedStreamReader reader, final List<ModelNode> operations,
final PathAddress subsystemPath, final String tlsEntityName) throws XMLStreamException {
final ModelNode elytronTLSEntityAddOperation = Util.createAddOperation();
PathElement elytronTLSEntityPath = null;
final EnumSet<Attribute> required = EnumSet.of(Attribute.NAME, Attribute.LEGACY_JSSE_CONFIG);
final int count = reader.getAttributeCount();
for (int i = 0; i < count; i++) {
requireNoNamespaceAttribute(reader, i);
final String value = reader.getAttributeValue(i);
final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
required.remove(attribute);
switch (attribute) {
case NAME: {
if (value == null || value.length() == 0) {
throw invalidAttributeValue(reader, i);
}
elytronTLSEntityPath = PathElement.pathElement(tlsEntityName, value);
break;
}
case LEGACY_JSSE_CONFIG: {
LEGACY_JSSE_CONFIG.parseAndSetParameter(value, elytronTLSEntityAddOperation, reader);
break;
}
default:
throw unexpectedAttribute(reader, i);
}
}
if (required.size() > 0) {
throw missingRequired(reader, required);
}
elytronTLSEntityAddOperation.get(OP_ADDR).set(subsystemPath.append(elytronTLSEntityPath).toModelNode());
operations.add(elytronTLSEntityAddOperation);
requireNoContent(reader);
}
}