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.components.crypto;
21  
22  import org.apache.ws.security.WSSecurityException;
23  import org.apache.ws.security.util.Loader;
24  
25  import java.io.IOException;
26  import java.lang.reflect.Constructor;
27  import java.net.URL;
28  import java.util.Map;
29  import java.util.Properties;
30  
31  /**
32   * CryptoFactory.
33   * <p/>
34   *
35   * @author Davanum Srinivas (dims@yahoo.com).
36   */
37  public abstract class CryptoFactory {
38      private static final org.apache.commons.logging.Log LOG = 
39          org.apache.commons.logging.LogFactory.getLog(CryptoFactory.class);
40  
41      /**
42       * getInstance
43       * <p/>
44       * Returns an instance of Crypto. This method uses the file
45       * <code>crypto.properties</code> to determine which implementation to
46       * use. Thus the property <code>org.apache.ws.security.crypto.provider</code>
47       * must define the classname of the Crypto implementation. The file
48       * may contain other property definitions as well. These properties are
49       * handed over to the Crypto implementation. The file
50       * <code>crypto.properties</code> is loaded with the
51       * <code>Loader.getResource()</code> method.
52       * <p/>
53       *
54       * @return The crypto implementation was defined
55       * @throws WSSecurityException if there is an error in loading the crypto properties
56       */
57      public static Crypto getInstance() throws WSSecurityException {
58          return getInstance("crypto.properties");
59      }
60  
61      /**
62       * getInstance
63       * <p/>
64       * Returns an instance of Crypto. The properties are handed over the the crypto
65       * implementation. The properties must at least contain the Crypto implementation
66       * class name as the value of the property : org.apache.ws.security.crypto.provider
67       * <p/>
68       *
69       * @param properties      The Properties that are forwarded to the crypto implementation 
70       *                        and the Crypto impl class name.
71       *                        These properties are dependent on the crypto implementation
72       * @return The cyrpto implementation or null if no cryptoClassName was defined
73       * @throws WSSecurityException if there is an error in loading the crypto properties
74       */
75      public static Crypto getInstance(Properties properties) throws WSSecurityException {
76          if (properties == null) {
77              if (LOG.isDebugEnabled()) {
78                  LOG.debug("Cannot load Crypto instance as properties object is null");
79              }
80              throw new WSSecurityException("Cannot load Crypto instance as properties object is null");
81          }
82          return getInstance(properties, Loader.getClassLoader(CryptoFactory.class));
83      }
84  
85      /**
86       * getInstance
87       * <p/>
88       * Returns an instance of Crypto loaded with the given classloader. 
89       * The properties are handed over the the crypto implementation. 
90       * The properties must at least contain the Crypto implementation
91       * class name as the value of the property : org.apache.ws.security.crypto.provider
92       * <p/>
93       *
94       * @param properties      The Properties that are forwarded to the crypto implementation 
95       *                        and the Crypto impl class name.
96       *                        These properties are dependent on the crypto implementation
97       * @param classLoader   The class loader to use
98       * @return The crypto implementation or null if no cryptoClassName was defined
99       * @throws WSSecurityException if there is an error in loading the crypto properties
100      */
101     public static Crypto getInstance(
102         Properties properties, 
103         ClassLoader classLoader
104     ) throws WSSecurityException {
105         if (properties == null) {
106             if (LOG.isDebugEnabled()) {
107                 LOG.debug("Cannot load Crypto instance as properties object is null");
108             }
109             throw new WSSecurityException("Cannot load Crypto instance as properties object is null");
110         }
111         
112         String cryptoClassName = properties.getProperty("org.apache.ws.security.crypto.provider");
113         Class<? extends Crypto> cryptoClass = null;
114         if (cryptoClassName == null 
115             || cryptoClassName.equals("org.apache.ws.security.components.crypto.Merlin")) {
116             try {
117                 return new Merlin(properties, classLoader);
118             } catch (java.lang.Exception e) {
119                 if (LOG.isDebugEnabled()) {
120                     LOG.debug("Unable to instantiate Merlin", e);
121                 }
122                 throw new WSSecurityException(cryptoClass + " cannot create instance", e);
123             }
124         } else {
125             try {
126                 // instruct the class loader to load the crypto implementation
127                 cryptoClass = Loader.loadClass(cryptoClassName, Crypto.class);
128             } catch (ClassNotFoundException ex) {
129                 if (LOG.isDebugEnabled()) {
130                     LOG.debug(ex.getMessage(), ex);
131                 }
132                 throw new WSSecurityException(cryptoClassName + " Not Found", ex);
133             }
134         }
135         return loadClass(cryptoClass, properties, classLoader);
136     }
137     
138     /**
139      * getInstance
140      * <p/>
141      * Returns an instance of Crypto. The supplied map is handed over the the crypto
142      * implementation. The map can be <code>null</code>. It is dependent on the
143      * Crypto implementation how the initialization is done in this case.
144      * <p/>
145      *
146      * @param cryptoClass     This is the crypto implementation class. No default is
147      *                        provided here.
148      * @param map             The Maps that is forwarded to the crypto implementation.
149      *                        These contents of the map are dependent on the 
150      *                        underlying crypto implementation specified in the 
151      *                        cryptoClassName parameter.
152      * @return The crypto implementation or null if no cryptoClassName was defined
153      * @throws WSSecurityException if there is an error in loading the crypto properties
154      */
155     public static Crypto getInstance(
156         Class<? extends Crypto> cryptoClass, 
157         Map<Object, Object> map
158     ) throws WSSecurityException {
159         return loadClass(cryptoClass, map, Loader.getClassLoader(CryptoFactory.class));
160     }
161 
162     /**
163      * getInstance
164      * <p/>
165      * Returns an instance of Crypto. This method uses the specified filename
166      * to load a property file. This file shall use the property
167      * <code>org.apache.ws.security.crypto.provider</code>
168      * to define the classname of the Crypto implementation. The file
169      * may contain other property definitions as well. These properties are
170      * handed over to the Crypto implementation. The specified file
171      * is loaded with the <code>Loader.getResource()</code> method.
172      * <p/>
173      *
174      * @param propFilename The name of the property file to load
175      * @return The crypto implementation that was defined
176      * @throws WSSecurityException if there is an error in loading the crypto properties
177      */
178     public static Crypto getInstance(String propFilename) throws WSSecurityException {
179         return getInstance(propFilename, Loader.getClassLoader(CryptoFactory.class));
180     }    
181     
182     public static Crypto getInstance(
183         String propFilename, 
184         ClassLoader customClassLoader
185     ) throws WSSecurityException {
186         Properties properties = getProperties(propFilename, customClassLoader);
187         return getInstance(properties, customClassLoader);
188     }
189 
190     /**
191      * This allows loading the classes with a custom class loader  
192      * @param cryptoClass
193      * @param properties
194      * @param loader
195      * @return
196      * @throws WSSecurityException if there is an error in loading the crypto properties
197      */
198     private static Crypto loadClass(
199         Class<? extends Crypto> cryptoClass,
200         Map<Object, Object> map, 
201         ClassLoader loader
202     ) throws WSSecurityException {
203         if (LOG.isDebugEnabled()) {
204             LOG.debug("Using Crypto Engine [" + cryptoClass + "]");
205         }
206         try {
207             Class<?>[] classes = new Class[]{Map.class, ClassLoader.class};
208             Constructor<? extends Crypto> c = cryptoClass.getConstructor(classes);
209             return c.newInstance(new Object[] {map, loader});
210         } catch (java.lang.Exception e) {
211             if (LOG.isDebugEnabled()) {
212                 LOG.debug("Unable to instantiate: " + cryptoClass.getName(), e);
213             }
214             throw new WSSecurityException(cryptoClass + " cannot create instance", e);
215         }
216     }
217     
218     /**
219      * This allows loading the classes with a custom class loader  
220      * @param cryptoClass
221      * @param properties
222      * @param loader
223      * @return
224      * @throws WSSecurityException if there is an error in loading the crypto properties
225      */
226     private static Crypto loadClass(
227         Class<? extends Crypto> cryptoClass, 
228         Properties map, 
229         ClassLoader loader
230     ) throws WSSecurityException {
231         if (LOG.isDebugEnabled()) {
232             LOG.debug("Using Crypto Engine [" + cryptoClass + "]");
233         }
234         try {
235             Class<?>[] classes = new Class[]{Properties.class, ClassLoader.class};
236             Constructor<? extends Crypto> c = cryptoClass.getConstructor(classes);
237             return c.newInstance(new Object[] {map, loader});
238         } catch (java.lang.Exception e) {
239             if (LOG.isDebugEnabled()) {
240                 LOG.debug("Unable to instantiate: " + cryptoClass.getName(), e);
241             }
242             throw new WSSecurityException(cryptoClass + " cannot create instance", e);
243         }
244     }
245     
246     /**
247      * This allows loading the resources with a custom class loader
248      * @param propFilename
249      * @param loader
250      * @return
251      * @throws WSSecurityException if there is an error in loading the crypto properties
252      */
253     private static Properties getProperties(
254         String propFilename, 
255         ClassLoader loader
256     ) throws WSSecurityException {
257         Properties properties = new Properties();
258         try {
259             URL url = Loader.getResource(loader, propFilename);
260             if (url == null) {
261                 throw new WSSecurityException(
262                     WSSecurityException.FAILURE, 
263                     "resourceNotFound",
264                     new Object[]{propFilename}
265                 );
266             }
267             properties.load(url.openStream());
268         } catch (IOException e) {
269             if (LOG.isDebugEnabled()) {
270                 LOG.debug("Cannot find resource: " + propFilename, e);
271             }
272             throw new WSSecurityException(
273                 WSSecurityException.FAILURE, 
274                 "resourceNotFound",
275                 new Object[]{propFilename},
276                 e
277             );
278         }
279         return properties;
280     }
281 
282 }
283