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.ws.security;
21  
22  import java.lang.reflect.Field;
23  import java.security.AccessController;
24  import java.security.PrivilegedAction;
25  import java.security.PrivilegedExceptionAction;
26  import java.security.Provider;
27  import java.security.Security;
28  import java.util.HashMap;
29  import java.util.Map;
30  
31  import javax.xml.namespace.QName;
32  
33  import org.apache.ws.security.action.Action;
34  import org.apache.ws.security.processor.Processor;
35  import org.apache.ws.security.util.Loader;
36  import org.apache.ws.security.util.UUIDGenerator;
37  import org.apache.ws.security.validate.Validator;
38  import org.apache.xml.security.utils.XMLUtils;
39  
40  /**
41   * WSSConfig <p/> Carries configuration data so the WSS4J spec compliance can be
42   * modified in runtime. Configure an instance of this object only if you need
43   * WSS4J to emulate certain industry clients or previous OASIS specifications
44   * for WS-Security interoperability testing purposes. <p/> The default settings
45   * follow the latest OASIS and changing anything might violate the OASIS specs.
46   * <p/> <b>WARNING: changing the default settings will break the compliance with
47   * the latest specs. Do this only if you know what you are doing.</b> <p/>
48   * 
49   * @author Rami Jaamour (rjaamour@parasoft.com)
50   * @author Werner Dittmann (werner@apache.org)
51   */
52  public class WSSConfig {
53      
54      private static final org.apache.commons.logging.Log LOG = 
55          org.apache.commons.logging.LogFactory.getLog(WSSConfig.class);
56  
57      /**
58       * The default collection of actions supported by the toolkit.
59       */
60      private static final Map<Integer, Class<?>> DEFAULT_ACTIONS;
61      static {
62          final Map<Integer, Class<?>> tmp = new HashMap<Integer, Class<?>>();
63          try {
64              tmp.put(
65                  Integer.valueOf(WSConstants.UT),
66                  org.apache.ws.security.action.UsernameTokenAction.class
67              );
68              tmp.put(
69                  Integer.valueOf(WSConstants.ENCR),
70                  org.apache.ws.security.action.EncryptionAction.class
71              );
72              tmp.put(
73                  Integer.valueOf(WSConstants.SIGN),
74                  org.apache.ws.security.action.SignatureAction.class
75              );
76              tmp.put(
77                  Integer.valueOf(WSConstants.ST_SIGNED),
78                  org.apache.ws.security.action.SAMLTokenSignedAction.class
79              );
80              tmp.put(
81                  Integer.valueOf(WSConstants.ST_UNSIGNED),
82                  org.apache.ws.security.action.SAMLTokenUnsignedAction.class
83              );
84              tmp.put(
85                  Integer.valueOf(WSConstants.TS),
86                  org.apache.ws.security.action.TimestampAction.class
87              );
88              tmp.put(
89                  Integer.valueOf(WSConstants.UT_SIGN),
90                  org.apache.ws.security.action.UsernameTokenSignedAction.class
91              );
92              tmp.put(
93                  Integer.valueOf(WSConstants.SC),
94                  org.apache.ws.security.action.SignatureConfirmationAction.class
95              );
96          } catch (final Exception ex) {
97              if (LOG.isDebugEnabled()) {
98                  LOG.debug(ex.getMessage(), ex);
99              }
100         }
101         DEFAULT_ACTIONS = java.util.Collections.unmodifiableMap(tmp);
102     }
103 
104     /**
105      * The default collection of processors supported by the toolkit
106      */
107     private static final Map<QName, Class<?>> DEFAULT_PROCESSORS;
108     static {
109         final Map<QName, Class<?>> tmp = new HashMap<QName, Class<?>>();
110         try {
111             tmp.put(
112                 WSSecurityEngine.SAML_TOKEN,
113                 org.apache.ws.security.processor.SAMLTokenProcessor.class
114             );
115             tmp.put(
116                 WSSecurityEngine.SAML2_TOKEN,
117                 org.apache.ws.security.processor.SAMLTokenProcessor.class
118             );
119             tmp.put(
120                 WSSecurityEngine.ENCRYPTED_KEY,
121                 org.apache.ws.security.processor.EncryptedKeyProcessor.class
122             );
123             tmp.put(
124                 WSSecurityEngine.SIGNATURE,
125                 org.apache.ws.security.processor.SignatureProcessor.class
126             );
127             tmp.put(
128                 WSSecurityEngine.TIMESTAMP,
129                 org.apache.ws.security.processor.TimestampProcessor.class
130             );
131             tmp.put(
132                 WSSecurityEngine.USERNAME_TOKEN,
133                 org.apache.ws.security.processor.UsernameTokenProcessor.class
134             );
135             tmp.put(
136                 WSSecurityEngine.REFERENCE_LIST,
137                 org.apache.ws.security.processor.ReferenceListProcessor.class
138             );
139             tmp.put(
140                 WSSecurityEngine.SIGNATURE_CONFIRMATION,
141                 org.apache.ws.security.processor.SignatureConfirmationProcessor.class
142             );
143             tmp.put(
144                 WSSecurityEngine.DERIVED_KEY_TOKEN_05_02,
145                 org.apache.ws.security.processor.DerivedKeyTokenProcessor.class
146             );
147             tmp.put(
148                 WSSecurityEngine.DERIVED_KEY_TOKEN_05_12,
149                 tmp.get(WSSecurityEngine.DERIVED_KEY_TOKEN_05_02)
150             );
151             tmp.put(
152                 WSSecurityEngine.SECURITY_CONTEXT_TOKEN_05_02,
153                 org.apache.ws.security.processor.SecurityContextTokenProcessor.class
154             );
155             tmp.put(
156                 WSSecurityEngine.SECURITY_CONTEXT_TOKEN_05_12,
157                 tmp.get(WSSecurityEngine.SECURITY_CONTEXT_TOKEN_05_02)
158             );
159             tmp.put(
160                 WSSecurityEngine.BINARY_TOKEN,
161                 org.apache.ws.security.processor.BinarySecurityTokenProcessor.class
162             );
163             tmp.put(
164                 WSSecurityEngine.ENCRYPTED_DATA,
165                 org.apache.ws.security.processor.EncryptedDataProcessor.class
166             );
167         } catch (final Exception ex) {
168             if (LOG.isDebugEnabled()) {
169                 LOG.debug(ex.getMessage(), ex);
170             }
171         }
172         DEFAULT_PROCESSORS = java.util.Collections.unmodifiableMap(tmp);
173     }
174     
175     /**
176      * The default collection of validators supported by the toolkit
177      */
178     private static final Map<QName, Class<?>> DEFAULT_VALIDATORS;
179     static {
180         final Map<QName, Class<?>> tmp = new HashMap<QName, Class<?>>();
181         try {
182             tmp.put(
183                 WSSecurityEngine.SAML_TOKEN,
184                 org.apache.ws.security.validate.SamlAssertionValidator.class
185             );
186             tmp.put(
187                 WSSecurityEngine.SAML2_TOKEN,
188                 org.apache.ws.security.validate.SamlAssertionValidator.class
189             );
190             tmp.put(
191                 WSSecurityEngine.SIGNATURE,
192                 org.apache.ws.security.validate.SignatureTrustValidator.class
193             );
194             tmp.put(
195                 WSSecurityEngine.TIMESTAMP,
196                 org.apache.ws.security.validate.TimestampValidator.class
197             );
198             tmp.put(
199                 WSSecurityEngine.USERNAME_TOKEN,
200                 org.apache.ws.security.validate.UsernameTokenValidator.class
201             );
202         } catch (final Exception ex) {
203             if (LOG.isDebugEnabled()) {
204                 LOG.debug(ex.getMessage(), ex);
205             }
206         }
207         DEFAULT_VALIDATORS = java.util.Collections.unmodifiableMap(tmp);
208     }
209 
210     protected boolean wsiBSPCompliant = true;
211 
212     /**
213      * Set the timestamp precision mode. If set to <code>true</code> then use
214      * timestamps with milliseconds, otherwise omit the milliseconds. As per XML
215      * Date/Time specification the default is to include the milliseconds.
216      */
217     protected boolean precisionInMilliSeconds = true;
218 
219     protected boolean enableSignatureConfirmation = false;
220 
221     /**
222      * If set to true then the timestamp handling will throw an exception if the
223      * timestamp contains an expires element and the semantics are expired.
224      * 
225      * If set to false, no exception will be thrown, even if the semantics are
226      * expired.
227      */
228     protected boolean timeStampStrict = true;
229     
230     /**
231      * If this value is not null, then username token handling will throw an 
232      * exception if the password type of the Username Token does not match this value
233      */
234     protected String requiredPasswordType = null;
235     
236     /**
237      * The time in seconds between creation and expiry for a Timestamp. The default
238      * is 300 seconds (5 minutes).
239      */
240     protected int timeStampTTL = 300;
241     
242     /**
243      * The time in seconds in the future within which the Created time of an incoming 
244      * Timestamp is valid. The default is 60 seconds.
245      */
246     protected int timeStampFutureTTL = 60;
247     
248     /**
249      * This variable controls whether types other than PasswordDigest or PasswordText
250      * are allowed when processing UsernameTokens. 
251      * 
252      * By default this is set to false so that the user doesn't have to explicitly
253      * reject custom token types in the callback handler.
254      */
255     protected boolean handleCustomPasswordTypes = false;
256     
257     /**
258      * This variable controls whether (wsse) namespace qualified password types are
259      * accepted when processing UsernameTokens.
260      * 
261      * By default this is set to false.
262      */
263     protected boolean allowNamespaceQualifiedPasswordTypes = false;
264     
265     /**
266      * The secret key length to be used for UT_SIGN.
267      */
268     protected int secretKeyLength = WSConstants.WSE_DERIVED_KEY_LEN;
269 
270     /**
271      * Whether the password should be treated as a binary value.  This
272      * is needed to properly handle password equivalence for UsernameToken
273      * passwords.  Binary passwords are Base64 encoded so they can be
274      * treated as strings in most places, but when the password digest
275      * is calculated or a key is derived from the password, the password
276      * will be Base64 decoded before being used. This is most useful for
277      * hashed passwords as password equivalents.
278      *
279      * See https://issues.apache.org/jira/browse/WSS-239
280      */
281     protected boolean passwordsAreEncoded = false;
282     
283     /**
284      * The default wsu:Id allocator is a simple "start at 1 and increment up"
285      * thing that is very fast.
286      */
287     public static final WsuIdAllocator DEFAULT_ID_ALLOCATOR = new WsuIdAllocator() {
288         int i;
289         private synchronized String next() {
290             return Integer.toString(++i);
291         }
292         public String createId(String prefix, Object o) {
293             if (prefix == null) {
294                 return next();
295             }
296             return prefix + next();
297         }
298 
299         public String createSecureId(String prefix, Object o) {
300             if (prefix == null) {
301                 return UUIDGenerator.getUUID();
302             }
303             return prefix + UUIDGenerator.getUUID();
304         }
305     };
306     protected WsuIdAllocator idAllocator = DEFAULT_ID_ALLOCATOR;
307     
308     /**
309      * The known actions. This map is of the form <Integer, Class<?>> or 
310      * <Integer, Action>. 
311      * The known actions are initialized from a set of defaults,
312      * but the list may be modified via the setAction operations.
313      */
314     private final Map<Integer, Object> actionMap = 
315         new HashMap<Integer, Object>(DEFAULT_ACTIONS);
316 
317     /**
318      * The known processors. This map is of the form <QName, Class<?>> or
319      * <QName, Processor>.
320      * The known processors are initialized from a set of defaults,
321      * but the list may be modified via the setProcessor operations.
322      */
323     private final Map<QName, Object> processorMap = 
324         new HashMap<QName, Object>(DEFAULT_PROCESSORS);
325     
326     /**
327      * The known validators. This map is of the form <QName, Class<?>> or
328      * <QName, Validator>.
329      * The known validators are initialized from a set of defaults,
330      * but the list may be modified via the setValidator operations.
331      */
332     private final Map<QName, Object> validatorMap = 
333         new HashMap<QName, Object>(DEFAULT_VALIDATORS);
334     
335     /**
336      * a static boolean flag that determines whether default JCE providers
337      * should be added at the time of construction.
338      *
339      * These providers, and the order in which they are added, can interfere
340      * with some JVMs (such as IBMs).
341      */
342     private static boolean addJceProviders = true;
343     
344     /**
345      * a boolean flag to record whether we have already been statically
346      * initialized.  This flag prevents repeated and unnecessary calls
347      * to static initialization code at construction time.
348      */
349     private static boolean staticallyInitialized = false;
350     
351     /**
352      * Set the value of the internal addJceProviders flag.  This flag
353      * turns on (or off) automatic registration of known JCE providers
354      * that provide necessary cryptographic algorithms for use with WSS4J.
355      * By default, this flag is true.  You may wish (or need) to initialize 
356      * the JCE manually, e.g., in some JVMs.
357      */
358     public static void setAddJceProviders(boolean value) {
359         addJceProviders = value;
360     }
361     
362     private static void setXmlSecIgnoreLineBreak() {
363         //really need to make sure ignoreLineBreaks is set to
364         boolean wasSet = false;
365         try {
366             // Don't override if it was set explicitly
367             wasSet = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
368                 public Boolean run() {
369                     String lineBreakPropName = "org.apache.xml.security.ignoreLineBreaks";
370                     if (System.getProperty(lineBreakPropName) == null) {
371                         System.setProperty(lineBreakPropName, "true");
372                         return false;
373                     }
374                     return true; 
375                 }
376             });
377         } catch (Throwable t) { //NOPMD
378             //ignore
379         }
380         org.apache.xml.security.Init.init();
381         if (!wasSet) {
382             try {
383                 AccessController.doPrivileged(new PrivilegedExceptionAction<Boolean>() {
384                     public Boolean run() throws Exception {
385                         Field f = XMLUtils.class.getDeclaredField("ignoreLineBreaks");
386                         f.setAccessible(true);
387                         f.set(null, Boolean.TRUE);
388                         return false;
389                     }
390                 });
391             } catch (Throwable t) { //NOPMD
392                 //ignore
393             }
394         }
395     }
396     
397     public static synchronized void init() {
398         if (!staticallyInitialized) {
399             if (addJceProviders) {
400                 setXmlSecIgnoreLineBreak();
401                 AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
402                     public Boolean run() {
403                         addXMLDSigRI();
404                         addJceProvider("BC", "org.bouncycastle.jce.provider.BouncyCastleProvider");
405                         Security.removeProvider("STRTransform");
406                         appendJceProvider(
407                             "STRTransform", new org.apache.ws.security.transform.STRTransformProvider()
408                         );
409                         
410                         return true;
411                     }
412                 });
413             }
414             staticallyInitialized = true;
415         }
416     }
417     
418     private static void addXMLDSigRI() {
419         try {
420             addXMLDSigRIInternal();
421         } catch (Throwable t) {
422             //ignore - may be a NoClassDefFound if XMLDSigRI isn't avail
423             return;
424         }
425     }
426     
427     public static void addXMLDSigRIInternal() {
428         addJceProvider("ApacheXMLDSig", SantuarioUtil.getSantuarioProvider());
429     }
430 
431     /**
432      * @return a new WSSConfig instance configured with the default values
433      */
434     public static WSSConfig getNewInstance() {
435         init();
436         return new WSSConfig();
437     }
438 
439     /**
440      * Checks if we are in WS-I Basic Security Profile compliance mode
441      * 
442      * @return whether we are in WS-I Basic Security Profile compliance mode
443      */
444     public boolean isWsiBSPCompliant() {
445         return wsiBSPCompliant;
446     }
447 
448     /**
449      * Set the WS-I Basic Security Profile compliance mode. The default is true.
450      * 
451      * @param wsiBSPCompliant
452      */
453     public void setWsiBSPCompliant(boolean wsiBSPCompliant) {
454         this.wsiBSPCompliant = wsiBSPCompliant;
455     }
456 
457     /**
458      * Checks if we need to use milliseconds in timestamps
459      * 
460      * @return whether to use precision in milliseconds for timestamps
461      */
462     public boolean isPrecisionInMilliSeconds() {
463         return precisionInMilliSeconds;
464     }
465 
466     /**
467      * Set the precision in milliseconds for timestamps
468      * 
469      * @param precisionInMilliSeconds whether to use precision in milliseconds for timestamps
470      */
471     public void setPrecisionInMilliSeconds(boolean precisionInMilliSeconds) {
472         this.precisionInMilliSeconds = precisionInMilliSeconds;
473     }
474 
475     /**
476      * @return Returns the enableSignatureConfirmation.
477      */
478     public boolean isEnableSignatureConfirmation() {
479         return enableSignatureConfirmation;
480     }
481 
482     /**
483      * @param enableSignatureConfirmation
484      *            The enableSignatureConfirmation to set.
485      */
486     public void setEnableSignatureConfirmation(boolean enableSignatureConfirmation) {
487         this.enableSignatureConfirmation = enableSignatureConfirmation;
488     }
489     
490     /**
491      * @param handleCustomTypes 
492      * whether to handle custom UsernameToken password types or not
493      */
494     public void setHandleCustomPasswordTypes(boolean handleCustomTypes) {
495         this.handleCustomPasswordTypes = handleCustomTypes;
496     }
497     
498     /**
499      * @return whether custom UsernameToken password types are allowed or not
500      */
501     public boolean getHandleCustomPasswordTypes() {
502         return handleCustomPasswordTypes;
503     }
504     
505     /**
506      * @param allowNamespaceQualifiedTypes
507      * whether (wsse) namespace qualified password types are accepted or not
508      */
509     public void setAllowNamespaceQualifiedPasswordTypes(boolean allowNamespaceQualifiedTypes) {
510         allowNamespaceQualifiedPasswordTypes = allowNamespaceQualifiedTypes;
511     }
512     
513     /**
514      * @return whether (wsse) namespace qualified password types are accepted or not
515      */
516     public boolean getAllowNamespaceQualifiedPasswordTypes() {
517         return allowNamespaceQualifiedPasswordTypes;
518     }
519     
520     /**
521      * @return Returns if we shall throw an exception on expired request
522      *         semantic
523      */
524     public boolean isTimeStampStrict() {
525         return timeStampStrict;
526     }
527 
528     /**
529      * @param timeStampStrict
530      *            If true throw an exception on expired request semantic
531      */
532     public void setTimeStampStrict(boolean timeStampStrict) {
533         this.timeStampStrict = timeStampStrict;
534     }
535     
536     /**
537      * @return the required password type when processing a UsernameToken
538      */
539     public String getRequiredPasswordType() {
540         return requiredPasswordType;
541     }
542 
543     /**
544      * @param requiredPasswordType The required password type when processing
545      * a Username Token.
546      */
547     public void setRequiredPasswordType(String requiredPasswordType) {
548         this.requiredPasswordType = requiredPasswordType;
549     }
550     
551     /**
552      * @return Returns the TTL of a Timestamp in seconds
553      */
554     public int getTimeStampTTL() {
555         return timeStampTTL;
556     }
557 
558     /**
559      * @param timeStampTTL The new value for timeStampTTL
560      */
561     public void setTimeStampTTL(int timeStampTTL) {
562         this.timeStampTTL = timeStampTTL;
563     }
564     
565     /**
566      * @return Returns the Future TTL of a Timestamp in seconds
567      */
568     public int getTimeStampFutureTTL() {
569         return timeStampFutureTTL;
570     }
571 
572     /**
573      * @param timeStampFutureTTL the new value for timeStampFutureTTL
574      */
575     public void setTimeStampFutureTTL(int timeStampFutureTTL) {
576         this.timeStampFutureTTL = timeStampFutureTTL;
577     }
578     
579     /**
580      * Set the secret key length to be used for UT_SIGN.
581      */
582     public void setSecretKeyLength(int length) {
583         secretKeyLength = length;
584     }
585     
586     /**
587      * Get the secret key length to be used for UT_SIGN.
588      */
589     public int getSecretKeyLength() {
590         return secretKeyLength;
591     }
592     
593     /**
594      * @param passwordsAreEncoded
595      * whether passwords are encoded
596      */
597     public void setPasswordsAreEncoded(boolean passwordsAreEncoded) {
598         this.passwordsAreEncoded = passwordsAreEncoded;
599     }
600     
601     /**
602      * @return whether passwords are encoded
603      */
604     public boolean getPasswordsAreEncoded() {
605         return passwordsAreEncoded;
606     }
607     
608     /**
609      * @return Returns the WsuIdAllocator used to generate wsu:Id attributes
610      */
611     public WsuIdAllocator getIdAllocator() {
612         return idAllocator;
613     }
614 
615     public void setIdAllocator(WsuIdAllocator idAllocator) {
616         this.idAllocator = idAllocator;
617     }
618     
619     /**
620      * Associate an action instance with a specific action code.
621      *
622      * This operation allows applications to supply their own
623      * actions for well-known operations.
624      * 
625      * Please note that the Action object does NOT get class-loaded per invocation, and so
626      * it is up to the implementing class to ensure that it is thread-safe.
627      */
628     public Class<?> setAction(int code, Action action) {
629         Object result = actionMap.put(Integer.valueOf(code), action);
630         if (result instanceof Class<?>) {
631             return (Class<?>)result;
632         } else if (result instanceof Action) {
633             return result.getClass();
634         }
635         return null;
636     }
637     
638     /**
639      * Associate an action instance with a specific action code.
640      *
641      * This operation allows applications to supply their own
642      * actions for well-known operations.
643      */
644     public Class<?> setAction(int code, Class<?> clazz) {
645         Object result = actionMap.put(Integer.valueOf(code), clazz);
646         if (result instanceof Class<?>) {
647             return (Class<?>)result;
648         } else if (result instanceof Action) {
649             return result.getClass();
650         }
651         return null;
652     }
653 
654     /**
655      * Lookup action
656      * 
657      * @param action
658      * @return An action class to create a security token
659      * @throws WSSecurityException
660      */
661     public Action getAction(int action) throws WSSecurityException {
662         final Object actionObject = actionMap.get(Integer.valueOf(action));
663         
664         if (actionObject instanceof Class<?>) {
665             try {
666                 return (Action)((Class<?>)actionObject).newInstance();
667             } catch (Throwable t) {
668                 if (LOG.isDebugEnabled()) {
669                     LOG.debug(t.getMessage(), t);
670                 }
671                 throw new WSSecurityException(WSSecurityException.FAILURE,
672                         "unableToLoadClass", new Object[] { ((Class<?>)actionObject).getName() }, t);
673             }
674         } else if (actionObject instanceof Action) {
675             return (Action)actionObject;
676         }
677         return null;
678     }
679     
680     /**
681      * Associate a SOAP processor name with a specified SOAP Security header
682      * element QName.  Processors registered under this QName will be
683      * called when processing header elements with the specified type.
684      * 
685      * Please note that the Processor object does NOT get class-loaded per invocation, and so
686      * it is up to the implementing class to ensure that it is thread-safe.
687      */
688     public Class<?> setProcessor(QName el, Processor processor) {
689         Object result = processorMap.put(el, processor);
690         if (result instanceof Class<?>) {
691             return (Class<?>)result;
692         } else if (result instanceof Processor) {
693             return result.getClass();
694         }
695         return null;
696     }
697     
698     /**
699      * Associate a SOAP processor name with a specified SOAP Security header
700      * element QName.  Processors registered under this QName will be
701      * called when processing header elements with the specified type.
702      */
703     public Class<?> setProcessor(QName el, Class<?> clazz) {
704         Object result = processorMap.put(el, clazz);
705         if (result instanceof Class<?>) {
706             return (Class<?>)result;
707         } else if (result instanceof Processor) {
708             return result.getClass();
709         }
710         return null;
711     }
712     
713     /**
714      * Associate a SOAP validator name with a specified SOAP Security header
715      * element QName.  Validators registered under this QName will be
716      * called when processing header elements with the specified type.
717      * 
718      * Please note that the Validator object does NOT get class-loaded per invocation, and so
719      * it is up to the implementing class to ensure that it is thread-safe.
720      */
721     public Class<?> setValidator(QName el, Validator validator) {
722         Object result = validatorMap.put(el, validator);
723         if (result instanceof Class<?>) {
724             return (Class<?>)result;
725         } else if (result instanceof Validator) {
726             return result.getClass();
727         }
728         return null;
729     }
730     
731     /**
732      * Associate a SOAP validator name with a specified SOAP Security header
733      * element QName.  validator registered under this QName will be
734      * called when processing header elements with the specified type.
735      */
736     public Class<?> setValidator(QName el, Class<?> clazz) {
737         Object result = validatorMap.put(el, clazz);
738         if (result instanceof Class<?>) {
739             return (Class<?>)result;
740         } else if (result instanceof Validator) {
741             return result.getClass();
742         }
743         return null;
744     }
745     
746     /**
747      * @return      the SOAP Validator associated with the specified
748      *              QName.  The QName is intended to refer to an element
749      *              in a SOAP security header.  This operation returns
750      *              null if there is no Validator associated with the 
751      *              specified QName.
752      */
753     public Validator getValidator(QName el) throws WSSecurityException {
754         final Object validatorObject = validatorMap.get(el);
755         
756         if (validatorObject instanceof Class<?>) {
757             try {
758                 return (Validator)((Class<?>)validatorObject).newInstance();
759             } catch (Throwable t) {
760                 if (LOG.isDebugEnabled()) {
761                     LOG.debug(t.getMessage(), t);
762                 }
763                 throw new WSSecurityException(WSSecurityException.FAILURE,
764                     "unableToLoadClass", new Object[] { ((Class<?>)validatorObject).getName() }, t);
765             }
766         } else if (validatorObject instanceof Validator) {
767             return (Validator)validatorObject;
768         }
769         return null;
770     }
771     
772     /**
773      * @return      the SOAP processor associated with the specified
774      *              QName.  The QName is intended to refer to an element
775      *              in a SOAP security header.  This operation returns
776      *              null if there is no processor associated with the 
777      *              specified QName.
778      */
779     public Processor getProcessor(QName el) throws WSSecurityException {
780         final Object processorObject = processorMap.get(el);
781         
782         if (processorObject instanceof Class<?>) {
783             try {
784                 return (Processor)((Class<?>)processorObject).newInstance();
785             } catch (Throwable t) {
786                 if (LOG.isDebugEnabled()) {
787                     LOG.debug(t.getMessage(), t);
788                 }
789                 throw new WSSecurityException(WSSecurityException.FAILURE,
790                         "unableToLoadClass", new Object[] { ((Class<?>)processorObject).getName() }, t);
791             }
792         } else if (processorObject instanceof Processor) {
793             return (Processor)processorObject;
794         }
795         return null;
796     }
797 
798     /**
799      * Add a new JCE security provider to use for WSS4J, of the specified name and class. Return
800      * either the name of the previously loaded provider, the name of the new loaded provider, or
801      * null if there's an exception in loading the provider. Add the provider either after the SUN
802      * provider (see WSS-99), or the IBMJCE provider. Otherwise fall back to the old behaviour of
803      * inserting the provider in position 2.
804      * 
805      * @param name
806      *            The name string of the provider (this may not be the real name of the provider)
807      * @param className
808      *            Name of the class the implements the provider. This class must
809      *            be a subclass of <code>java.security.Provider</code>
810      * 
811      * @return Returns the actual name of the provider that was loaded
812      */
813     public static String addJceProvider(String name, String className) {
814         Provider currentProvider = Security.getProvider(name);
815         if (currentProvider == null) {
816             try {
817                 Class<? extends Provider> clazz = Loader.loadClass(className, false, Provider.class);
818                 Provider provider = clazz.newInstance();
819                 return addJceProvider(name, provider);
820             } catch (Throwable t) {
821                 if (LOG.isDebugEnabled()) {
822                     LOG.debug("The provider " + name + " could not be added: " + t.getMessage(), t);
823                 }
824                 return null;
825             }
826         }
827         return currentProvider.getName();
828     }
829     
830     /**
831      * Add a new JCE security provider to use for WSS4J, of the specified name and class. Return
832      * either the name of the previously loaded provider, the name of the new loaded provider, or
833      * null if there's an exception in loading the provider. Add the provider either after the SUN
834      * provider (see WSS-99), or the IBMJCE provider. Otherwise fall back to the old behaviour of
835      * inserting the provider in position 2.
836      * 
837      * @param name
838      *            The name string of the provider (this may not be the real name of the provider)
839      * @param provider
840      *            A subclass of <code>java.security.Provider</code>
841      * 
842      * @return Returns the actual name of the provider that was loaded
843      */
844     public static String addJceProvider(String name, Provider provider) {
845         Provider currentProvider = Security.getProvider(name);
846         if (currentProvider == null) {
847             try {
848                 //
849                 // Install the provider after the SUN provider (see WSS-99)
850                 // Otherwise fall back to the old behaviour of inserting
851                 // the provider in position 2. For AIX, install it after
852                 // the IBMJCE provider.
853                 //
854                 int ret = 0;
855                 Provider[] provs = Security.getProviders();
856                 for (int i = 0; i < provs.length; i++) {
857                     if ("SUN".equals(provs[i].getName())
858                         || "IBMJCE".equals(provs[i].getName())) {
859                         ret = Security.insertProviderAt(provider, i + 2);
860                         break;
861                     }
862                 }
863                 if (ret == 0) {
864                     ret = Security.insertProviderAt(provider, 2);
865                 }
866                 if (LOG.isDebugEnabled()) {
867                     LOG.debug(
868                         "The provider " + provider.getName() + " - "
869                          + provider.getVersion() + " was added at position: " + ret
870                     );
871                 }
872                 return provider.getName();
873             } catch (Throwable t) {
874                 if (LOG.isDebugEnabled()) {
875                     LOG.debug("The provider " + name + " could not be added: " + t.getMessage(), t);
876                 }
877                 return null;
878             }
879         }
880         return currentProvider.getName();
881     }
882     
883     
884     /**
885      * Add a new JCE security provider to use for WSS4J, of the specified name and class. Return
886      * either the name of the previously loaded provider, the name of the new loaded provider, or
887      * null if there's an exception in loading the provider. Append the provider to the provider
888      * list.
889      * 
890      * @param name
891      *            The name string of the provider (this may not be the real name of the provider)
892      * @param className
893      *            Name of the class the implements the provider. This class must
894      *            be a subclass of <code>java.security.Provider</code>
895      * 
896      * @return Returns the actual name of the provider that was loaded
897      */
898     public static String appendJceProvider(String name, String className) {
899         Provider currentProvider = Security.getProvider(name);
900         if (currentProvider == null) {
901             try {
902                 Class<? extends Provider> clazz = Loader.loadClass(className, false, Provider.class);
903                 Provider provider = clazz.newInstance();
904                 
905                 int ret = Security.addProvider(provider);
906                 if (LOG.isDebugEnabled()) {
907                     LOG.debug(
908                         "The provider " + provider.getName() 
909                         + " was added at position: " + ret
910                     );
911                 }
912                 return provider.getName();
913             } catch (Throwable t) {
914                 if (LOG.isDebugEnabled()) {
915                     LOG.debug("The provider " + name + " could not be added: " + t.getMessage(), t);
916                 }
917                 return null;
918             }
919         }
920         return currentProvider.getName();
921     }
922     
923     /**
924      * Add a new JCE security provider to use for WSS4J, of the specified name and class. Return
925      * either the name of the previously loaded provider, the name of the new loaded provider, or
926      * null if there's an exception in loading the provider. Append the provider to the provider
927      * list.
928      * 
929      * @param name
930      *            The name string of the provider (this may not be the real name of the provider)
931      * @param provider
932      *            A subclass of <code>java.security.Provider</code>
933      * 
934      * @return Returns the actual name of the provider that was loaded
935      */
936     public static String appendJceProvider(String name, Provider provider) {
937         Provider currentProvider = Security.getProvider(name);
938         if (currentProvider == null) {
939             try {
940                 int ret = Security.addProvider(provider);
941                 if (LOG.isDebugEnabled()) {
942                     LOG.debug(
943                         "The provider " + provider.getName() 
944                         + " was added at position: " + ret
945                     );
946                 }
947                 return provider.getName();
948             } catch (Throwable t) {
949                 if (LOG.isDebugEnabled()) {
950                     LOG.debug("The provider " + name + " could not be added: " + t.getMessage(), t);
951                 }
952                 return null;
953             }
954         }
955         return currentProvider.getName();
956     }
957     
958 }