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