OSDN Git Service

only built-in XML xsd file will be resolved by resolver.
[mikutoga/TogaGem.git] / src / main / java / jp / sfjp / mikutoga / xml / SchemaUtil.java
index 8afddf4..9e2ae10 100644 (file)
@@ -22,14 +22,47 @@ import javax.xml.validation.Schema;
 import javax.xml.validation.SchemaFactory;
 import org.w3c.dom.ls.LSResourceResolver;
 import org.xml.sax.SAXException;
+import org.xml.sax.SAXNotRecognizedException;
+import org.xml.sax.SAXNotSupportedException;
 
 /**
- * XMLスキーマの各種ビルダ。
+ * XML schema (XSD) utilities.
  */
 public final class SchemaUtil {
 
+
+    /** XML Schema. */
+    public static final String SCHEMA_XML =
+            "http://www.w3.org/2001/xml.xsd";
+
+    /** XSD namespace. */
+    public static final String NS_XSD =
+            "http://www.w3.org/2001/XMLSchema-instance";
+
+    private static final String LOCAL_SCHEMA_XML =
+            "resources/xmlspace.xsd";
+
+    private static final URI URI_XSD_ORIG;
+    private static final URI URI_XSD_LOCAL;
+
+    private static final String ALLOWED_USCHEMA = "http";
+
+    private static final Class<?> THISCLASS = SchemaUtil.class;
+
+
+    static{
+        URL redirectRes = THISCLASS.getResource(LOCAL_SCHEMA_XML);
+        String redirectResName = redirectRes.toString();
+
+        URI_XSD_ORIG  = URI.create(SCHEMA_XML);
+        URI_XSD_LOCAL = URI.create(redirectResName);
+
+        assert ALLOWED_USCHEMA.equalsIgnoreCase(URI_XSD_ORIG.getScheme());
+    }
+
+
     /**
-     * 隠しコンストラクタ。
+     * Hidden constructor.
      */
     private SchemaUtil(){
         assert false;
@@ -38,32 +71,64 @@ public final class SchemaUtil {
 
 
     /**
-     * XML Schema 用のスキーマファクトリを返す。
-     * @return スキーマファクトリ
+     * build xml.xsd redirection info.
+     *
+     * @return resolver
      */
-    public static SchemaFactory newSchemaFactory(){
-        SchemaFactory result = newSchemaFactory(null);
+    public static XmlResourceResolver buildXmlXsdResolver(){
+        XmlResourceResolver result = new XmlResourceResolver();
+        result.putRedirected(URI_XSD_ORIG, URI_XSD_LOCAL);
         return result;
     }
 
     /**
-     * XML Schema 用のスキーマファクトリを返す。
-     * @param resolver カスタムリゾルバ。nullも可。
-     * @return スキーマファクトリ
+     * Build SchemaFactory for XML Schema but safety.
+     *
+     * <p>Includes some considerations for XXE vulnerabilities.
+     *
+     * <p>Restrict access to
+     * External Entity Reference &amp; external DTDs
+     * in xml schema file.
+     *
+     * <p>Restrict access to External schema file access in xml schema file,
+     * but HTTP access is allowed.
+     * This special limit considers access to
+     * importing http://www.w3.org/2001/xml.xsd
+     * in top of common xml schema file.
+     *
+     * @return schema factory
      */
-    public static SchemaFactory newSchemaFactory(
-            LSResourceResolver resolver ){
-        SchemaFactory schemaFactory =
-                SchemaFactory.newInstance(
-                    XMLConstants.W3C_XML_SCHEMA_NS_URI
-                );
+    public static SchemaFactory newSchemaFactory(){
+        SchemaFactory schemaFactory;
+        schemaFactory = SchemaFactory.newInstance(
+                XMLConstants.W3C_XML_SCHEMA_NS_URI);
 
-        // schemaFactory.setFeature(name, value);
-        // schemaFactory.setProperty(name, object);
+        try{
+            // Prevent denial of service attack.
+            schemaFactory.setFeature(
+                    XMLConstants.FEATURE_SECURE_PROCESSING, true);
+        }catch(SAXNotRecognizedException | SAXNotSupportedException e){
+            // FEATURE MUST BE SUPPORTED
+            assert false;
+        }
 
-        schemaFactory.setErrorHandler(BotherHandler.HANDLER);
+        try{
+            // Disallow external entity reference &amp; external DTD access.
+            schemaFactory.setProperty(
+                    XMLConstants.ACCESS_EXTERNAL_DTD, "");
+            // Allow only HTTP external schema file.
+            schemaFactory.setProperty(
+                    XMLConstants.ACCESS_EXTERNAL_SCHEMA, ALLOWED_USCHEMA);
+        }catch(SAXNotRecognizedException | SAXNotSupportedException e){
+            // PROPERTY MUST BE SUPPORTED JAXP1.5 or later
+            assert false;
+        }
+
+        LSResourceResolver resolver = buildXmlXsdResolver();
         schemaFactory.setResourceResolver(resolver);
 
+        schemaFactory.setErrorHandler(BotherHandler.HANDLER);
+
         return schemaFactory;
     }
 
@@ -93,9 +158,9 @@ public final class SchemaUtil {
      * @throws MalformedURLException 不正なURI
      * @throws IOException オープンエラー
      */
-    private static Source[] toLocalSourceArray(LocalXmlResource[] resArray)
+    private static Source[] toLocalSourceArray(LocalXmlResource... resArray)
             throws MalformedURLException, IOException{
-        List<Source> sourceList = new ArrayList<Source>(resArray.length);
+        List<Source> sourceList = new ArrayList<>(resArray.length);
 
         for(LocalXmlResource resource : resArray){
             Source localSource = toLocalSource(resource);
@@ -112,16 +177,10 @@ public final class SchemaUtil {
      *
      * <p>任意のリゾルバを指定可能
      *
-     * @param resolver リゾルバ
      * @param resArray ローカルスキーマ情報並び
      * @return スキーマ
      */
-    public static Schema newSchema(XmlResourceResolver resolver,
-                                    LocalXmlResource... resArray ){
-        for(LocalXmlResource resource : resArray){
-            resolver.putRedirected(resource);
-        }
-
+    public static Schema newSchema(LocalXmlResource... resArray){
         Source[] sources;
         try{
             sources = toLocalSourceArray(resArray);
@@ -130,7 +189,7 @@ public final class SchemaUtil {
             throw new AssertionError(e);
         }
 
-        SchemaFactory schemaFactory = newSchemaFactory(resolver);
+        SchemaFactory schemaFactory = newSchemaFactory();
 
         Schema result;
         try{