| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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.apache.xml.security.stax.ext; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import javax.xml.namespace.QName; |
| import javax.xml.stream.XMLStreamException; |
| import javax.xml.stream.events.Attribute; |
| |
| import org.apache.xml.security.exceptions.XMLSecurityException; |
| import org.apache.xml.security.stax.ext.stax.XMLSecAttribute; |
| import org.apache.xml.security.stax.ext.stax.XMLSecCharacters; |
| import org.apache.xml.security.stax.ext.stax.XMLSecEndElement; |
| import org.apache.xml.security.stax.ext.stax.XMLSecEvent; |
| import org.apache.xml.security.stax.ext.stax.XMLSecEventFactory; |
| import org.apache.xml.security.stax.ext.stax.XMLSecNamespace; |
| import org.apache.xml.security.stax.ext.stax.XMLSecStartElement; |
| import org.w3c.dom.Attr; |
| import org.w3c.dom.Element; |
| import org.w3c.dom.NamedNodeMap; |
| import org.w3c.dom.Node; |
| import org.w3c.dom.Text; |
| |
| /** |
| * An abstract OutputProcessor class for reusabilty |
| * |
| */ |
| public abstract class AbstractOutputProcessor implements OutputProcessor { |
| |
| protected XMLSecurityProperties securityProperties; |
| protected XMLSecurityConstants.Action action; |
| |
| private XMLSecurityConstants.Phase phase = XMLSecurityConstants.Phase.PROCESSING; |
| private Set<Object> beforeProcessors; |
| private Set<Object> afterProcessors; |
| |
| protected AbstractOutputProcessor() throws XMLSecurityException { |
| super(); |
| } |
| |
| @Override |
| public void setXMLSecurityProperties(XMLSecurityProperties xmlSecurityProperties) { |
| this.securityProperties = xmlSecurityProperties; |
| } |
| |
| @Override |
| public void setAction(XMLSecurityConstants.Action action) { |
| this.action = action; |
| } |
| |
| @Override |
| public void init(OutputProcessorChain outputProcessorChain) throws XMLSecurityException { |
| outputProcessorChain.addProcessor(this); |
| } |
| |
| @Override |
| public XMLSecurityConstants.Phase getPhase() { |
| return phase; |
| } |
| |
| public void setPhase(XMLSecurityConstants.Phase phase) { |
| this.phase = phase; |
| } |
| |
| @Override |
| public void addBeforeProcessor(Object processor) { |
| if (this.beforeProcessors == null) { |
| this.beforeProcessors = new HashSet<>(); |
| } |
| this.beforeProcessors.add(processor); |
| } |
| |
| @Override |
| public Set<Object> getBeforeProcessors() { |
| if (this.beforeProcessors == null) { |
| return Collections.emptySet(); |
| } |
| return this.beforeProcessors; |
| } |
| |
| @Override |
| public void addAfterProcessor(Object processor) { |
| if (this.afterProcessors == null) { |
| this.afterProcessors = new HashSet<>(); |
| } |
| this.afterProcessors.add(processor); |
| } |
| |
| @Override |
| public Set<Object> getAfterProcessors() { |
| if (this.afterProcessors == null) { |
| return Collections.emptySet(); |
| } |
| return this.afterProcessors; |
| } |
| |
| public XMLSecurityProperties getSecurityProperties() { |
| return securityProperties; |
| } |
| |
| public XMLSecurityConstants.Action getAction() { |
| return action; |
| } |
| |
| public abstract void processEvent(XMLSecEvent xmlSecEvent, OutputProcessorChain outputProcessorChain) |
| throws XMLStreamException, XMLSecurityException; |
| |
| @Override |
| public void processNextEvent(XMLSecEvent xmlSecEvent, OutputProcessorChain outputProcessorChain) |
| throws XMLStreamException, XMLSecurityException { |
| processEvent(xmlSecEvent, outputProcessorChain); |
| } |
| |
| @Override |
| public void doFinal(OutputProcessorChain outputProcessorChain) throws XMLStreamException, XMLSecurityException { |
| outputProcessorChain.doFinal(); |
| } |
| |
| public XMLSecStartElement addAttributes(XMLSecStartElement xmlSecStartElement, |
| List<XMLSecAttribute> attributeList) throws XMLStreamException { |
| |
| List<XMLSecNamespace> declaredNamespaces = xmlSecStartElement.getOnElementDeclaredNamespaces(); |
| for (int i = 0; i < attributeList.size(); i++) { |
| XMLSecAttribute xmlSecAttribute = attributeList.get(i); |
| xmlSecStartElement.addAttribute(xmlSecAttribute); |
| |
| final QName attributeName = xmlSecAttribute.getName(); |
| if (attributeName.getNamespaceURI() != null && !"".equals(attributeName.getNamespaceURI()) |
| && !declaredNamespaces.contains(xmlSecAttribute.getAttributeNamespace())) { |
| xmlSecStartElement.addNamespace(xmlSecAttribute.getAttributeNamespace()); |
| } |
| } |
| return xmlSecStartElement; |
| } |
| |
| public void createStartElementAndOutputAsEvent( |
| OutputProcessorChain outputProcessorChain, QName element, |
| List<XMLSecNamespace> namespaces, List<XMLSecAttribute> attributes) |
| throws XMLStreamException, XMLSecurityException { |
| |
| XMLSecStartElement xmlSecStartElement = XMLSecEventFactory.createXmlSecStartElement(element, attributes, namespaces); |
| outputAsEvent(outputProcessorChain, xmlSecStartElement); |
| } |
| |
| public XMLSecStartElement createStartElementAndOutputAsEvent( |
| OutputProcessorChain outputProcessorChain, QName element, |
| boolean outputLocalNs, List<XMLSecAttribute> attributes) throws XMLStreamException, XMLSecurityException { |
| |
| List<XMLSecNamespace> comparableNamespaces = Collections.emptyList(); |
| if (outputLocalNs) { |
| comparableNamespaces = new ArrayList<>(2); |
| comparableNamespaces.add(XMLSecEventFactory.createXMLSecNamespace(element.getPrefix(), element.getNamespaceURI())); |
| } |
| |
| if (attributes != null) { |
| for (int i = 0; i < attributes.size(); i++) { |
| XMLSecAttribute xmlSecAttribute = attributes.get(i); |
| QName attributeName = xmlSecAttribute.getName(); |
| String attributeNamePrefix = attributeName.getPrefix(); |
| |
| if (attributeNamePrefix != null && attributeNamePrefix.isEmpty()) { |
| continue; |
| } |
| |
| if (!comparableNamespaces.contains(xmlSecAttribute.getAttributeNamespace())) { |
| if (comparableNamespaces == Collections.<XMLSecNamespace>emptyList()) { |
| comparableNamespaces = new ArrayList<>(1); |
| } |
| comparableNamespaces.add(xmlSecAttribute.getAttributeNamespace()); |
| } |
| } |
| } |
| XMLSecStartElement xmlSecStartElement |
| = XMLSecEventFactory.createXmlSecStartElement(element, attributes, comparableNamespaces); |
| outputAsEvent(outputProcessorChain, xmlSecStartElement); |
| return xmlSecStartElement; |
| } |
| |
| public XMLSecEndElement createEndElement(QName element) { |
| return XMLSecEventFactory.createXmlSecEndElement(element); |
| } |
| |
| public void createEndElementAndOutputAsEvent(OutputProcessorChain outputProcessorChain, QName element) |
| throws XMLStreamException, XMLSecurityException { |
| outputAsEvent(outputProcessorChain, createEndElement(element)); |
| } |
| |
| public void createCharactersAndOutputAsEvent(OutputProcessorChain outputProcessorChain, String characters) |
| throws XMLStreamException, XMLSecurityException { |
| outputAsEvent(outputProcessorChain, createCharacters(characters)); |
| } |
| |
| public void createCharactersAndOutputAsEvent(OutputProcessorChain outputProcessorChain, char[] text) |
| throws XMLStreamException, XMLSecurityException { |
| outputAsEvent(outputProcessorChain, createCharacters(text)); |
| } |
| |
| public XMLSecCharacters createCharacters(String characters) { |
| return XMLSecEventFactory.createXmlSecCharacters(characters); |
| } |
| |
| public XMLSecCharacters createCharacters(char[] text) { |
| return XMLSecEventFactory.createXmlSecCharacters(text); |
| } |
| |
| public XMLSecAttribute createAttribute(QName attribute, String attributeValue) { |
| return XMLSecEventFactory.createXMLSecAttribute(attribute, attributeValue); |
| } |
| |
| public XMLSecNamespace createNamespace(String prefix, String uri) { |
| return XMLSecEventFactory.createXMLSecNamespace(prefix, uri); |
| } |
| |
| protected void outputAsEvent(OutputProcessorChain outputProcessorChain, XMLSecEvent xmlSecEvent) |
| throws XMLStreamException, XMLSecurityException { |
| outputProcessorChain.reset(); |
| outputProcessorChain.processEvent(xmlSecEvent); |
| } |
| |
| protected SecurePart securePartMatches(XMLSecStartElement xmlSecStartElement, |
| OutputProcessorChain outputProcessorChain, String dynamicParts) { |
| Map<Object, SecurePart> dynamicSecureParts = outputProcessorChain.getSecurityContext().getAsMap(dynamicParts); |
| return securePartMatches(xmlSecStartElement, dynamicSecureParts); |
| } |
| |
| protected SecurePart securePartMatches(XMLSecStartElement xmlSecStartElement, Map<Object, SecurePart> secureParts) { |
| SecurePart securePart = null; |
| if (secureParts != null) { |
| securePart = secureParts.get(xmlSecStartElement.getName()); |
| if (securePart == null) { |
| Attribute attribute = xmlSecStartElement.getAttributeByName(securityProperties.getIdAttributeNS()); |
| if (attribute != null) { |
| securePart = secureParts.get(attribute.getValue()); |
| } |
| } |
| } |
| return securePart; |
| } |
| |
| protected void outputDOMElement(Element element, OutputProcessorChain outputProcessorChain) |
| throws XMLStreamException, XMLSecurityException { |
| |
| NamedNodeMap namedNodeMap = element.getAttributes(); |
| List<XMLSecAttribute> attributes = new ArrayList<>(namedNodeMap.getLength()); |
| List<XMLSecNamespace> namespaces = new ArrayList<>(namedNodeMap.getLength()); |
| for (int i = 0; i < namedNodeMap.getLength(); i++) { |
| Attr attribute = (Attr) namedNodeMap.item(i); |
| if (attribute.getPrefix() == null) { |
| attributes.add( |
| createAttribute( |
| new QName(attribute.getNamespaceURI(), attribute.getLocalName()), attribute.getValue())); |
| } else if ("xmlns".equals(attribute.getPrefix()) || "xmlns".equals(attribute.getLocalName())) { |
| namespaces.add(createNamespace(attribute.getLocalName(), attribute.getValue())); |
| } else { |
| attributes.add( |
| createAttribute( |
| new QName(attribute.getNamespaceURI(), attribute.getLocalName(), attribute.getPrefix()), |
| attribute.getValue())); |
| } |
| } |
| |
| QName elementName = new QName(element.getNamespaceURI(), element.getLocalName(), element.getPrefix()); |
| createStartElementAndOutputAsEvent(outputProcessorChain, elementName, namespaces, attributes); |
| Node childNode = element.getFirstChild(); |
| while (childNode != null) { |
| if (Node.ELEMENT_NODE == childNode.getNodeType()) { |
| outputDOMElement((Element) childNode, outputProcessorChain); |
| } else if (Node.TEXT_NODE == childNode.getNodeType()) { |
| createCharactersAndOutputAsEvent(outputProcessorChain, ((Text) childNode).getData()); |
| } |
| childNode = childNode.getNextSibling(); |
| } |
| createEndElementAndOutputAsEvent(outputProcessorChain, elementName); |
| } |
| } |