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 */
175 public static void registerValidatorSuite(String suiteId, ValidatorSuite suite) {
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 configured ValidatorSuite by its ID.
191 *
192 * @param suiteId the suite's ID
193 *
194 * @return the ValidatorSuite or null if no suite was registered under that ID
195 */
196 public static ValidatorSuite getValidatorSuite(String suiteId) {
197 return validatorSuites.get(suiteId);
198 }
199
200 /**
201 * Register an attribute as having a type of ID.
202 *
203 * @param attributeName the QName of the ID attribute to be registered
204 */
205 public static void registerIDAttribute(QName attributeName) {
206 if (!idAttributeNames.contains(attributeName)) {
207 idAttributeNames.add(attributeName);
208 }
209 }
210
211 /**
212 * Deregister an attribute as having a type of ID.
213 *
214 * @param attributeName the QName of the ID attribute to be de-registered
215 */
216 public static void deregisterIDAttribute(QName attributeName) {
217 if (idAttributeNames.contains(attributeName)) {
218 idAttributeNames.remove(attributeName);
219 }
220 }
221
222 /**
223 * Determine whether a given attribute is registered as having an ID type.
224 *
225 * @param attributeName the QName of the attribute to be checked for ID type.
226 * @return true if attribute is registered as having an ID type.
227 */
228 public static boolean isIDAttribute(QName attributeName) {
229 return idAttributeNames.contains(attributeName);
230 }
231
232 /**
233 * Get the global security configuration.
234 *
235 * @return the global security configuration instance
236 */
237 public static SecurityConfiguration getGlobalSecurityConfiguration() {
238 return globalSecurityConfig;
239 }
240
241 /**
242 * Set the global security configuration.
243 *
244 * @param config the new global security configuration instance
245 */
246 public static void setGlobalSecurityConfiguration(SecurityConfiguration config) {
247 globalSecurityConfig = config;
248 }
249
250 /**
251 * Validates that the system is not using the horribly buggy Sun JAXP implementation.
252 */
253 public static void validateNonSunJAXP() {
254 Logger log = getLogger();
255 String builderFactoryClass = DocumentBuilderFactory.newInstance().getClass().getName();
256 log.debug("VM using JAXP parser {}", builderFactoryClass);
257
258 if (builderFactoryClass.startsWith("com.sun")) {
259 String errorMsg = "\n\n\nOpenSAML requires an xml parser that supports JAXP 1.3 and DOM3.\n"
260 + "The JVM is currently configured to use the Sun XML parser, which is known\n"
261 + "to be buggy and can not be used with OpenSAML. Please endorse a functional\n"
262 + "JAXP library(ies) such as Xerces and Xalan. For instructions on how to endorse\n"
263 + "a new parser see http://java.sun.com/j2se/1.5.0/docs/guide/standards/index.html\n\n\n";
264
265 log.error(errorMsg);
266 throw new Error(errorMsg);
267 }
268 }
269
270 /**
271 * Validates that the set of security providers configured in the JVM supports required cryptographic capabilities,
272 * for example for the XML Encryption and XML Signature specifications.
273 *
274 * Depending on the requirements of the calling code, failure to fully support encryption and signature requirements
275 * may or may not be significant, so return a status flag to let the caller make that determination.
276 *
277 * @return false if one or more capablities are not present, otherwise true
278 */
279 public static boolean validateJCEProviders() {
280 Logger log = getLogger();
281 boolean ret = true;
282
283 // XML Encryption spec requires AES support (128 and 256).
284 // Some JRE's are known to ship with no JCE's that support
285 // the ISO10126Padding padding scheme.
286
287 String errorMsgAESPadding = "The JCE providers currently configured in the JVM do not support\n"
288 + "required capabilities for XML Encryption, either the 'AES' cipher algorithm\n"
289 + "or the 'ISO10126Padding' padding scheme\n";
290
291 try {
292 Cipher.getInstance("AES/CBC/ISO10126Padding");
293 } catch (NoSuchAlgorithmException e) {
294 // IBM JCE returns this as the top-level exception even for the unsupported padding case. :-(
295 // Otherwise would be nice to make the error msg more specific.
296 log.warn(errorMsgAESPadding);
297 ret = false;
298 } catch (NoSuchPaddingException e) {
299 log.warn(errorMsgAESPadding);
300 ret = false;
301 }
302
303 // Could do more tests here as needed.
304
305 return ret;
306 }
307
308 /**
309 * Adds an object provider to this configuration.
310 *
311 * @param providerName the name of the object provider, corresponding to the element name or type name that the
312 * builder, marshaller, and unmarshaller operate on
313 * @param builder the builder for that given provider
314 * @param marshaller the marshaller for the provider
315 * @param unmarshaller the unmarshaller for the provider
316 * @param configuration optional XML configuration snippet
317 *
318 * @deprecated this method is deprecated with no replacement
319 */
320 public static void registerObjectProvider(QName providerName, XMLObjectBuilder builder, Marshaller marshaller,
321 Unmarshaller unmarshaller, Element configuration) {
322 Logger log = getLogger();
323 log.debug("Registering new builder, marshaller, and unmarshaller for {}", providerName);
324 if (configuration != null) {
325 configuredObjectProviders.put(providerName, configuration);
326 }
327 builderFactory.registerBuilder(providerName, builder);
328 marshallerFactory.registerMarshaller(providerName, marshaller);
329 unmarshallerFactory.registerUnmarshaller(providerName, unmarshaller);
330 }
331
332 /**
333 * Gets a clone of the configuration element for a qualified element. Note that this configuration reflects the
334 * state of things as they were when the configuration was loaded, applications may have programmatically removed
335 * builder, marshallers, and unmarshallers during runtime.
336 *
337 * @param qualifedName the namespace qualifed element name of the schema type of the object provider
338 *
339 * @return the object provider configuration element or null if no object provider is configured with that name
340 *
341 * @deprecated this method is deprecated with no replacement
342 */
343 public static Element getObjectProviderConfiguration(QName qualifedName) {
344 Element configElement = configuredObjectProviders.get(qualifedName);
345 if (configElement != null) {
346 return (Element) configElement.cloneNode(true);
347 }
348 return null;
349 }
350
351 /**
352 * Registers a configured validator suite.
353 *
354 * @param suiteId the ID of the suite
355 * @param suite the configured suite
356 * @param configuration optional XML configuration information
357 *
358 * @deprecated this method is deprecated with no replacement
359 */
360 public static void registerValidatorSuite(String suiteId, ValidatorSuite suite, Element configuration) {
361 if (configuration != null) {
362 validatorSuiteConfigurations.put(suiteId, configuration);
363 }
364 validatorSuites.put(suiteId, suite);
365 }
366
367 /**
368 * Gets a clone of the ValidatorSuite configuration element for the ID. Note that this configuration reflects the
369 * state of things as they were when the configuration was loaded, applications may have programmatically removed
370 * altered the suite during runtime.
371 *
372 * @param suiteId the ID of the ValidatorSuite whose configuration is to be retrieved
373 *
374 * @return the validator suite configuration element or null if no suite is configured with that ID
375 *
376 * @deprecated this method is deprecated with no replacement
377 */
378 public static Element getValidatorSuiteConfiguration(String suiteId) {
379 Element configElement = validatorSuiteConfigurations.get(suiteId);
380 if (configElement != null) {
381 return (Element) configElement.cloneNode(true);
382 }
383
384 return null;
385 }
386
387 /**
388 * Get an SLF4J Logger.
389 *
390 * @return a Logger instance
391 */
392 private static Logger getLogger() {
393 return LoggerFactory.getLogger(Configuration.class);
394 }
395
396 static {
397 validateJCEProviders();
398
399 // Default to registering the xml:id attribute as an ID type for all configurations
400 registerIDAttribute(new QName(javax.xml.XMLConstants.XML_NS_URI, "id"));
401 }
402 }