View Javadoc

1   /*
2    * Copyright 2006 University Corporation for Advanced Internet Development, Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.opensaml.xml;
18  
19  import java.security.NoSuchAlgorithmException;
20  import java.util.Map;
21  import java.util.Set;
22  import java.util.concurrent.ConcurrentHashMap;
23  import java.util.concurrent.CopyOnWriteArraySet;
24  
25  import javax.crypto.Cipher;
26  import javax.crypto.NoSuchPaddingException;
27  import javax.xml.namespace.QName;
28  import javax.xml.parsers.DocumentBuilderFactory;
29  
30  import org.opensaml.xml.io.Marshaller;
31  import org.opensaml.xml.io.MarshallerFactory;
32  import org.opensaml.xml.io.Unmarshaller;
33  import org.opensaml.xml.io.UnmarshallerFactory;
34  import org.opensaml.xml.parse.ParserPool;
35  import org.opensaml.xml.security.SecurityConfiguration;
36  import org.opensaml.xml.util.XMLConstants;
37  import org.opensaml.xml.validation.ValidatorSuite;
38  import org.slf4j.Logger;
39  import org.slf4j.LoggerFactory;
40  import org.w3c.dom.Element;
41  
42  /** Class for loading library configuration files and retrieving the configured components. */
43  public class Configuration {
44  
45      /** Default object provider. */
46      private static QName defaultProvider = new QName(XMLConstants.XMLTOOLING_CONFIG_NS,
47              XMLConstants.XMLTOOLING_DEFAULT_OBJECT_PROVIDER);
48  
49      /** Object provider configuration elements indexed by QName. */
50      private static Map<QName, Element> configuredObjectProviders = new ConcurrentHashMap<QName, Element>(0);
51  
52      /** Validator suite configuration elements indexed by suite IDs. */
53      private static Map<String, Element> validatorSuiteConfigurations = new ConcurrentHashMap<String, Element>(0);
54  
55      /** Configured XMLObject builder factory. */
56      private static XMLObjectBuilderFactory builderFactory = new XMLObjectBuilderFactory();
57  
58      /** Configured XMLObject marshaller factory. */
59      private static MarshallerFactory marshallerFactory = new MarshallerFactory();
60  
61      /** Configured XMLObject unmarshaller factory. */
62      private static UnmarshallerFactory unmarshallerFactory = new UnmarshallerFactory();
63  
64      /** Configured ValidatorSuites. */
65      private static Map<String, ValidatorSuite> validatorSuites = new ConcurrentHashMap<String, ValidatorSuite>(5);
66  
67      /** Configured set of attribute QNames which have been globally registered as having an ID type. */
68      private static Set<QName> idAttributeNames = new CopyOnWriteArraySet<QName>();
69  
70      /** Configured global security configuration information. */
71      private static SecurityConfiguration globalSecurityConfig;
72  
73      /** Configured parser pool. */
74      private static ParserPool parserPool;
75  
76      /** Constructor. */
77      protected Configuration() {
78  
79      }
80      
81      /**
82       * Get the currently configured ParserPool instance.
83       * 
84       * @return the currently ParserPool
85       */
86      public static ParserPool getParserPool() {
87          return parserPool;
88      }
89  
90      /**
91       * Set the currently configured ParserPool instance.
92       * 
93       * @param newParserPool the new ParserPool instance to configure
94       */
95      public static void setParserPool(ParserPool newParserPool) {
96          parserPool = newParserPool;
97      }
98      
99      /**
100      * Gets the QName for the object provider that will be used for XMLObjects that do not have a registered object
101      * provider.
102      * 
103      * @return the QName for the default object provider
104      */
105     public static QName getDefaultProviderQName() {
106         return defaultProvider;
107     }
108 
109     /**
110      * Adds an object provider to this configuration.
111      * 
112      * @param providerName the name of the object provider, corresponding to the element name or type name that the
113      *            builder, marshaller, and unmarshaller operate on
114      * @param builder the builder for that given provider
115      * @param marshaller the marshaller for the provider
116      * @param unmarshaller the unmarshaller for the provider
117      */
118     public static void registerObjectProvider(QName providerName, XMLObjectBuilder builder, Marshaller marshaller,
119             Unmarshaller unmarshaller) {
120         Logger log = getLogger();
121         log.debug("Registering new builder, marshaller, and unmarshaller for {}", providerName);
122         builderFactory.registerBuilder(providerName, builder);
123         marshallerFactory.registerMarshaller(providerName, marshaller);
124         unmarshallerFactory.registerUnmarshaller(providerName, unmarshaller);
125     }
126 
127     /**
128      * Removes the builder, marshaller, and unmarshaller registered to the given key.
129      * 
130      * @param key the key of the builder, marshaller, and unmarshaller to be removed
131      */
132     public static void deregisterObjectProvider(QName key) {
133         Logger log = getLogger();
134         log.debug("Unregistering builder, marshaller, and unmarshaller for {}", key);
135         configuredObjectProviders.remove(key);
136         builderFactory.deregisterBuilder(key);
137         marshallerFactory.deregisterMarshaller(key);
138         unmarshallerFactory.deregisterUnmarshaller(key);
139     }
140 
141     /**
142      * Gets the XMLObject builder factory that has been configured with information from loaded configuration files.
143      * 
144      * @return the XMLObject builder factory
145      */
146     public static XMLObjectBuilderFactory getBuilderFactory() {
147         return builderFactory;
148     }
149 
150     /**
151      * Gets the XMLObject marshaller factory that has been configured with information from loaded configuration files.
152      * 
153      * @return the XMLObject marshaller factory
154      */
155     public static MarshallerFactory getMarshallerFactory() {
156         return marshallerFactory;
157     }
158 
159     /**
160      * Gets the XMLObject unmarshaller factory that has been configured with information from loaded configuration
161      * files.
162      * 
163      * @return the XMLObject unmarshaller factory
164      */
165     public static UnmarshallerFactory getUnmarshallerFactory() {
166         return unmarshallerFactory;
167     }
168 
169     /**
170      * Registers a configured validator suite.
171      * 
172      * @param suiteId the ID of the suite
173      * @param suite the configured suite
174      * @param configuration optional XML configuration information
175      */
176     public static void registerValidatorSuite(String suiteId, ValidatorSuite suite) {
177         validatorSuites.put(suiteId, suite);
178     }
179 
180     /**
181      * Removes a registered validator suite.
182      * 
183      * @param suiteId the ID of the suite
184      */
185     public static void deregisterValidatorSuite(String suiteId) {
186         validatorSuiteConfigurations.remove(suiteId);
187         validatorSuites.remove(suiteId);
188     }
189 
190     /**
191      * Gets a configured ValidatorSuite by its ID.
192      * 
193      * @param suiteId the suite's ID
194      * 
195      * @return the ValidatorSuite or null if no suite was registered under that ID
196      */
197     public static ValidatorSuite getValidatorSuite(String suiteId) {
198         return validatorSuites.get(suiteId);
199     }
200 
201     /**
202      * Register an attribute as having a type of ID.
203      * 
204      * @param attributeName the QName of the ID attribute to be registered
205      */
206     public static void registerIDAttribute(QName attributeName) {
207         if (!idAttributeNames.contains(attributeName)) {
208             idAttributeNames.add(attributeName);
209         }
210     }
211 
212     /**
213      * Deregister an attribute as having a type of ID.
214      * 
215      * @param attributeName the QName of the ID attribute to be de-registered
216      */
217     public static void deregisterIDAttribute(QName attributeName) {
218         if (idAttributeNames.contains(attributeName)) {
219             idAttributeNames.remove(attributeName);
220         }
221     }
222 
223     /**
224      * Determine whether a given attribute is registered as having an ID type.
225      * 
226      * @param attributeName the QName of the attribute to be checked for ID type.
227      * @return true if attribute is registered as having an ID type.
228      */
229     public static boolean isIDAttribute(QName attributeName) {
230         return idAttributeNames.contains(attributeName);
231     }
232 
233     /**
234      * Get the global security configuration.
235      * 
236      * @return the global security configuration instance
237      */
238     public static SecurityConfiguration getGlobalSecurityConfiguration() {
239         return globalSecurityConfig;
240     }
241 
242     /**
243      * Set the global security configuration.
244      * 
245      * @param config the new global security configuration instance
246      */
247     public static void setGlobalSecurityConfiguration(SecurityConfiguration config) {
248         globalSecurityConfig = config;
249     }
250 
251     /**
252      * Validates that the system is not using the horribly buggy Sun JAXP implementation.
253      */
254     public static void validateNonSunJAXP() {
255         Logger log = getLogger();
256         String builderFactoryClass = DocumentBuilderFactory.newInstance().getClass().getName();
257         log.debug("VM using JAXP parser {}", builderFactoryClass);
258 
259         if (builderFactoryClass.startsWith("com.sun")) {
260             String errorMsg = "\n\n\nOpenSAML requires an xml parser that supports JAXP 1.3 and DOM3.\n"
261                     + "The JVM is currently configured to use the Sun XML parser, which is known\n"
262                     + "to be buggy and can not be used with OpenSAML.  Please endorse a functional\n"
263                     + "JAXP library(ies) such as Xerces and Xalan.  For instructions on how to endorse\n"
264                     + "a new parser see http://java.sun.com/j2se/1.5.0/docs/guide/standards/index.html\n\n\n";
265 
266             log.error(errorMsg);
267             throw new Error(errorMsg);
268         }
269     }
270 
271     /**
272      * Validates that the set of security providers configured in the JVM supports required cryptographic capabilities,
273      * for example for the XML Encryption and XML Signature specifications.
274      * 
275      * Depending on the requirements of the calling code, failure to fully support encryption and signature requirements
276      * may or may not be significant, so return a status flag to let the caller make that determination.
277      * 
278      * @return false if one or more capablities are not present, otherwise true
279      */
280     public static boolean validateJCEProviders() {
281         Logger log = getLogger();
282         boolean ret = true;
283 
284         // XML Encryption spec requires AES support (128 and 256).
285         // Some JRE's are known to ship with no JCE's that support
286         // the ISO10126Padding padding scheme.
287 
288         String errorMsgAESPadding = "The JCE providers currently configured in the JVM do not support\n"
289                 + "required capabilities for XML Encryption, either the 'AES' cipher algorithm\n"
290                 + "or the 'ISO10126Padding' padding scheme\n";
291 
292         try {
293             Cipher.getInstance("AES/CBC/ISO10126Padding");
294         } catch (NoSuchAlgorithmException e) {
295             // IBM JCE returns this as the top-level exception even for the unsupported padding case. :-(
296             // Otherwise would be nice to make the error msg more specific.
297             log.warn(errorMsgAESPadding);
298             ret = false;
299         } catch (NoSuchPaddingException e) {
300             log.warn(errorMsgAESPadding);
301             ret = false;
302         }
303 
304         // Could do more tests here as needed.
305 
306         return ret;
307     }
308 
309     /**
310      * Adds an object provider to this configuration.
311      * 
312      * @param providerName the name of the object provider, corresponding to the element name or type name that the
313      *            builder, marshaller, and unmarshaller operate on
314      * @param builder the builder for that given provider
315      * @param marshaller the marshaller for the provider
316      * @param unmarshaller the unmarshaller for the provider
317      * @param configuration optional XML configuration snippet
318      * 
319      * @deprecated this method is deprecated with no replacement
320      */
321     public static void registerObjectProvider(QName providerName, XMLObjectBuilder builder, Marshaller marshaller,
322             Unmarshaller unmarshaller, Element configuration) {
323         Logger log = getLogger();
324         log.debug("Registering new builder, marshaller, and unmarshaller for {}", providerName);
325         if (configuration != null) {
326             configuredObjectProviders.put(providerName, configuration);
327         }
328         builderFactory.registerBuilder(providerName, builder);
329         marshallerFactory.registerMarshaller(providerName, marshaller);
330         unmarshallerFactory.registerUnmarshaller(providerName, unmarshaller);
331     }
332 
333     /**
334      * Gets a clone of the configuration element for a qualified element. Note that this configuration reflects the
335      * state of things as they were when the configuration was loaded, applications may have programmatically removed
336      * builder, marshallers, and unmarshallers during runtime.
337      * 
338      * @param qualifedName the namespace qualifed element name of the schema type of the object provider
339      * 
340      * @return the object provider configuration element or null if no object provider is configured with that name
341      * 
342      * @deprecated this method is deprecated with no replacement
343      */
344     public static Element getObjectProviderConfiguration(QName qualifedName) {
345         Element configElement = configuredObjectProviders.get(qualifedName);
346         if (configElement != null) {
347             return (Element) configElement.cloneNode(true);
348         }
349         return null;
350     }
351 
352     /**
353      * Registers a configured validator suite.
354      * 
355      * @param suiteId the ID of the suite
356      * @param suite the configured suite
357      * @param configuration optional XML configuration information
358      * 
359      * @deprecated this method is deprecated with no replacement
360      */
361     public static void registerValidatorSuite(String suiteId, ValidatorSuite suite, Element configuration) {
362         if (configuration != null) {
363             validatorSuiteConfigurations.put(suiteId, configuration);
364         }
365         validatorSuites.put(suiteId, suite);
366     }
367 
368     /**
369      * Gets a clone of the ValidatorSuite configuration element for the ID. Note that this configuration reflects the
370      * state of things as they were when the configuration was loaded, applications may have programmatically removed
371      * altered the suite during runtime.
372      * 
373      * @param suiteId the ID of the ValidatorSuite whose configuration is to be retrieved
374      * 
375      * @return the validator suite configuration element or null if no suite is configured with that ID
376      * 
377      * @deprecated this method is deprecated with no replacement
378      */
379     public static Element getValidatorSuiteConfiguration(String suiteId) {
380         Element configElement = validatorSuiteConfigurations.get(suiteId);
381         if (configElement != null) {
382             return (Element) configElement.cloneNode(true);
383         }
384 
385         return null;
386     }
387     
388     /**
389      * Get an SLF4J Logger.
390      * 
391      * @return a Logger instance
392      */
393     private static Logger getLogger() {
394         return LoggerFactory.getLogger(Configuration.class);
395     }
396 
397     static {
398         validateJCEProviders();
399 
400         // Default to registering the xml:id attribute as an ID type for all configurations
401         registerIDAttribute(new QName(javax.xml.XMLConstants.XML_NS_URI, "id"));
402     }
403 }