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