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