Skip to content

Commit 3edc899

Browse files
committed
Ensure local resolution of schemas (and DTDs)
Schemas in main/resources were not correctly used on schema loading when java-saml was used as a JAR in a consuming application. It seems like the local XSD files for imported schemas were used only when running unit tests, while remote HTTP lookups from the W3C website were made when using java-saml as a JAR. Now a LSResoureResolver is set on the schema factory so that any known XSD or DTD is loaded from the classpath, even when inside a JAR. Any other (unknown) schema is resolved in the standard way (and may involve a remote call). Also, in the unlikely event that retrieving the local copy of the XSD/DTD is impossible, a fallback mechanism ensures the standard resolution is performed. Please note that the online version of xenc-schema.xsd contains a reference to the XML Schema DTD. Now that we can resolve resources locally, I decided to keep the DTD and include it in /schemas package (along with the datatypes DTD). This should provide an even more comprehensive schema validation. Closes #327.
1 parent 523786b commit 3edc899

File tree

4 files changed

+696
-3
lines changed

4 files changed

+696
-3
lines changed

core/src/main/java/com/onelogin/saml2/util/SchemaFactory.java

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
11
package com.onelogin.saml2.util;
22

3+
import java.io.InputStream;
34
import java.net.URL;
5+
import java.util.Locale;
46

57
import javax.xml.XMLConstants;
68
import javax.xml.validation.Schema;
79

10+
import org.slf4j.Logger;
11+
import org.slf4j.LoggerFactory;
12+
import org.w3c.dom.bootstrap.DOMImplementationRegistry;
13+
import org.w3c.dom.ls.DOMImplementationLS;
14+
import org.w3c.dom.ls.LSInput;
15+
import org.w3c.dom.ls.LSResourceResolver;
816
import org.xml.sax.SAXException;
917

1018
/**
@@ -14,6 +22,11 @@
1422
*/
1523
public abstract class SchemaFactory {
1624

25+
/**
26+
* Private property to construct a logger for this class.
27+
*/
28+
private static final Logger LOGGER = LoggerFactory.getLogger(SchemaFactory.class);
29+
1730
private SchemaFactory() {
1831
//not called
1932
}
@@ -24,7 +37,72 @@ private SchemaFactory() {
2437
.getResource("/schemas/saml-schema-protocol-2.0.xsd");
2538

2639
public static Schema loadFromUrl(URL schemaUrl) throws SAXException {
27-
return javax.xml.validation.SchemaFactory
28-
.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI).newSchema(schemaUrl);
40+
javax.xml.validation.SchemaFactory factory = javax.xml.validation.SchemaFactory
41+
.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
42+
factory.setResourceResolver(new LSResourceResolver() {
43+
44+
private DOMImplementationLS ls;
45+
46+
@Override
47+
public LSInput resolveResource(final String type, final String namespaceURI,
48+
final String publicId, final String systemId, final String baseURI) {
49+
try {
50+
if(namespaceURI != null)
51+
switch (namespaceURI) {
52+
case "urn:oasis:names:tc:SAML:2.0:assertion":
53+
return getLocalResource("saml-schema-assertion-2.0.xsd");
54+
case "urn:oasis:names:tc:SAML:2.0:ac":
55+
return getLocalResource("saml-schema-authn-context-2.0.xsd");
56+
case "urn:oasis:names:tc:SAML:2.0:metadata":
57+
return getLocalResource("saml-schema-metadata-2.0.xsd");
58+
case "urn:oasis:names:tc:SAML:2.0:protocol":
59+
return getLocalResource("saml-schema-protocol-2.0.xsd");
60+
case "urn:oasis:names:tc:SAML:metadata:attribute":
61+
return getLocalResource("sstc-metadata-attr.xsd");
62+
case "urn:oasis:names:tc:SAML:attribute:ext":
63+
return getLocalResource("sstc-saml-attribute-ext.xsd");
64+
case "urn:oasis:names:tc:SAML:metadata:algsupport":
65+
return getLocalResource("sstc-saml-metadata-algsupport-v1.0.xsd");
66+
case "urn:oasis:names:tc:SAML:metadata:ui":
67+
return getLocalResource("sstc-saml-metadata-ui-v1.0.xsd");
68+
case "http://www.w3.org/2001/04/xmlenc#":
69+
return getLocalResource("xenc-schema.xsd");
70+
case "http://www.w3.org/XML/1998/namespace":
71+
return getLocalResource("xml.xsd");
72+
case "http://www.w3.org/2000/09/xmldsig#":
73+
return getLocalResource("xmldsig-core-schema.xsd");
74+
}
75+
if("saml-schema-authn-context-types-2.0.xsd".equals(systemId))
76+
return getLocalResource("saml-schema-authn-context-types-2.0.xsd");
77+
if(publicId != null)
78+
switch(publicId.toUpperCase(Locale.ROOT)) {
79+
case "-//W3C//DTD XMLSCHEMA 200102//EN":
80+
return getLocalResource("XMLSchema.dtd");
81+
case "DATATYPES":
82+
return getLocalResource("datatypes.dtd");
83+
}
84+
} catch (final Throwable e) {
85+
// fallback to standard behaviour in case of errors
86+
LOGGER.warn("could not resolve schema or DTD locally, proceeding the standard way",
87+
e);
88+
return null;
89+
}
90+
return null;
91+
}
92+
93+
public LSInput getLocalResource(String name) throws Throwable {
94+
if (ls == null) {
95+
DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
96+
ls = (DOMImplementationLS) registry.getDOMImplementation("LS 3.0");
97+
}
98+
final InputStream inputStream = getClass().getResourceAsStream("/schemas/" + name);
99+
if (inputStream == null)
100+
return null;
101+
final LSInput lsInput = ls.createLSInput();
102+
lsInput.setByteStream(inputStream);
103+
return lsInput;
104+
}
105+
});
106+
return factory.newSchema(schemaUrl);
29107
}
30108
}

0 commit comments

Comments
 (0)