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