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