/* * Copyright 2008 Federal Chancellery Austria and * Graz University of Technology * * 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 at.gv.egiz.bku.slcommands.impl.xsect; import java.util.Iterator; import javax.xml.XMLConstants; import javax.xml.namespace.NamespaceContext; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpression; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Node; import at.buergerkarte.namespaces.securitylayer._1.SignatureInfoCreationType; import at.gv.egiz.bku.slexceptions.SLCommandException; import at.gv.egiz.slbinding.impl.SignatureLocationType; /** * This class implements the SignatureLocation of an XML-Signature * to be created by the security layer command CreateXMLSignature. * * @author mcentner */ public class SignatureLocation { /** * Logging facility. */ private final Logger log = LoggerFactory.getLogger(SignatureLocation.class); /** * The SignatureContext for the XML signature */ private SignatureContext ctx; /** * The parent node for the XML signature. */ private Node parent; /** * The next sibling node for the XML signature. */ private Node nextSibling; /** * Creates a new SignatureLocation with the given signatureContext * * @param signatureContext the context for the XML signature creation */ public SignatureLocation(SignatureContext signatureContext) { this.ctx = signatureContext; } /** * @return the parent node for the XML signature */ public Node getParent() { return parent; } /** * @param parent the parent for the XML signature */ public void setParent(Node parent) { this.parent = parent; } /** * @return the next sibling node for the XML signature */ public Node getNextSibling() { return nextSibling; } /** * @param nextSibling the next sibling node for the XML signature */ public void setNextSibling(Node nextSibling) { this.nextSibling = nextSibling; } /** * Configures this SignatureLocation with the information provided by the * given SignatureInfo element. * * @param signatureInfo * the SignatureInfo element * * @throws SLCommandException * if configuring this SignatureLocation with given * signatureInfofails */ public void setSignatureInfo(SignatureInfoCreationType signatureInfo) throws SLCommandException { // evaluate signature location XPath ... SignatureLocationType signatureLocation = (SignatureLocationType) signatureInfo .getSignatureLocation(); NamespaceContext namespaceContext = new MOAIDWorkaroundNamespaceContext( signatureLocation.getNamespaceContext()); parent = evaluateSignatureLocation(signatureInfo.getSignatureLocation() .getValue(), namespaceContext, ctx.getDocument().getDocumentElement()); // ... and index nextSibling = findNextSibling(parent, signatureInfo.getSignatureLocation() .getIndex().intValue()); } /** * Evaluates the given xpath with the document element as context node * and returns the resulting node. * * @param xpath the XPath expression * @param nsContext the namespace context of the XPath expression * @param contextNode the context node for the XPath evaluation * * @return the result of evaluating the XPath expression * * @throws SLCommandException */ private Node evaluateSignatureLocation(String xpath, NamespaceContext nsContext, Node contextNode) throws SLCommandException { Node node = null; try { XPathFactory xpathFactory = XPathFactory.newInstance(); XPath xPath = xpathFactory.newXPath(); xPath.setNamespaceContext(nsContext); XPathExpression xpathExpr = xPath.compile(xpath); node = (Node) xpathExpr.evaluate(contextNode, XPathConstants.NODE); } catch (XPathExpressionException e) { log.info("Failed to evaluate SignatureLocation XPath expression '{}' on context node.", xpath, e); throw new SLCommandException(4102); } if (node == null) { log.info("Failed to evaluate SignatureLocation XPath expression '{}'. Result is empty.", xpath); throw new SLCommandException(4102); } return node; } /** * Finds the next sibling node of the parent's n-th child node * or null if there is no next sibling. * * @param parent the parent node * @param n the index of the child node * * @return the next sibling node of the node specified by parent and index n, * or null if there is no next sibling node. * * @throws SLCommandException if the n-th child of parent does not exist */ private Node findNextSibling(Node parent, int n) throws SLCommandException { return parent.getChildNodes().item(n); } /** * Workaround for a missing namespace prefix declaration in MOA-ID. * * @author mcentner */ private class MOAIDWorkaroundNamespaceContext implements NamespaceContext { private NamespaceContext namespaceContext; public MOAIDWorkaroundNamespaceContext(NamespaceContext namespaceContext) { super(); this.namespaceContext = namespaceContext; } @Override public String getNamespaceURI(String prefix) { String namespaceURI = namespaceContext.getNamespaceURI(prefix); if ((namespaceURI == null || XMLConstants.NULL_NS_URI.equals(namespaceURI)) && "saml".equals(prefix)) { namespaceURI = "urn:oasis:names:tc:SAML:1.0:assertion"; log.debug("Namespace prefix '{}' resolved to '{}' (MOA-ID Workaround).", prefix, namespaceURI); } else { log.trace("Namespace prefix '{}' resolved to '{}'.", prefix, namespaceURI); } return namespaceURI; } @Override public String getPrefix(String namespaceURI) { return namespaceContext.getPrefix(namespaceURI); } @Override public Iterator getPrefixes(String namespaceURI) { return namespaceContext.getPrefixes(namespaceURI); } } }