Details
diff --git a/saml-core/src/main/java/org/keycloak/saml/common/parsers/AbstractParser.java b/saml-core/src/main/java/org/keycloak/saml/common/parsers/AbstractParser.java
index fd12b63..7e7daa5 100755
--- a/saml-core/src/main/java/org/keycloak/saml/common/parsers/AbstractParser.java
+++ b/saml-core/src/main/java/org/keycloak/saml/common/parsers/AbstractParser.java
@@ -33,6 +33,9 @@ import javax.xml.stream.events.Characters;
import javax.xml.stream.events.XMLEvent;
import javax.xml.stream.util.EventReaderDelegate;
import java.io.InputStream;
+import javax.xml.transform.Source;
+import javax.xml.transform.dom.DOMSource;
+import org.w3c.dom.Node;
/**
* Base class for parsers
@@ -49,28 +52,28 @@ public abstract class AbstractParser implements ParserNamespaceSupport {
protected XMLInputFactory initialValue() {
return getXMLInputFactory();
}
- };
- /**
- * Get the JAXP {@link XMLInputFactory}
- *
- * @return
- */
- private static XMLInputFactory getXMLInputFactory() {
- boolean tccl_jaxp = SystemPropertiesUtil.getSystemProperty(GeneralConstants.TCCL_JAXP, "false")
- .equalsIgnoreCase("true");
- ClassLoader prevTCCL = SecurityActions.getTCCL();
- try {
- if (tccl_jaxp) {
- SecurityActions.setTCCL(AbstractParser.class.getClassLoader());
- }
- return XMLInputFactory.newInstance();
- } finally {
- if (tccl_jaxp) {
- SecurityActions.setTCCL(prevTCCL);
+ /**
+ * Get the JAXP {@link XMLInputFactory}
+ *
+ * @return
+ */
+ private XMLInputFactory getXMLInputFactory() {
+ boolean tccl_jaxp = SystemPropertiesUtil.getSystemProperty(GeneralConstants.TCCL_JAXP, "false")
+ .equalsIgnoreCase("true");
+ ClassLoader prevTCCL = SecurityActions.getTCCL();
+ try {
+ if (tccl_jaxp) {
+ SecurityActions.setTCCL(AbstractParser.class.getClassLoader());
+ }
+ return XMLInputFactory.newInstance();
+ } finally {
+ if (tccl_jaxp) {
+ SecurityActions.setTCCL(prevTCCL);
+ }
}
}
- }
+ };
/**
* Parse an InputStream for payload
@@ -87,6 +90,15 @@ public abstract class AbstractParser implements ParserNamespaceSupport {
return parse(xmlEventReader);
}
+ public Object parse(Source source) throws ParsingException {
+ XMLEventReader xmlEventReader = createEventReader(source);
+ return parse(xmlEventReader);
+ }
+
+ public Object parse(Node node) throws ParsingException {
+ return parse(new DOMSource(node));
+ }
+
public XMLEventReader createEventReader(InputStream configStream) throws ParsingException {
if (configStream == null)
throw logger.nullArgumentError("InputStream");
@@ -102,6 +114,21 @@ public abstract class AbstractParser implements ParserNamespaceSupport {
return xmlEventReader;
}
+ public XMLEventReader createEventReader(Source source) throws ParsingException {
+ if (source == null)
+ throw logger.nullArgumentError("Source");
+
+ XMLEventReader xmlEventReader = StaxParserUtil.getXMLEventReader(source);
+
+ try {
+ xmlEventReader = filterWhitespaces(xmlEventReader);
+ } catch (XMLStreamException e) {
+ throw logger.parserException(e);
+ }
+
+ return xmlEventReader;
+ }
+
protected XMLEventReader filterWhitespaces(XMLEventReader xmlEventReader) throws XMLStreamException {
XMLInputFactory xmlInputFactory = XML_INPUT_FACTORY.get();
diff --git a/saml-core/src/main/java/org/keycloak/saml/common/util/StaxParserUtil.java b/saml-core/src/main/java/org/keycloak/saml/common/util/StaxParserUtil.java
index 1b06e9d..f0f6e2b 100755
--- a/saml-core/src/main/java/org/keycloak/saml/common/util/StaxParserUtil.java
+++ b/saml-core/src/main/java/org/keycloak/saml/common/util/StaxParserUtil.java
@@ -24,6 +24,8 @@ import org.keycloak.saml.common.constants.JBossSAMLConstants;
import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
import org.keycloak.saml.common.exceptions.ConfigurationException;
import org.keycloak.saml.common.exceptions.ParsingException;
+import org.keycloak.saml.common.exceptions.ProcessingException;
+
import org.w3c.dom.Document;
import org.w3c.dom.Element;
@@ -47,6 +49,7 @@ import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import java.io.InputStream;
+import java.util.concurrent.atomic.AtomicBoolean;
/**
* Utility for the stax based parser
@@ -250,6 +253,34 @@ public class StaxParserUtil {
return xmlEventReader;
}
+ private static AtomicBoolean XML_EVENT_READER_ON_SOURCE_SUPPORTED = new AtomicBoolean(true);
+
+ /**
+ * Get the XML event reader
+ *
+ * @param source
+ *
+ * @return
+ */
+ public static XMLEventReader getXMLEventReader(Source source) {
+ XMLInputFactory xmlInputFactory = XML_INPUT_FACTORY.get();
+ try {
+ if (XML_EVENT_READER_ON_SOURCE_SUPPORTED.get()) {
+ try {
+ // The following method is optional per specification
+ return xmlInputFactory.createXMLEventReader(source);
+ } catch (UnsupportedOperationException ex) {
+ XML_EVENT_READER_ON_SOURCE_SUPPORTED.set(false);
+ return getXMLEventReader(source);
+ }
+ } else {
+ return getXMLEventReader(DocumentUtil.getSourceAsStream(source));
+ }
+ } catch (ConfigurationException | ProcessingException | XMLStreamException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
/**
* Given a {@code Location}, return a formatted string [lineNum,colNum]
*
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/api/saml/v2/request/SAML2Request.java b/saml-core/src/main/java/org/keycloak/saml/processing/api/saml/v2/request/SAML2Request.java
index 9830482..2bfa41f 100755
--- a/saml-core/src/main/java/org/keycloak/saml/processing/api/saml/v2/request/SAML2Request.java
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/api/saml/v2/request/SAML2Request.java
@@ -165,7 +165,7 @@ public class SAML2Request {
SAMLParser samlParser = new SAMLParser();
JAXPValidationUtil.checkSchemaValidation(samlDocument);
- SAML2Object requestType = (SAML2Object) samlParser.parse(DocumentUtil.getNodeAsStream(samlDocument));
+ SAML2Object requestType = (SAML2Object) samlParser.parse(samlDocument);
samlDocumentHolder = new SAMLDocumentHolder(requestType, samlDocument);
return requestType;
@@ -192,7 +192,7 @@ public class SAML2Request {
SAMLParser samlParser = new SAMLParser();
JAXPValidationUtil.checkSchemaValidation(samlDocument);
- RequestAbstractType requestType = (RequestAbstractType) samlParser.parse(DocumentUtil.getNodeAsStream(samlDocument));
+ RequestAbstractType requestType = (RequestAbstractType) samlParser.parse(samlDocument);
samlDocumentHolder = new SAMLDocumentHolder(requestType, samlDocument);
return requestType;
@@ -220,7 +220,7 @@ public class SAML2Request {
SAMLParser samlParser = new SAMLParser();
JAXPValidationUtil.checkSchemaValidation(samlDocument);
- AuthnRequestType requestType = (AuthnRequestType) samlParser.parse(DocumentUtil.getNodeAsStream(samlDocument));
+ AuthnRequestType requestType = (AuthnRequestType) samlParser.parse(samlDocument);
samlDocumentHolder = new SAMLDocumentHolder(requestType, samlDocument);
return requestType;
}
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/api/saml/v2/response/SAML2Response.java b/saml-core/src/main/java/org/keycloak/saml/processing/api/saml/v2/response/SAML2Response.java
index 76155fe..a650c7a 100755
--- a/saml-core/src/main/java/org/keycloak/saml/processing/api/saml/v2/response/SAML2Response.java
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/api/saml/v2/response/SAML2Response.java
@@ -376,7 +376,7 @@ public class SAML2Response {
SAMLParser samlParser = new SAMLParser();
JAXPValidationUtil.checkSchemaValidation(samlDocument);
- return (EncryptedAssertionType) samlParser.parse(DocumentUtil.getNodeAsStream(samlDocument));
+ return (EncryptedAssertionType) samlParser.parse(samlDocument);
}
@@ -398,7 +398,7 @@ public class SAML2Response {
SAMLParser samlParser = new SAMLParser();
JAXPValidationUtil.checkSchemaValidation(samlDocument);
- return (AssertionType) samlParser.parse(DocumentUtil.getNodeAsStream(samlDocument));
+ return (AssertionType) samlParser.parse(samlDocument);
}
/**
@@ -429,7 +429,7 @@ public class SAML2Response {
SAMLParser samlParser = new SAMLParser();
JAXPValidationUtil.checkSchemaValidation(samlResponseDocument);
- ResponseType responseType = (ResponseType) samlParser.parse(DocumentUtil.getNodeAsStream(samlResponseDocument));
+ ResponseType responseType = (ResponseType) samlParser.parse(samlResponseDocument);
samlDocumentHolder = new SAMLDocumentHolder(responseType, samlResponseDocument);
return responseType;
@@ -460,8 +460,7 @@ public class SAML2Response {
SAMLParser samlParser = new SAMLParser();
JAXPValidationUtil.checkSchemaValidation(samlResponseDocument);
- InputStream responseStream = DocumentUtil.getNodeAsStream(samlResponseDocument);
- SAML2Object responseType = (SAML2Object) samlParser.parse(responseStream);
+ SAML2Object responseType = (SAML2Object) samlParser.parse(samlResponseDocument);
samlDocumentHolder = new SAMLDocumentHolder(responseType, samlResponseDocument);
return responseType;
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/saml/SamlEcpProfileTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/saml/SamlEcpProfileTest.java
index 778085c..bc6d316 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/saml/SamlEcpProfileTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/saml/SamlEcpProfileTest.java
@@ -146,7 +146,7 @@ public class SamlEcpProfileTest {
assertNotNull(samlResponse);
- ResponseType responseType = (ResponseType) new SAMLParser().parse(DocumentUtil.getNodeAsStream(samlResponse));
+ ResponseType responseType = (ResponseType) new SAMLParser().parse(samlResponse);
StatusCodeType statusCode = responseType.getStatus().getStatusCode();
assertEquals(statusCode.getValue().toString(), JBossSAMLURIConstants.STATUS_SUCCESS.get());
@@ -229,7 +229,7 @@ public class SamlEcpProfileTest {
assertNotNull(samlResponse);
- StatusResponseType responseType = (StatusResponseType) new SAMLParser().parse(DocumentUtil.getNodeAsStream(samlResponse));
+ StatusResponseType responseType = (StatusResponseType) new SAMLParser().parse(samlResponse);
StatusCodeType statusCode = responseType.getStatus().getStatusCode();
assertNotEquals(statusCode.getStatusCode().getValue().toString(), JBossSAMLURIConstants.STATUS_SUCCESS.get());