/*
* gvNIX is an open source tool for rapid application development (RAD).
* Copyright (C) 2010 Generalitat Valenciana
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.gvnix.service.roo.addon.addon.security;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.logging.Logger;
import javax.net.ssl.X509TrustManager;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.Validate;
import org.springframework.roo.process.manager.FileManager;
import org.springframework.roo.project.LogicalPath;
import org.springframework.roo.project.Path;
import org.springframework.roo.project.PathResolver;
/**
* Implementation of X509TrustManager in order to deal with SSL connection
* against secure servers that uses certificates not included in the JVM
* keystore (Usually in $JAVA_HOME/jre/lib/security/cacerts)
*
* @author <a href="http://www.disid.com">DISID Corporation S.L.</a> made for <a
* href="http://www.dgti.gva.es">General Directorate for Information
* Technologies (DGTI)</a>
*/
public class GvNix509TrustManager implements X509TrustManager {
private static Logger logger = Logger.getLogger(GvNix509TrustManager.class
.getName());
private final X509TrustManager tm;
private X509Certificate[] chain;
GvNix509TrustManager(X509TrustManager tm) {
this.tm = tm;
}
public X509Certificate[] getAcceptedIssuers() {
throw new UnsupportedOperationException();
}
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
throw new UnsupportedOperationException();
}
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
this.chain = chain;
tm.checkServerTrusted(chain, authType);
}
/**
* Import certs in this.chain to the keystore given by the file passed.
*
* @param host
* @param keystore
* @param pass
* @return
* @throws Exception
*/
public X509Certificate[] addCerts(String host, File keystore, char[] pass)
throws Exception {
// Specific Exceptions thrown in this code: NoSuchAlgorithmException,
// KeyStoreException, CertificateException, IOException
X509Certificate[] chain = this.chain;
if (chain == null) {
return null;
}
KeyStore ks = loadKeyStore(keystore, pass);
String alias = host;
for (int i = 0; i < chain.length; i++) {
X509Certificate cert = chain[i];
alias = alias.concat("-" + (i + 1));
ks.setCertificateEntry(alias, cert);
alias = host;
}
if (keystore.canWrite()) {
OutputStream out = null;
try {
out = new FileOutputStream(keystore);
ks.store(out, pass);
}
finally {
IOUtils.closeQuietly(out);
}
}
else {
throw new Exception(
keystore.getAbsolutePath()
.concat(" is not writable. ")
.concat("You should to import needed certificates in your")
.concat(" JVM trustcacerts keystore.\n")
.concat("You have them in src/main/resources/*.cer.\n")
.concat("Use keytool for that: ")
.concat("http://download.oracle.com/javase/6/docs/technotes/tools/solaris/keytool.html"));
}
return chain;
}
/**
* Export the given certificate to a file in SRC_MAIN_RESOURCES. The cert
* file will have given <code>{alias}.cer</code> as file name.
* <p>
* <b>We don't use Roo FileManager API</b> here in order to create cert
* files because in this way if we have any problem importing them to the
* JVM <code>cacerts</cacerts> Roo won't undo the cert files creation.
* </p>
*
* @param alias
* @param cert
* @param fileManager
* @param pathResolver
* @throws Exception
*/
public static void saveCertFile(String alias, X509Certificate cert,
FileManager fileManager, PathResolver pathResolver)
throws Exception {
String aliasCerFileName = alias.concat(".cer");
String cerFilePath = pathResolver.getIdentifier(
LogicalPath.getInstance(Path.SRC_MAIN_RESOURCES, ""),
aliasCerFileName);
if (!fileManager.exists(cerFilePath)) {
File cerFile = new File(cerFilePath);
OutputStream os = null;
try {
os = new FileOutputStream(cerFile);
os.write(cert.getEncoded());
}
finally {
IOUtils.closeQuietly(os);
}
logger.info("Created ".concat(Path.SRC_MAIN_RESOURCES.name())
.concat("/").concat(aliasCerFileName));
}
}
/**
* Loads keystore in the given file using passphrase as keystore password.
*
* @param keystore
* @param pass
* @return
* @throws Exception will be a IOExecption if the given password is a wrong
* one
*/
public static KeyStore loadKeyStore(File keystore, char[] pass)
throws Exception {
Validate.notNull(keystore, "keystore must be a vaild keystore file");
InputStream in = new FileInputStream(keystore);
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(in, pass);
in.close();
return ks;
}
}