View Javadoc
1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements. See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership. The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License. You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied. See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.wss4j.dom.engine;
21  
22  import java.security.AccessController;
23  import java.security.PrivilegedAction;
24  import java.security.Security;
25  import java.util.HashMap;
26  import java.util.Map;
27  
28  import javax.xml.datatype.DatatypeConfigurationException;
29  import javax.xml.datatype.DatatypeFactory;
30  import javax.xml.namespace.QName;
31  
32  import org.apache.wss4j.dom.WSConstants;
33  import org.apache.wss4j.dom.WsuIdAllocator;
34  import org.apache.wss4j.dom.action.Action;
35  import org.apache.wss4j.common.crypto.WSProviderConfig;
36  import org.apache.wss4j.common.ext.WSSecurityException;
37  import org.apache.wss4j.common.util.WSCurrentTimeSource;
38  import org.apache.wss4j.common.util.WSTimeSource;
39  import org.apache.wss4j.dom.processor.Processor;
40  import org.apache.wss4j.dom.resolvers.ResolverAttachment;
41  import org.apache.wss4j.dom.transform.AttachmentCiphertextTransform;
42  import org.apache.wss4j.dom.transform.AttachmentCompleteSignatureTransformProvider;
43  import org.apache.wss4j.dom.transform.AttachmentContentSignatureTransformProvider;
44  import org.apache.wss4j.dom.validate.Validator;
45  import org.apache.xml.security.stax.impl.util.IDGenerator;
46  import org.apache.xml.security.transforms.Transform;
47  import org.apache.xml.security.utils.resolver.ResourceResolver;
48  
49  /**
50   * WSSConfig <p/> Carries configuration data so the WSS4J spec compliance can be
51   * modified in runtime. Configure an instance of this object only if you need
52   * WSS4J to emulate certain industry clients or previous OASIS specifications
53   * for WS-Security interoperability testing purposes. <p/> The default settings
54   * follow the latest OASIS and changing anything might violate the OASIS specs.
55   * <p/> <b>WARNING: changing the default settings will break the compliance with
56   * the latest specs. Do this only if you know what you are doing.</b> <p/>
57   */
58  public final class WSSConfig {
59  
60      public static final DatatypeFactory DATATYPE_FACTORY;
61  
62      static {
63          try {
64              DATATYPE_FACTORY = DatatypeFactory.newInstance();
65          } catch (DatatypeConfigurationException e) {
66              throw new RuntimeException(e);
67          }
68      }
69  
70      private static final org.slf4j.Logger LOG =
71          org.slf4j.LoggerFactory.getLogger(WSSConfig.class);
72  
73      /**
74       * The default collection of actions supported by the toolkit.
75       */
76      private static final Map<Integer, Class<?>> DEFAULT_ACTIONS;
77      static {
78          final Map<Integer, Class<?>> tmp = new HashMap<>();
79          try {
80              tmp.put(
81                  WSConstants.UT,
82                  org.apache.wss4j.dom.action.UsernameTokenAction.class
83              );
84              tmp.put(
85                  WSConstants.UT_NOPASSWORD,
86                  org.apache.wss4j.dom.action.UsernameTokenAction.class
87              );
88              tmp.put(
89                  WSConstants.ENCR,
90                  org.apache.wss4j.dom.action.EncryptionAction.class
91              );
92              tmp.put(
93                  WSConstants.SIGN,
94                  org.apache.wss4j.dom.action.SignatureAction.class
95              );
96              tmp.put(
97                  WSConstants.DKT_SIGN,
98                  org.apache.wss4j.dom.action.SignatureDerivedAction.class
99              );
100             tmp.put(
101                 WSConstants.DKT_ENCR,
102                 org.apache.wss4j.dom.action.EncryptionDerivedAction.class
103             );
104             tmp.put(
105                 WSConstants.ST_SIGNED,
106                 org.apache.wss4j.dom.action.SAMLTokenSignedAction.class
107             );
108             tmp.put(
109                 WSConstants.ST_UNSIGNED,
110                 org.apache.wss4j.dom.action.SAMLTokenUnsignedAction.class
111             );
112             tmp.put(
113                 WSConstants.TS,
114                 org.apache.wss4j.dom.action.TimestampAction.class
115             );
116             tmp.put(
117                 WSConstants.UT_SIGN,
118                 org.apache.wss4j.dom.action.UsernameTokenSignedAction.class
119             );
120             tmp.put(
121                 WSConstants.SC,
122                 org.apache.wss4j.dom.action.SignatureConfirmationAction.class
123             );
124             tmp.put(
125                 WSConstants.CUSTOM_TOKEN,
126                 org.apache.wss4j.dom.action.CustomTokenAction.class
127             );
128         } catch (final Exception ex) {
129             LOG.debug(ex.getMessage(), ex);
130         }
131         DEFAULT_ACTIONS = java.util.Collections.unmodifiableMap(tmp);
132     }
133 
134     /**
135      * The default collection of processors supported by the toolkit
136      */
137     private static final Map<QName, Class<?>> DEFAULT_PROCESSORS;
138     static {
139         final Map<QName, Class<?>> tmp = new HashMap<>();
140         try {
141             tmp.put(
142                 WSConstants.SAML_TOKEN,
143                 org.apache.wss4j.dom.processor.SAMLTokenProcessor.class
144             );
145             tmp.put(
146                 WSConstants.SAML2_TOKEN,
147                 org.apache.wss4j.dom.processor.SAMLTokenProcessor.class
148             );
149             tmp.put(
150                 WSConstants.ENCRYPTED_ASSERTION,
151                 org.apache.wss4j.dom.processor.EncryptedAssertionProcessor.class
152             );
153             tmp.put(
154                 WSConstants.ENCRYPTED_KEY,
155                 org.apache.wss4j.dom.processor.EncryptedKeyProcessor.class
156             );
157             tmp.put(
158                 WSConstants.SIGNATURE,
159                 org.apache.wss4j.dom.processor.SignatureProcessor.class
160             );
161             tmp.put(
162                 WSConstants.TIMESTAMP,
163                 org.apache.wss4j.dom.processor.TimestampProcessor.class
164             );
165             tmp.put(
166                 WSConstants.USERNAME_TOKEN,
167                 org.apache.wss4j.dom.processor.UsernameTokenProcessor.class
168             );
169             tmp.put(
170                 WSConstants.REFERENCE_LIST,
171                 org.apache.wss4j.dom.processor.ReferenceListProcessor.class
172             );
173             tmp.put(
174                 WSConstants.SIGNATURE_CONFIRMATION,
175                 org.apache.wss4j.dom.processor.SignatureConfirmationProcessor.class
176             );
177             tmp.put(
178                 WSConstants.DERIVED_KEY_TOKEN_05_02,
179                 org.apache.wss4j.dom.processor.DerivedKeyTokenProcessor.class
180             );
181             tmp.put(
182                 WSConstants.DERIVED_KEY_TOKEN_05_12,
183                 tmp.get(WSConstants.DERIVED_KEY_TOKEN_05_02)
184             );
185             tmp.put(
186                 WSConstants.SECURITY_CONTEXT_TOKEN_05_02,
187                 org.apache.wss4j.dom.processor.SecurityContextTokenProcessor.class
188             );
189             tmp.put(
190                 WSConstants.SECURITY_CONTEXT_TOKEN_05_12,
191                 tmp.get(WSConstants.SECURITY_CONTEXT_TOKEN_05_02)
192             );
193             tmp.put(
194                 WSConstants.BINARY_TOKEN,
195                 org.apache.wss4j.dom.processor.BinarySecurityTokenProcessor.class
196             );
197             tmp.put(
198                 WSConstants.ENCRYPTED_DATA,
199                 org.apache.wss4j.dom.processor.EncryptedDataProcessor.class
200             );
201         } catch (final Exception ex) {
202             LOG.debug(ex.getMessage(), ex);
203         }
204         DEFAULT_PROCESSORS = java.util.Collections.unmodifiableMap(tmp);
205     }
206 
207     /**
208      * The default collection of validators supported by the toolkit
209      */
210     private static final Map<QName, Class<?>> DEFAULT_VALIDATORS;
211     static {
212         final Map<QName, Class<?>> tmp = new HashMap<>();
213         try {
214             tmp.put(
215                 WSConstants.SAML_TOKEN,
216                 org.apache.wss4j.dom.validate.SamlAssertionValidator.class
217             );
218             tmp.put(
219                 WSConstants.SAML2_TOKEN,
220                 org.apache.wss4j.dom.validate.SamlAssertionValidator.class
221             );
222             tmp.put(
223                 WSConstants.SIGNATURE,
224                 org.apache.wss4j.dom.validate.SignatureTrustValidator.class
225             );
226             tmp.put(
227                 WSConstants.TIMESTAMP,
228                 org.apache.wss4j.dom.validate.TimestampValidator.class
229             );
230             tmp.put(
231                 WSConstants.USERNAME_TOKEN,
232                 org.apache.wss4j.dom.validate.UsernameTokenValidator.class
233             );
234         } catch (final Exception ex) {
235             LOG.debug(ex.getMessage(), ex);
236         }
237         DEFAULT_VALIDATORS = java.util.Collections.unmodifiableMap(tmp);
238     }
239 
240     /**
241      * a static boolean flag that determines whether default JCE providers
242      * should be added at the time of construction.
243      *
244      * These providers, and the order in which they are added, can interfere
245      * with some JVMs (such as IBMs).
246      */
247     private static boolean addJceProviders = true;
248 
249     /**
250      * a boolean flag to record whether we have already been statically
251      * initialized.  This flag prevents repeated and unnecessary calls
252      * to static initialization code at construction time.
253      */
254     private static boolean staticallyInitialized = false;
255 
256     /**
257      * This allows the user to specify a different time than that of the current System time.
258      */
259     private WSTimeSource currentTime;
260 
261     public static final WsuIdAllocator DEFAULT_ID_ALLOCATOR = new WsuIdAllocator() {
262 
263         public String createId(String prefix, Object o) {
264             if (prefix == null) {
265                 return IDGenerator.generateID("_");
266             }
267 
268             return IDGenerator.generateID(prefix);
269         }
270 
271         public String createSecureId(String prefix, Object o) {
272             return IDGenerator.generateID(prefix);
273         }
274     };
275     protected WsuIdAllocator idAllocator = DEFAULT_ID_ALLOCATOR;
276 
277     /**
278      * The known actions. This map is of the form <Integer, Class<?>> or
279      * <Integer, Action>.
280      * The known actions are initialized from a set of defaults,
281      * but the list may be modified via the setAction operations.
282      */
283     private final Map<Integer, Object> actionMap = new HashMap<>(DEFAULT_ACTIONS);
284 
285     /**
286      * The known processors. This map is of the form <QName, Class<?>> or
287      * <QName, Processor>.
288      * The known processors are initialized from a set of defaults,
289      * but the list may be modified via the setProcessor operations.
290      */
291     private final Map<QName, Object> processorMap = new HashMap<>(DEFAULT_PROCESSORS);
292 
293     /**
294      * The known validators. This map is of the form <QName, Class<?>> or
295      * <QName, Validator>.
296      * The known validators are initialized from a set of defaults,
297      * but the list may be modified via the setValidator operations.
298      */
299     private final Map<QName, Object> validatorMap = new HashMap<>(DEFAULT_VALIDATORS);
300 
301     static {
302         try {
303             Transform.register(WSConstants.SWA_ATTACHMENT_CIPHERTEXT_TRANS,
304                     AttachmentCiphertextTransform.class);
305         } catch (Exception e) {
306             LOG.debug(e.getMessage(), e);
307         }
308 
309         ResourceResolver.register(new ResolverAttachment(), false);
310     }
311 
312     private WSSConfig() {
313         // complete
314     }
315 
316     public static synchronized void init() {
317         if (!staticallyInitialized) {
318             if (addJceProviders) {
319                 AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
320                     public Boolean run() {
321                         Security.removeProvider("STRTransform");
322                         WSProviderConfig.appendJceProvider(
323                             "STRTransform",
324                             new org.apache.wss4j.dom.transform.STRTransformProvider()
325                         );
326 
327                         Security.removeProvider("AttachmentContentSignatureTransform");
328                         WSProviderConfig.appendJceProvider(
329                                 "AttachmentContentSignatureTransform",
330                                 new AttachmentContentSignatureTransformProvider()
331                         );
332 
333                         Security.removeProvider("AttachmentCompleteSignatureTransform");
334                         WSProviderConfig.appendJceProvider(
335                                 "AttachmentCompleteSignatureTransform",
336                                 new AttachmentCompleteSignatureTransformProvider()
337                         );
338 
339                         return true;
340                     }
341                 });
342             }
343             WSProviderConfig.init();
344             staticallyInitialized = true;
345         }
346     }
347 
348     public static synchronized void cleanUp() {
349         if (staticallyInitialized) {
350             if (addJceProviders) {
351                 Security.removeProvider("STRTransform");
352                 Security.removeProvider("AttachmentContentSignatureTransform");
353                 Security.removeProvider("AttachmentCompleteSignatureTransform");
354             }
355             WSProviderConfig.cleanUp();
356 
357             staticallyInitialized = false;
358         }
359     }
360 
361     /**
362      * @return a new WSSConfig instance configured with the default values
363      */
364     public static WSSConfig getNewInstance() {
365         init();
366         return new WSSConfig();
367     }
368 
369     /**
370      * @return Returns the WsuIdAllocator used to generate wsu:Id attributes
371      */
372     public WsuIdAllocator getIdAllocator() {
373         return idAllocator;
374     }
375 
376     public void setIdAllocator(WsuIdAllocator idAllocator) {
377         this.idAllocator = idAllocator;
378     }
379 
380     /**
381      * Associate an action instance with a specific action code.
382      *
383      * This operation allows applications to supply their own
384      * actions for well-known operations.
385      *
386      * Please note that the Action object does NOT get class-loaded per invocation, and so
387      * it is up to the implementing class to ensure that it is thread-safe.
388      */
389     public Class<?> setAction(int code, Action action) {
390         Object result = actionMap.put(code, action);
391         if (result instanceof Class<?>) {
392             return (Class<?>)result;
393         } else if (result instanceof Action) {
394             return result.getClass();
395         }
396         return null;
397     }
398 
399     /**
400      * Associate an action instance with a specific action code.
401      *
402      * This operation allows applications to supply their own
403      * actions for well-known operations.
404      */
405     public Class<?> setAction(int code, Class<?> clazz) {
406         Object result = actionMap.put(code, clazz);
407         if (result instanceof Class<?>) {
408             return (Class<?>)result;
409         } else if (result instanceof Action) {
410             return result.getClass();
411         }
412         return null;
413     }
414 
415     /**
416      * Lookup action
417      *
418      * @param action
419      * @return An action class to create a security token
420      * @throws WSSecurityException
421      */
422     public Action getAction(int action) throws WSSecurityException {
423         final Object actionObject = actionMap.get(action);
424 
425         if (actionObject instanceof Class<?>) {
426             try {
427                 return (Action)((Class<?>)actionObject).getDeclaredConstructor().newInstance();
428             } catch (Exception ex) {
429                 LOG.debug(ex.getMessage(), ex);
430                 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, ex,
431                         "unableToLoadClass", new Object[] {((Class<?>)actionObject).getName()});
432             }
433         } else if (actionObject instanceof Action) {
434             return (Action)actionObject;
435         }
436         return null;
437     }
438 
439     /**
440      * Associate a SOAP processor name with a specified SOAP Security header
441      * element QName.  Processors registered under this QName will be
442      * called when processing header elements with the specified type.
443      *
444      * Please note that the Processor object does NOT get class-loaded per invocation, and so
445      * it is up to the implementing class to ensure that it is thread-safe.
446      */
447     public Class<?> setProcessor(QName el, Processor processor) {
448         Object result = processorMap.put(el, processor);
449         if (result instanceof Class<?>) {
450             return (Class<?>)result;
451         } else if (result instanceof Processor) {
452             return result.getClass();
453         }
454         return null;
455     }
456 
457     /**
458      * Associate a SOAP processor name with a specified SOAP Security header
459      * element QName.  Processors registered under this QName will be
460      * called when processing header elements with the specified type.
461      */
462     public Class<?> setProcessor(QName el, Class<?> clazz) {
463         Object result = processorMap.put(el, clazz);
464         if (result instanceof Class<?>) {
465             return (Class<?>)result;
466         } else if (result instanceof Processor) {
467             return result.getClass();
468         }
469         return null;
470     }
471 
472     /**
473      * Associate a SOAP validator name with a specified SOAP Security header
474      * element QName.  Validators registered under this QName will be
475      * called when processing header elements with the specified type.
476      *
477      * Please note that the Validator object does NOT get class-loaded per invocation, and so
478      * it is up to the implementing class to ensure that it is thread-safe.
479      */
480     public Class<?> setValidator(QName el, Validator validator) {
481         Object result = validatorMap.put(el, validator);
482         if (result instanceof Class<?>) {
483             return (Class<?>)result;
484         } else if (result instanceof Validator) {
485             return result.getClass();
486         }
487         return null;
488     }
489 
490     /**
491      * Associate a SOAP validator name with a specified SOAP Security header
492      * element QName.  validator registered under this QName will be
493      * called when processing header elements with the specified type.
494      */
495     public Class<?> setValidator(QName el, Class<?> clazz) {
496         Object result = validatorMap.put(el, clazz);
497         if (result instanceof Class<?>) {
498             return (Class<?>)result;
499         } else if (result instanceof Validator) {
500             return result.getClass();
501         }
502         return null;
503     }
504 
505     /**
506      * @return      the SOAP Validator associated with the specified
507      *              QName.  The QName is intended to refer to an element
508      *              in a SOAP security header.  This operation returns
509      *              null if there is no Validator associated with the
510      *              specified QName.
511      */
512     public Validator getValidator(QName el) throws WSSecurityException {
513         final Object validatorObject = validatorMap.get(el);
514 
515         if (validatorObject instanceof Class<?>) {
516             try {
517                 return (Validator)((Class<?>)validatorObject).getDeclaredConstructor().newInstance();
518             } catch (Exception ex) {
519                 LOG.debug(ex.getMessage(), ex);
520                 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, ex,
521                     "unableToLoadClass", new Object[] {((Class<?>)validatorObject).getName()});
522             }
523         } else if (validatorObject instanceof Validator) {
524             return (Validator)validatorObject;
525         }
526         return null;
527     }
528 
529     /**
530      * @return      the SOAP processor associated with the specified
531      *              QName.  The QName is intended to refer to an element
532      *              in a SOAP security header.  This operation returns
533      *              null if there is no processor associated with the
534      *              specified QName.
535      */
536     public Processor getProcessor(QName el) throws WSSecurityException {
537         final Object processorObject = processorMap.get(el);
538 
539         if (processorObject instanceof Class<?>) {
540             try {
541                 return (Processor)((Class<?>)processorObject).getDeclaredConstructor().newInstance();
542             } catch (Exception ex) {
543                 LOG.debug(ex.getMessage(), ex);
544                 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, ex,
545                         "unableToLoadClass", new Object[] {((Class<?>)processorObject).getName()});
546             }
547         } else if (processorObject instanceof Processor) {
548             return (Processor)processorObject;
549         }
550         return null;
551     }
552 
553     public WSTimeSource getCurrentTime() {
554         if (currentTime != null) {
555             return currentTime;
556         }
557         return new WSCurrentTimeSource();
558     }
559 
560     public void setCurrentTime(WSTimeSource currentTime) {
561         this.currentTime = currentTime;
562     }
563 
564 
565     public static boolean isAddJceProviders() {
566         return addJceProviders;
567     }
568 
569     public static void setAddJceProviders(boolean addJceProviders) {
570         WSSConfig.addJceProviders = addJceProviders;
571         WSProviderConfig.setAddJceProviders(addJceProviders);
572     }
573 }