Sensible XPath processing optimizations.
This commit is contained in:
parent
cc46504126
commit
618b8a5dab
|
|
@ -0,0 +1,87 @@
|
|||
package org.jasig.cas.client.util;
|
||||
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
import javax.xml.namespace.NamespaceContext;
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.xpath.*;
|
||||
|
||||
/**
|
||||
* Thread local XPath expression.
|
||||
*
|
||||
* @author Marvin S. Addison
|
||||
* @since 3.3
|
||||
*/
|
||||
public class ThreadLocalXPathExpression extends ThreadLocal<XPathExpression> implements XPathExpression {
|
||||
|
||||
/** XPath expression */
|
||||
private String expression;
|
||||
|
||||
/** Namespace context. */
|
||||
private NamespaceContext context;
|
||||
|
||||
/**
|
||||
* Creates a new instance from an XPath expression and namespace context.
|
||||
*
|
||||
* @param xPath XPath expression.
|
||||
* @param context Namespace context for handling namespace prefix to URI mappings.
|
||||
*/
|
||||
public ThreadLocalXPathExpression(final String xPath, final NamespaceContext context) {
|
||||
this.expression = xPath;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public Object evaluate(final Object o, final QName qName) throws XPathExpressionException {
|
||||
return get().evaluate(o, qName);
|
||||
}
|
||||
|
||||
public String evaluate(final Object o) throws XPathExpressionException {
|
||||
return get().evaluate(o);
|
||||
}
|
||||
|
||||
public Object evaluate(final InputSource inputSource, final QName qName) throws XPathExpressionException {
|
||||
return get().evaluate(inputSource, qName);
|
||||
}
|
||||
|
||||
public String evaluate(final InputSource inputSource) throws XPathExpressionException {
|
||||
return get().evaluate(inputSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates the XPath expression and returns the result coerced to a string.
|
||||
*
|
||||
* @param o Object on which to evaluate the expression; typically a DOM node.
|
||||
*
|
||||
* @return Evaluation result as a string.
|
||||
*
|
||||
* @throws XPathExpressionException On XPath evaluation errors.
|
||||
*/
|
||||
public String evaluateAsString(final Object o) throws XPathExpressionException {
|
||||
return (String) evaluate(o, XPathConstants.STRING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates the XPath expression and returns the result coerced to a node list.
|
||||
*
|
||||
* @param o Object on which to evaluate the expression; typically a DOM node.
|
||||
*
|
||||
* @return Evaluation result as a node list.
|
||||
*
|
||||
* @throws XPathExpressionException On XPath evaluation errors.
|
||||
*/
|
||||
public NodeList evaluateAsNodeList(final Object o) throws XPathExpressionException {
|
||||
return (NodeList) evaluate(o, XPathConstants.NODESET);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected XPathExpression initialValue() {
|
||||
try {
|
||||
final XPath xPath = XPathFactory.newInstance().newXPath();
|
||||
xPath.setNamespaceContext(context);
|
||||
return xPath.compile(expression);
|
||||
} catch (XPathExpressionException e) {
|
||||
throw new IllegalArgumentException("Invalid XPath expression");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -24,7 +24,6 @@ import java.util.*;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
|
|
@ -32,11 +31,9 @@ import org.xml.sax.XMLReader;
|
|||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
import javax.xml.XMLConstants;
|
||||
import javax.xml.namespace.NamespaceContext;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
import javax.xml.xpath.*;
|
||||
|
||||
/**
|
||||
* Common utilities for easily parsing XML without duplicating logic.
|
||||
|
|
@ -80,65 +77,6 @@ public final class XmlUtils {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compiles the given XPath expression.
|
||||
*
|
||||
* @param expression XPath expression.
|
||||
* @param nsContext XML namespace context for resolving namespace prefixes in XPath expressions.
|
||||
*
|
||||
* @return Compiled XPath expression.
|
||||
*/
|
||||
public static XPathExpression compileXPath(final String expression, final NamespaceContext nsContext) {
|
||||
try {
|
||||
final XPath xPath = XPathFactory.newInstance().newXPath();
|
||||
xPath.setNamespaceContext(nsContext);
|
||||
return xPath.compile(expression);
|
||||
} catch (XPathExpressionException e) {
|
||||
throw new IllegalArgumentException("Invalid XPath expression");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Evaluates the given XPath expression as a string result.
|
||||
*
|
||||
* @param expression XPath expression.
|
||||
* @param nsContext XML namespace context for resolving namespace prefixes in XPath expressions.
|
||||
* @param document DOM document on which to evaluate expression.
|
||||
*
|
||||
* @return Evaluated XPath expression as a string.
|
||||
*/
|
||||
public static String evaluateXPathString(
|
||||
final String expression, final NamespaceContext nsContext, final Document document) {
|
||||
try {
|
||||
return (String) compileXPath(expression, nsContext).evaluate(document, XPathConstants.STRING);
|
||||
} catch (XPathExpressionException e) {
|
||||
throw new RuntimeException("XPath evaluation error", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Evaluates the given XPath expression as a node list result.
|
||||
*
|
||||
* @param expression XPath expression.
|
||||
* @param nsContext XML namespace context for resolving namespace prefixes in XPath expressions.
|
||||
* @param document DOM document on which to evaluate expression.
|
||||
*
|
||||
* @return Evaluated XPath expression as a node list.
|
||||
*/
|
||||
public static NodeList evaluateXPathNodeList(
|
||||
final String expression, final NamespaceContext nsContext, final Document document) {
|
||||
try {
|
||||
return (NodeList) compileXPath(expression, nsContext).evaluate(document, XPathConstants.NODESET);
|
||||
} catch (XPathExpressionException e) {
|
||||
throw new RuntimeException("XPath evaluation error", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get an instance of an XML reader from the XMLReaderFactory.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -26,10 +26,7 @@ import java.security.NoSuchAlgorithmException;
|
|||
import java.security.SecureRandom;
|
||||
import java.util.*;
|
||||
import org.jasig.cas.client.authentication.AttributePrincipalImpl;
|
||||
import org.jasig.cas.client.util.CommonUtils;
|
||||
import org.jasig.cas.client.util.IOUtils;
|
||||
import org.jasig.cas.client.util.MapNamespaceContext;
|
||||
import org.jasig.cas.client.util.XmlUtils;
|
||||
import org.jasig.cas.client.util.*;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.joda.time.Interval;
|
||||
|
|
@ -54,25 +51,30 @@ public final class Saml11TicketValidator extends AbstractUrlBasedTicketValidator
|
|||
private static final String SAML_REQUEST_TEMPLATE;
|
||||
|
||||
/** SAML 1.1. namespace context. */
|
||||
private static final NamespaceContext SAML_NS_CONTEXT = new MapNamespaceContext(
|
||||
private static final NamespaceContext NS_CONTEXT = new MapNamespaceContext(
|
||||
"soap->http://schemas.xmlsoap.org/soap/envelope/",
|
||||
"sa->urn:oasis:names:tc:SAML:1.0:assertion",
|
||||
"sp->urn:oasis:names:tc:SAML:1.0:protocol");
|
||||
|
||||
/** XPath expression to extract Assertion validity start date. */
|
||||
private static final String XPATH_ASSERTION_DATE_START = "//sa:Assertion/sa:Conditions/@NotBefore";
|
||||
private static final ThreadLocalXPathExpression XPATH_ASSERTION_DATE_START =
|
||||
new ThreadLocalXPathExpression("//sa:Assertion/sa:Conditions/@NotBefore", NS_CONTEXT);
|
||||
|
||||
/** XPath expression to extract Assertion validity end date. */
|
||||
private static final String XPATH_ASSERTION_DATE_END = "//sa:Assertion/sa:Conditions/@NotOnOrAfter";
|
||||
private static final ThreadLocalXPathExpression XPATH_ASSERTION_DATE_END =
|
||||
new ThreadLocalXPathExpression("//sa:Assertion/sa:Conditions/@NotOnOrAfter", NS_CONTEXT);
|
||||
|
||||
/** XPath expression to extract NameIdentifier. */
|
||||
private static final String XPATH_NAME_ID = "//sa:AuthenticationStatement/sa:Subject/sa:NameIdentifier";
|
||||
private static final ThreadLocalXPathExpression XPATH_NAME_ID =
|
||||
new ThreadLocalXPathExpression("//sa:AuthenticationStatement/sa:Subject/sa:NameIdentifier", NS_CONTEXT);
|
||||
|
||||
/** XPath expression to extract authentication method. */
|
||||
private static final String XPATH_AUTH_METHOD = "//sa:AuthenticationStatement/@AuthenticationMethod";
|
||||
private static final ThreadLocalXPathExpression XPATH_AUTH_METHOD =
|
||||
new ThreadLocalXPathExpression("//sa:AuthenticationStatement/@AuthenticationMethod", NS_CONTEXT);
|
||||
|
||||
/** XPath expression to extract attributes. */
|
||||
private static final String XPATH_ATTRIBUTES = "//sa:AttributeStatement/sa:Attribute";
|
||||
private static final ThreadLocalXPathExpression XPATH_ATTRIBUTES =
|
||||
new ThreadLocalXPathExpression("//sa:AttributeStatement/sa:Attribute", NS_CONTEXT);
|
||||
|
||||
private static final String HEX_CHARS = "0123456789abcdef";
|
||||
|
||||
|
|
@ -118,18 +120,18 @@ public final class Saml11TicketValidator extends AbstractUrlBasedTicketValidator
|
|||
try {
|
||||
final Document document = XmlUtils.newDocument(response);
|
||||
final Date assertionValidityStart = CommonUtils.parseUtcDate(
|
||||
XmlUtils.evaluateXPathString(XPATH_ASSERTION_DATE_START, SAML_NS_CONTEXT, document));
|
||||
XPATH_ASSERTION_DATE_START.evaluateAsString(document));
|
||||
final Date assertionValidityEnd = CommonUtils.parseUtcDate(
|
||||
XmlUtils.evaluateXPathString(XPATH_ASSERTION_DATE_END, SAML_NS_CONTEXT, document));
|
||||
XPATH_ASSERTION_DATE_END.evaluateAsString(document));
|
||||
if (!isValidAssertion(assertionValidityStart, assertionValidityEnd)) {
|
||||
throw new TicketValidationException("Invalid SAML assertion");
|
||||
}
|
||||
final String nameId = XmlUtils.evaluateXPathString(XPATH_NAME_ID, SAML_NS_CONTEXT, document);
|
||||
final String nameId = XPATH_NAME_ID.evaluateAsString(document);
|
||||
if (nameId == null) {
|
||||
throw new TicketValidationException("SAML assertion does not contain NameIdentifier element");
|
||||
}
|
||||
final String authMethod = XmlUtils.evaluateXPathString(XPATH_AUTH_METHOD, SAML_NS_CONTEXT, document);
|
||||
final NodeList attributes = XmlUtils.evaluateXPathNodeList(XPATH_ATTRIBUTES, SAML_NS_CONTEXT, document);
|
||||
final String authMethod = XPATH_AUTH_METHOD.evaluateAsString(document);
|
||||
final NodeList attributes = XPATH_ATTRIBUTES.evaluateAsNodeList(document);
|
||||
final Map<String, Object> principalAttributes = new HashMap<String, Object>(attributes.getLength());
|
||||
Element attribute;
|
||||
NodeList values;
|
||||
|
|
|
|||
Loading…
Reference in New Issue