Removed unneeded schema.
[java-idp.git] / src / edu / internet2 / middleware / shibboleth / xml / Parser.java
1 /*
2  * Parser.java
3  * 
4  * Validating and non-validating XML parsing using JAXP 1.3.
5  * 
6  * Previous versions of the code directly used the Xerces DOMParser
7  * class. This class has been hidden in the Sun XML stack, and the
8  * public interface is to use DocumentBuilderFactory. This module 
9  * requires the DOM 3 and JAXP 1.3 support built into J2SE 5.0 and
10  * distributed separately for earlier releases of Java from
11  * https://jaxp.dev.java.net/. It should also work with Xerces 2.7.0
12  * when that release becomes available.
13  * 
14  * The org.opensaml.XML class already has most of the parsing code,
15  * but it uses a subset of the required Schemas. Here we build a
16  * wider Schema object, set it as the default SAML schema (because
17  * some Shibboleth namespace fields appear in SAML statements), and
18  * demand that Schema for every parser (DocumentBuilder) we request.
19  * 
20  * Currently, this class exposes static methods. Should a real 
21  * framework be installed, it would become a singleton object.
22  */
23 package edu.internet2.middleware.shibboleth.xml;
24
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.io.StringWriter;
28
29 import javax.xml.transform.OutputKeys;
30 import javax.xml.transform.Transformer;
31 import javax.xml.transform.TransformerConfigurationException;
32 import javax.xml.transform.TransformerException;
33 import javax.xml.transform.TransformerFactory;
34 import javax.xml.transform.dom.DOMSource;
35 import javax.xml.transform.stream.StreamResult;
36 import javax.xml.validation.Schema;
37
38 import org.apache.log4j.Logger;
39 import org.opensaml.SAMLException;
40 import org.w3c.dom.Document;
41 import org.w3c.dom.Node;
42 import org.xml.sax.InputSource;
43 import org.xml.sax.SAXException;
44
45 /**
46  * Obtain schema validating and non-validating XML parsers.
47  * 
48  * @author Howard Gilbert
49  */
50 public class Parser {
51     private static Logger log = Logger.getLogger(Parser.class);
52     
53     
54     /**
55      * All the namespaces used by any part of Shibboleth
56      * 
57      * Note: The current Schema compiler requires that dependencies
58      * (imports) be listed before the namespace of the schema
59      * that imports them.
60      */
61     private static String[] namespaces = new String[]{
62             "http://www.w3.org/2000/09/xmldsig#",  
63             "http://www.w3.org/2001/04/xmlenc#",
64             "urn:oasis:names:tc:SAML:1.0:assertion",
65             "urn:oasis:names:tc:SAML:2.0:assertion",
66             "http://www.w3.org/XML/1998/namespace",
67             "http://schemas.xmlsoap.org/soap/envelope/",
68             "urn:mace:shibboleth:credentials:1.0",
69             "urn:oasis:names:tc:SAML:1.0:protocol",
70             "urn:oasis:names:tc:SAML:2.0:protocol",
71             "urn:mace:shibboleth:namemapper:1.0",
72             "urn:mace:shibboleth:origin:1.0",
73             "urn:mace:shibboleth:arp:1.0",
74             "urn:mace:shibboleth:resolver:1.0",
75             "urn:mace:shibboleth:target:config:1.0",
76             "urn:mace:shibboleth:trust:1.0",
77             "urn:mace:shibboleth:1.0",
78             "http://schemas.xmlsoap.org/soap/envelope/",
79             "urn:oasis:names:tc:SAML:2.0:metadata"
80       };
81     
82     // If there were a real Framework here (like Spring) then
83     // the schemaBuilder would be inserted 
84     private static Schemas schemaBuilder = new SchemasDirectoryImpl();
85     private static Schema schema = schemaBuilder.compileSchema(namespaces);
86     
87     /**
88      * Load a DOM from a wrapped byte stream.
89      * 
90      * @param ins InputSource The XML document
91      * @param validate If true, use Schema. Otherwise, its raw XML.
92      * @return A DOM 3 tree
93      */
94     public static Document loadDom(InputSource ins, boolean validate) {
95         Document doc=null;
96         log.info("Loading XML from (" + ins.getSystemId() + ")"
97                 + (validate?" with Schema validation":"")
98                 );
99         try {
100             if (validate)
101                 doc = org.opensaml.XML.parserPool.parse(ins,schema);
102             else
103                 doc = org.opensaml.XML.parserPool.parse(ins,null);
104             
105         } catch (SAXException e) {
106             log.error("Error in XML configuration file"+e);
107             return null;
108         } catch (IOException e) {
109             log.error("Error accessing XML configuration file"+e);
110             return null;
111         } catch (SAMLException e) {
112             log.error("Error with XML parser "+e);
113             return null;
114        }
115         
116         return doc;
117     }
118     
119     
120     /**
121      * A dummy class that pretends to be an old Xerces DOMParser
122      * to simplify conversion of existing code.
123      */
124     public static class DOMParser {
125         Document doc = null;
126         boolean validate = false;
127         
128         public DOMParser(boolean validate) {
129             this.validate=validate;
130         }
131         
132         public Document parse(InputSource ins) throws SAXException, IOException {
133             doc = loadDom(ins,true);
134             return doc;
135         }
136         
137         public Document getDocument() {
138             return doc;
139         }
140     }
141     
142     /**
143      * Write a DOM out to a character stream (for debugging and logging)
144      * 
145      * @param dom The DOM tree to write
146      * @return A string containing the XML in character form.
147      */
148     public static String serialize(Node dom) {
149         String ret = null;
150         
151         TransformerFactory factory = TransformerFactory.newInstance();
152         Transformer transformer = null;
153         DOMSource source = new DOMSource(dom);
154         try {
155             transformer = factory.newTransformer();
156             transformer.setOutputProperty(OutputKeys.INDENT, "yes");
157         } catch (TransformerConfigurationException e) {
158             return null;
159         }
160         StringWriter stringWriter = new StringWriter();
161         StreamResult result = new StreamResult(stringWriter);
162         try {
163             transformer.transform(source, result);
164         } catch (TransformerException e1) {
165             return null;
166         }
167         return stringWriter.toString();
168     }
169     
170     /**
171      * Version of loadDom where the file is specified as a resource name
172      * 
173      * @param configFilePath input resource
174      * @param validate if true, use Schema
175      * @return DOM tree
176      */
177     public static Document loadDom(String configFilePath,boolean validate) 
178     {
179         InputSource insrc;
180         String schemaCannonicalFilePath;
181        try {
182             InputStream resourceAsStream = Parser.class.getResourceAsStream(configFilePath);
183             insrc = new InputSource(resourceAsStream);
184             insrc.setSystemId(configFilePath);
185         } catch (Exception e1) {
186             log.error("Configuration file "+configFilePath+" could not be located.");
187             return null;
188         }
189         
190         return loadDom(insrc,validate); // Now pass on to the main routine
191         
192     }
193     
194     /**
195      * Override the OpenSAML default schema from SAML 1.1 to 
196      * SAML 1.1 plus Shibboleth (and some SAML 2.0).
197      */
198     static {
199         org.opensaml.XML.parserPool.setDefaultSchema(schema);
200     }
201     
202 }