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.common.crypto;
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  
29  import org.apache.wss4j.common.util.Loader;
30  import org.apache.xml.security.utils.I18n;
31  import org.apache.xml.security.utils.XMLUtils;
32  
33  
34  /**
35   * Configure Crypto providers.
36   */
37  public final class WSProviderConfig {
38  
39      private static final org.slf4j.Logger LOG =
40          org.slf4j.LoggerFactory.getLogger(WSProviderConfig.class);
41  
42      /**
43       * a static boolean flag that determines whether default JCE providers
44       * should be added at the time of construction.
45       *
46       * These providers, and the order in which they are added, can interfere
47       * with some JVMs (such as IBMs).
48       */
49      private static boolean addJceProviders = true;
50  
51      /**
52       * a boolean flag to record whether we have already been statically
53       * initialized.  This flag prevents repeated and unnecessary calls
54       * to static initialization code at construction time.
55       */
56      private static boolean staticallyInitialized;
57  
58      private static boolean santuarioProviderAdded;
59      private static boolean bcProviderAdded;
60      private static boolean tlProviderAdded;
61  
62      private WSProviderConfig() {
63          // complete
64      }
65  
66      public static synchronized void init() {
67          if (!staticallyInitialized) {
68              if (addJceProviders) {
69                  initializeResourceBundles();
70                  setXmlSecIgnoreLineBreak();
71                  AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
72                      public Boolean run() {
73                          addXMLDSigRIInternal();
74                          return true;
75                      }
76                  });
77  
78                  santuarioProviderAdded = true;
79                  bcProviderAdded = false;
80                  tlProviderAdded = false;
81              }
82              staticallyInitialized = true;
83          }
84      }
85  
86      public static synchronized void init(boolean addXMLDSigRIInternalProv, boolean addBCProv, boolean addTLProv) {
87          if (!staticallyInitialized) {
88              initializeResourceBundles();
89              setXmlSecIgnoreLineBreak();
90              santuarioProviderAdded = addXMLDSigRIInternalProv;
91              if (addXMLDSigRIInternalProv) {
92                  AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
93                      public Boolean run() {
94                          addXMLDSigRIInternal();
95                          return true;
96                      }
97                  });
98              }
99  
100             bcProviderAdded = addBCProv;
101             if (addBCProv) {
102                 AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
103                     public Boolean run() {
104                         addJceProvider("BC", "org.bouncycastle.jce.provider.BouncyCastleProvider");
105                         return true;
106                     }
107                 });
108             }
109 
110             tlProviderAdded = addTLProv;
111             if (addTLProv) {
112                 AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
113                     public Boolean run() {
114                         ThreadLocalSecurityProvider.install();
115                         return true;
116                     }
117                 });
118             }
119             staticallyInitialized = true;
120         }
121     }
122 
123     public static synchronized void cleanUp() {
124         if (staticallyInitialized) {
125             if (santuarioProviderAdded) {
126                 Security.removeProvider("ApacheXMLDSig");
127                 santuarioProviderAdded = false;
128             }
129             if (bcProviderAdded) {
130                 Security.removeProvider("BC");
131                 bcProviderAdded = false;
132             }
133             if (tlProviderAdded) {
134                 Security.removeProvider("TLSP");
135                 tlProviderAdded = false;
136             }
137 
138             staticallyInitialized = false;
139         }
140     }
141 
142     /**
143      * Set the value of the internal addJceProviders flag.  This flag
144      * turns on (or off) automatic registration of known JCE providers
145      * that provide necessary cryptographic algorithms for use with WSS4J.
146      * By default, this flag is true.  You may wish (or need) to initialize
147      * the JCE manually, e.g., in some JVMs.
148      */
149     public static void setAddJceProviders(boolean value) {
150         addJceProviders = value;
151     }
152 
153     public static void setXmlSecIgnoreLineBreak() {
154         //really need to make sure ignoreLineBreaks is set to
155         boolean wasSet = false;
156         try {
157             // Don't override if it was set explicitly
158             wasSet = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
159                 public Boolean run() {
160                     String lineBreakPropName = "org.apache.xml.security.ignoreLineBreaks";
161                     if (System.getProperty(lineBreakPropName) == null) {
162                         System.setProperty(lineBreakPropName, "true");
163                         return false;
164                     }
165                     return true;
166                 }
167             });
168         } catch (Throwable t) { //NOPMD
169             //ignore
170         }
171         org.apache.xml.security.Init.init();
172         if (!wasSet) {
173             try {
174                 AccessController.doPrivileged(new PrivilegedExceptionAction<Boolean>() {
175                     public Boolean run() throws Exception {
176                         Field f = XMLUtils.class.getDeclaredField("ignoreLineBreaks");
177                         f.setAccessible(true);  //NOPMD
178                         f.set(null, Boolean.TRUE);
179                         return false;
180                     }
181                 });
182             } catch (Throwable t) { //NOPMD
183                 //ignore
184             }
185         }
186     }
187 
188     private static void addXMLDSigRIInternal() {
189         Security.removeProvider("ApacheXMLDSig");
190         addJceProvider("ApacheXMLDSig", SantuarioUtil.getSantuarioProvider());
191     }
192 
193     private static void initializeResourceBundles() {
194         I18n.init(new WSS4JResourceBundle());
195     }
196 
197     /**
198      * Add a new JCE security provider to use for WSS4J, of the specified name and class. Return
199      * either the name of the previously loaded provider, the name of the new loaded provider, or
200      * null if there's an exception in loading the provider. Add the provider either after the SUN
201      * provider (see WSS-99), or the IBMJCE provider. Otherwise fall back to the old behaviour of
202      * inserting the provider in position 2.
203      *
204      * @param name
205      *            The name string of the provider (this may not be the real name of the provider)
206      * @param className
207      *            Name of the class the implements the provider. This class must
208      *            be a subclass of <code>java.security.Provider</code>
209      *
210      * @return Returns the actual name of the provider that was loaded
211      */
212     public static String addJceProvider(String name, String className) {
213         Provider currentProvider = Security.getProvider(name);
214         if (currentProvider == null) {
215             try {
216                 Class<? extends Provider> clazz = Loader.loadClass(className, false, Provider.class);
217                 Provider provider = clazz.getDeclaredConstructor().newInstance();
218                 return addJceProvider(name, provider);
219             } catch (Throwable t) {
220                 if (LOG.isDebugEnabled()) {
221                     LOG.debug("The provider " + name + " could not be added: " + t.getMessage(), t);
222                 }
223                 return null;
224             }
225         }
226         return currentProvider.getName();
227     }
228 
229     /**
230      * Add a new JCE security provider to use for WSS4J, of the specified name and class. Return
231      * either the name of the previously loaded provider, the name of the new loaded provider, or
232      * null if there's an exception in loading the provider. Add the provider either after the SUN
233      * provider (see WSS-99), or the IBMJCE provider. Otherwise fall back to the old behaviour of
234      * inserting the provider in position 2.
235      *
236      * @param name
237      *            The name string of the provider (this may not be the real name of the provider)
238      * @param provider
239      *            A subclass of <code>java.security.Provider</code>
240      *
241      * @return Returns the actual name of the provider that was loaded
242      */
243     public static String addJceProvider(String name, Provider provider) {
244         Provider currentProvider = Security.getProvider(name);
245         if (currentProvider == null) {
246             try {
247                 int ret = Security.addProvider(provider);
248                 if (LOG.isDebugEnabled()) {
249                     LOG.debug(
250                         "The provider " + provider.getName() + " - "
251                          + provider.getVersionStr() + " was added at position: " + ret
252                     );
253                 }
254                 return provider.getName();
255             } catch (Throwable t) {
256                 if (LOG.isDebugEnabled()) {
257                     LOG.debug("The provider " + name + " could not be added: " + t.getMessage(), t);
258                 }
259                 return null;
260             }
261         }
262         return currentProvider.getName();
263     }
264 
265 
266     /**
267      * Add a new JCE security provider to use for WSS4J, of the specified name and class. Return
268      * either the name of the previously loaded provider, the name of the new loaded provider, or
269      * null if there's an exception in loading the provider. Append the provider to the provider
270      * list.
271      *
272      * @param name
273      *            The name string of the provider (this may not be the real name of the provider)
274      * @param className
275      *            Name of the class the implements the provider. This class must
276      *            be a subclass of <code>java.security.Provider</code>
277      *
278      * @return Returns the actual name of the provider that was loaded
279      */
280     public static String appendJceProvider(String name, String className) {
281         Provider currentProvider = Security.getProvider(name);
282         if (currentProvider == null) {
283             try {
284                 Class<? extends Provider> clazz = Loader.loadClass(className, false, Provider.class);
285                 Provider provider = clazz.getDeclaredConstructor().newInstance();
286 
287                 int ret = Security.addProvider(provider);
288                 LOG.debug(
289                     "The provider {} was added at position: {}",
290                      provider.getName(), ret
291                 );
292                 return provider.getName();
293             } catch (Throwable t) {
294                 if (LOG.isDebugEnabled()) {
295                     LOG.debug("The provider " + name + " could not be added: " + t.getMessage(), t);
296                 }
297                 return null;
298             }
299         }
300         return currentProvider.getName();
301     }
302 
303     /**
304      * Add a new JCE security provider to use for WSS4J, of the specified name and class. Return
305      * either the name of the previously loaded provider, the name of the new loaded provider, or
306      * null if there's an exception in loading the provider. Append the provider to the provider
307      * list.
308      *
309      * @param name
310      *            The name string of the provider (this may not be the real name of the provider)
311      * @param provider
312      *            A subclass of <code>java.security.Provider</code>
313      *
314      * @return Returns the actual name of the provider that was loaded
315      */
316     public static String appendJceProvider(String name, Provider provider) {
317         Provider currentProvider = Security.getProvider(name);
318         if (currentProvider == null) {
319             try {
320                 int ret = Security.addProvider(provider);
321                 LOG.debug(
322                     "The provider {} was added at position: {}",
323                      provider.getName(), ret
324                 );
325                 return provider.getName();
326             } catch (Throwable t) {
327                 if (LOG.isDebugEnabled()) {
328                     LOG.debug("The provider " + name + " could not be added: " + t.getMessage(), t);
329                 }
330                 return null;
331             }
332         }
333         return currentProvider.getName();
334     }
335 
336 }