blob: 91eb6b070bd191488750d669b8d2ef137368f2a9 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.wss4j.common.crypto;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.util.Map;
import java.util.Properties;
import org.apache.wss4j.common.ext.WSSecurityException;
import org.apache.wss4j.common.util.Loader;
/**
* CryptoFactory.
*/
public abstract class CryptoFactory {
private static final org.slf4j.Logger LOG =
org.slf4j.LoggerFactory.getLogger(CryptoFactory.class);
/**
* getInstance
* <p/>
* Returns an instance of Crypto. This method uses the file
* <code>crypto.properties</code> to determine which implementation to
* use. Thus the property <code>org.apache.wss4j.crypto.provider</code>
* must define the classname of the Crypto implementation. The file
* may contain other property definitions as well. These properties are
* handed over to the Crypto implementation. The file
* <code>crypto.properties</code> is loaded with the
* <code>Loader.getResource()</code> method.
* <p/>
*
* @return The crypto implementation was defined
* @throws WSSecurityException if there is an error in loading the crypto properties
*/
public static Crypto getInstance() throws WSSecurityException {
return getInstance("crypto.properties");
}
/**
* getInstance
* <p/>
* Returns an instance of Crypto. The properties are handed over the the crypto
* implementation. The properties must at least contain the Crypto implementation
* class name as the value of the property : org.apache.wss4j.crypto.provider
* <p/>
*
* @param properties The Properties that are forwarded to the crypto implementation
* and the Crypto impl class name.
* These properties are dependent on the crypto implementation
* @return The cyrpto implementation or null if no cryptoClassName was defined
* @throws WSSecurityException if there is an error in loading the crypto properties
*/
public static Crypto getInstance(Properties properties) throws WSSecurityException {
if (properties == null) {
LOG.debug("Cannot load Crypto instance as properties object is null");
throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE,
"empty", new Object[] {"Cannot load Crypto instance as properties object is null"});
}
return getInstance(properties, Loader.getClassLoader(CryptoFactory.class), null);
}
/**
* getInstance
* <p/>
* Returns an instance of Crypto loaded with the given classloader.
* The properties are handed over the the crypto implementation.
* The properties must at least contain the Crypto implementation
* class name as the value of the property : org.apache.wss4j.crypto.provider
* <p/>
*
* @param properties The Properties that are forwarded to the crypto implementation
* and the Crypto impl class name.
* These properties are dependent on the crypto implementation
* @param classLoader The class loader to use
* @param passwordEncryptor The PasswordEncryptor to use to decrypt encrypted passwords
* @return The crypto implementation or null if no cryptoClassName was defined
* @throws WSSecurityException if there is an error in loading the crypto properties
*/
public static Crypto getInstance(
Properties properties,
ClassLoader classLoader,
PasswordEncryptor passwordEncryptor
) throws WSSecurityException {
if (properties == null) {
LOG.debug("Cannot load Crypto instance as properties object is null");
throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE,
"empty", new Object[] {"Cannot load Crypto instance as properties object is null"});
}
String cryptoClassName = properties.getProperty("org.apache.wss4j.crypto.provider");
if (cryptoClassName == null) {
cryptoClassName = properties.getProperty("org.apache.ws.security.crypto.provider");
}
Class<? extends Crypto> cryptoClass = null;
if (cryptoClassName == null
|| cryptoClassName.equals("org.apache.wss4j.common.crypto.Merlin")
|| cryptoClassName.equals("org.apache.ws.security.components.crypto.Merlin")) {
try {
return new Merlin(properties, classLoader, passwordEncryptor);
} catch (java.lang.Exception e) {
LOG.debug("Unable to instantiate Merlin", e);
throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, e, "empty",
new Object[] {"Cannot create Crypto class " + cryptoClassName});
}
} else {
try {
// instruct the class loader to load the crypto implementation
cryptoClass = Loader.loadClass(cryptoClassName, Crypto.class);
} catch (ClassNotFoundException ex) {
LOG.debug(ex.getMessage(), ex);
throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, ex,
"empty", new Object[] {cryptoClassName + " Not Found"});
}
}
return loadClass(cryptoClass, properties, classLoader);
}
/**
* getInstance
* <p/>
* Returns an instance of Crypto. The supplied map is handed over the the crypto
* implementation. The map can be <code>null</code>. It is dependent on the
* Crypto implementation how the initialization is done in this case.
* <p/>
*
* @param cryptoClass This is the crypto implementation class. No default is
* provided here.
* @param map The Maps that is forwarded to the crypto implementation.
* These contents of the map are dependent on the
* underlying crypto implementation specified in the
* cryptoClassName parameter.
* @return The crypto implementation or null if no cryptoClassName was defined
* @throws WSSecurityException if there is an error in loading the crypto properties
*/
public static Crypto getInstance(
Class<? extends Crypto> cryptoClass,
Map<Object, Object> map
) throws WSSecurityException {
return loadClass(cryptoClass, map, Loader.getClassLoader(CryptoFactory.class));
}
/**
* getInstance
* <p/>
* Returns an instance of Crypto. This method uses the specified filename
* to load a property file. This file shall use the property
* <code>org.apache.wss4j.crypto.provider</code>
* to define the classname of the Crypto implementation. The file
* may contain other property definitions as well. These properties are
* handed over to the Crypto implementation. The specified file
* is loaded with the <code>Loader.getResource()</code> method.
* <p/>
*
* @param propFilename The name of the property file to load
* @return The crypto implementation that was defined
* @throws WSSecurityException if there is an error in loading the crypto properties
*/
public static Crypto getInstance(String propFilename) throws WSSecurityException {
return getInstance(propFilename, Loader.getClassLoader(CryptoFactory.class));
}
public static Crypto getInstance(
String propFilename,
ClassLoader customClassLoader
) throws WSSecurityException {
Properties properties = getProperties(propFilename, customClassLoader);
return getInstance(properties, customClassLoader, null);
}
/**
* This allows loading the classes with a custom class loader
* @param cryptoClass
* @param map
* @param loader
* @throws WSSecurityException if there is an error in loading the crypto properties
*/
private static Crypto loadClass(
Class<? extends Crypto> cryptoClass,
Map<Object, Object> map,
ClassLoader loader
) throws WSSecurityException {
LOG.debug("Using Crypto Engine [{}]", cryptoClass);
try {
Constructor<? extends Crypto> c = null;
try {
Class<?>[] classes = new Class[]{Map.class, ClassLoader.class};
c = cryptoClass.getConstructor(classes);
return c.newInstance(map, loader);
} catch (NoSuchMethodException ex) {
Class<?>[] classes =
new Class[]{Properties.class, Map.class, PasswordEncryptor.class};
c = cryptoClass.getConstructor(classes);
return c.newInstance(map, loader, null);
}
} catch (java.lang.Exception e) {
if (LOG.isDebugEnabled()) {
LOG.debug("Unable to instantiate: " + cryptoClass.getName(), e);
}
throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, e,
"empty", new Object[] {cryptoClass + " cannot create instance"});
}
}
/**
* This allows loading the classes with a custom class loader
* @param cryptoClass
* @param map
* @param loader
* @throws WSSecurityException if there is an error in loading the crypto properties
*/
private static Crypto loadClass(
Class<? extends Crypto> cryptoClass,
Properties map,
ClassLoader loader
) throws WSSecurityException {
LOG.debug("Using Crypto Engine [{}]", cryptoClass);
try {
Constructor<? extends Crypto> c = null;
try {
Class<?>[] classes = new Class[]{Properties.class, ClassLoader.class};
c = cryptoClass.getConstructor(classes);
return c.newInstance(map, loader);
} catch (NoSuchMethodException ex) {
Class<?>[] classes =
new Class[]{Properties.class, ClassLoader.class, PasswordEncryptor.class};
c = cryptoClass.getConstructor(classes);
return c.newInstance(map, loader, null);
}
} catch (java.lang.Exception e) {
if (LOG.isDebugEnabled()) {
LOG.debug("Unable to instantiate: " + cryptoClass.getName(), e);
}
throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, e,
"empty", new Object[] {cryptoClass + " cannot create instance"});
}
}
/**
* This allows loading the resources with a custom class loader
* @param propFilename
* @param loader
* @return a Properties object loaded from the propFilename argument
* @throws WSSecurityException if there is an error in loading the crypto properties
*/
public static Properties getProperties(
String propFilename,
ClassLoader loader
) throws WSSecurityException {
Properties properties = new Properties();
try {
InputStream is = Loader.loadInputStream(loader, propFilename);
if (is == null) {
throw new WSSecurityException(
WSSecurityException.ErrorCode.FAILURE,
"resourceNotFound",
new Object[] {propFilename}
);
}
properties.load(is);
is.close();
} catch (IOException e) {
if (LOG.isDebugEnabled()) {
LOG.debug("Cannot find resource: " + propFilename, e);
}
throw new WSSecurityException(
WSSecurityException.ErrorCode.FAILURE, e,
"resourceNotFound", new Object[] {propFilename}
);
}
return properties;
}
}