blob: 8fd9279028bcc87a99d412169eb88bbd36961890 [file] [log] [blame]
/**
* 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.test.dom.signature;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.apache.xml.security.signature.XMLSignatureInput;
import org.apache.xml.security.test.dom.DSNamespaceContext;
import org.apache.xml.security.utils.resolver.ResourceResolverContext;
import org.apache.xml.security.utils.resolver.ResourceResolverException;
import org.apache.xml.security.utils.resolver.ResourceResolverSpi;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* An implementation of a resource resolver, which evaluates xpointer expressions.
*
*/
public class XPointerResourceResolver extends ResourceResolverSpi {
private static final org.slf4j.Logger LOG =
org.slf4j.LoggerFactory.getLogger(XPointerResourceResolver.class);
private static final String XP_OPEN = "xpointer(";
private static final String XNS_OPEN = "xmlns(";
private Node baseNode;
public XPointerResourceResolver(Node baseNode) {
this.baseNode = baseNode;
}
@Override
public boolean engineCanResolveURI(ResourceResolverContext context) {
String v = context.uriToResolve;
if (v == null || v.length() <= 0) {
return false;
}
if (v.charAt(0) != '#') {
return false;
}
String xpURI;
try {
xpURI = URLDecoder.decode(v, "utf-8");
} catch (UnsupportedEncodingException e) {
LOG.warn("utf-8 not a valid encoding",e);
return false;
}
String[] parts = xpURI.substring(1).split("\\s");
// plain ID reference.
if (parts.length == 1 && !parts[0].startsWith(XNS_OPEN)) {
return true;
}
int i = 0;
for (; i < parts.length - 1; ++i) {
if (!parts[i].endsWith(")") || !parts[i].startsWith(XNS_OPEN)) {
return false;
}
}
if (!parts[i].endsWith(")") || !parts[i].startsWith(XP_OPEN)) {
return false;
}
LOG.debug("xpURI = " + xpURI);
LOG.debug("BaseURI = " + context.baseUri);
return true;
}
@Override
public XMLSignatureInput engineResolveURI(ResourceResolverContext context)
throws ResourceResolverException {
String v = context.uriToResolve;
if (v.charAt(0) != '#') {
return null;
}
String xpURI;
try {
xpURI = URLDecoder.decode(v, "utf-8");
} catch (UnsupportedEncodingException e) {
LOG.warn("utf-8 not a valid encoding ", e);
return null;
}
String[] parts = xpURI.substring(1).split("\\s");
int i = 0;
Map<String, String> namespaces = new HashMap<>();
if (parts.length > 1) {
for (; i < parts.length - 1; ++i) {
if (!parts[i].endsWith(")") || !parts[i].startsWith(XNS_OPEN)) {
return null;
}
String mapping = parts[i].substring(XNS_OPEN.length(), parts[i].length() - 1);
int pos = mapping.indexOf('=');
if (pos <= 0 || pos >= mapping.length() - 1) {
throw new ResourceResolverException(
"malformed namespace part of XPointer expression", context.uriToResolve, context.baseUri
);
}
namespaces.put(
mapping.substring(0, pos),
mapping.substring(pos + 1)
);
}
}
try {
Node node = null;
NodeList nodes = null;
// plain ID reference.
if (i == 0 && !parts[i].startsWith(XP_OPEN)) {
node = this.baseNode.getOwnerDocument().getElementById(parts[i]);
} else {
if (!parts[i].endsWith(")") || !parts[i].startsWith(XP_OPEN)) {
return null;
}
String xpathExpr = parts[i].substring(XP_OPEN.length(), parts[i].length() - 1);
XPathFactory xpf = XPathFactory.newInstance();
XPath xpath = xpf.newXPath();
DSNamespaceContext namespaceContext =
new DSNamespaceContext(namespaces);
xpath.setNamespaceContext(namespaceContext);
nodes =
(NodeList) xpath.evaluate(
xpathExpr, this.baseNode, XPathConstants.NODESET
);
if (nodes.getLength() == 0) {
return null;
}
if (nodes.getLength() == 1) {
node = nodes.item(0);
}
}
XMLSignatureInput result = null;
if (node != null) {
result = new XMLSignatureInput(node);
} else if (nodes != null) {
Set<Node> nodeSet = new HashSet<>(nodes.getLength());
for (int j = 0; j < nodes.getLength(); ++j) {
nodeSet.add(nodes.item(j));
}
result = new XMLSignatureInput(nodeSet);
} else {
return null;
}
result.setMIMEType("text/xml");
result.setExcludeComments(true);
result.setSourceURI((context.baseUri != null) ? context.baseUri.concat(v) : v);
return result;
} catch (XPathExpressionException e) {
throw new ResourceResolverException(
e, context.uriToResolve, context.baseUri, "Problem evaluating XPath expression"
);
}
}
}