Java tutorial
/* Copyright (C) 2008 Flix Garca Borrego (borrego at gmail.com) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ package org.viafirma.util; import java.security.InvalidAlgorithmParameterException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.PrivateKey; import java.security.cert.CertStore; import java.security.cert.CertStoreException; import java.security.cert.Certificate; import java.security.cert.CertificateParsingException; import java.security.cert.CollectionCertStoreParameters; import java.security.cert.X509Certificate; import java.util.List; import java.util.Properties; import javax.mail.Authenticator; import javax.mail.MessagingException; import javax.mail.PasswordAuthentication; import javax.mail.internet.MimeBodyPart; import javax.mail.internet.MimeMultipart; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.commons.mail.Email; import org.apache.commons.mail.EmailException; import org.apache.commons.mail.MultiPartEmail; import org.bouncycastle.asn1.ASN1EncodableVector; import org.bouncycastle.asn1.cms.AttributeTable; import org.bouncycastle.asn1.smime.SMIMECapabilitiesAttribute; import org.bouncycastle.asn1.smime.SMIMECapability; import org.bouncycastle.asn1.smime.SMIMECapabilityVector; import org.bouncycastle.asn1.smime.SMIMEEncryptionKeyPreferenceAttribute; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.mail.smime.SMIMEException; import org.bouncycastle.mail.smime.SMIMESignedGenerator; import org.bouncycastle.mail.smime.SMIMEUtil; import org.viafirma.excepciones.CodigoError; import org.viafirma.excepciones.ExcepcionCertificadoNoEncontrado; import org.viafirma.excepciones.ExcepcionErrorInterno; import org.viafirma.nucleo.X509.CertificadoGenericoFactory; import org.viafirma.nucleo.validacion.KeyStoreLoader; import org.viafirma.vo.CertificadoGenerico; import com.viavansi.framework.core.util.CadenaUtilities; /** * Mtodos de utiliza para el envo de emails. * @author Felix Garcia Borrego (borrego at gmail.com) */ public class SendMailUtil { private final Log log = LogFactory.getFactory().getInstance(SendMailUtil.class); /** * Host utilizado para el envio de SMTP */ private String smtpHost; /** * Usuario (opcional) para la conexin smtp. */ private String smtpUser; /** * Usuario (opcional) para la conexin smtp. */ private String smtpPass; // Se cogen de configuracin private static SendMailUtil emailUtilitiesSingleton = null; /** * Devuelve una instancia configurada de email util debe ser creada y * configurada al arrancar la aplicacin * * @return */ public static SendMailUtil getCurrentInstance() { return emailUtilitiesSingleton; } /** * Crea una nueva instancia configurada para el envo de emails. * * @param configuracion */ private SendMailUtil(Properties configuracion) { // Host SMTP try { smtpHost = configuracion.getProperty("HOST_SMTP"); } catch (Exception e) { log.warn("No se ha podido recuperar el valor del host del SMTP: " + e.toString()); } // User SMTP try { smtpUser = configuracion.getProperty("SMTP_USER"); } catch (Exception e) { log.warn("No se ha podido recuperar el valor del usuario del SMTP: " + e.toString()); } // Pass SMTP try { smtpPass = configuracion.getProperty("SMTP_PASS"); } catch (Exception e) { log.warn("No se ha podido recuperar el valor de la pass del SMTP: " + e.toString()); } } /** * Crea un objeto para enviar emails utilizando un mapa de configuracin * Recupera de las propiedades: HOST_SMTP * FROM_ADDRESS * DESC_FROM_ADDRESS * REPLYTO_ADDRESS * * * @param box_configuracion */ public static void init(Properties configuracion) { emailUtilitiesSingleton = new SendMailUtil(configuracion); if (StringUtils.isEmpty(emailUtilitiesSingleton.smtpHost)) { emailUtilitiesSingleton.log .warn("No hay configuracin SMTP, los servicios de envio de email no estaran disponibles."); } else { emailUtilitiesSingleton.log.info("Mail Service: HOST_SMTP " + emailUtilitiesSingleton.smtpHost + " User SMTP_USER: " + emailUtilitiesSingleton.smtpUser + ", SMTP_PASS: " + CadenaUtilities.getCurrentInstance().generarAsteriscos(emailUtilitiesSingleton.smtpPass)); } } public MultiPartEmail buildMessage(String subject, String mailTo, String texto, String htmlTexto, String alias, String password) throws ExcepcionErrorInterno, ExcepcionCertificadoNoEncontrado { try { // 1.- Preparamos el certificado // Recuperamos la clave privada asociada al alias PrivateKey privateKey = KeyStoreLoader.getPrivateKey(alias, password); if (privateKey == null) { throw new ExcepcionCertificadoNoEncontrado( "No existe una clave privada para el alias '" + alias + "'"); } if (log.isDebugEnabled()) log.info("Firmando el documento con el certificado " + alias); // Recuperamos el camino de confianza asociado al certificado List<Certificate> chain = KeyStoreLoader.getCertificateChain(alias); // Obtenemos los datos del certificado utilizado. X509Certificate certificadoX509 = (X509Certificate) chain.get(0); CertificadoGenerico datosCertificado = CertificadoGenericoFactory.getInstance() .generar(certificadoX509); String emailFrom = datosCertificado.getEmail(); String emailFromDesc = datosCertificado.getCn(); if (StringUtils.isEmpty(emailFrom)) { log.warn("El certificado indicado no tiene un email asociado, No es vlido para firmar emails" + datosCertificado); throw new ExcepcionCertificadoNoEncontrado( "El certificado indicado no tiene un email asociado, No es vlido para firmar emails."); } CertStore certificadosYcrls = CertStore.getInstance("Collection", new CollectionCertStoreParameters(chain), BouncyCastleProvider.PROVIDER_NAME); // 2.- Preparamos el mail MimeBodyPart bodyPart = new MimeBodyPart(); MimeMultipart dataMultiPart = new MimeMultipart(); MimeBodyPart msgHtml = new MimeBodyPart(); if (StringUtils.isNotEmpty(htmlTexto)) { msgHtml.setContent(htmlTexto, Email.TEXT_HTML + "; charset=UTF-8"); } else { msgHtml.setContent("<p>" + htmlTexto + "</p>", Email.TEXT_PLAIN + "; charset=UTF-8"); } // create the message we want signed MimeBodyPart mensajeTexto = new MimeBodyPart(); if (StringUtils.isNotEmpty(texto)) { mensajeTexto.setText(texto, "UTF-8"); } else if (StringUtils.isEmpty(texto)) { mensajeTexto.setText(CadenaUtilities.cleanHtml(htmlTexto), "UTF-8"); } dataMultiPart.addBodyPart(mensajeTexto); dataMultiPart.addBodyPart(msgHtml); bodyPart.setContent(dataMultiPart); // Crea el nuevo mensaje firmado MimeMultipart multiPart = createMultipartWithSignature(privateKey, certificadoX509, certificadosYcrls, bodyPart); // Creamos el mensaje que finalmente sera enviadio. MultiPartEmail mail = createMultiPartEmail(subject, mailTo, emailFrom, emailFromDesc, multiPart, multiPart.getContentType()); return mail; } catch (InvalidAlgorithmParameterException e) { throw new ExcepcionErrorInterno(CodigoError.ERROR_INTERNO, e); } catch (NoSuchAlgorithmException e) { throw new ExcepcionErrorInterno(CodigoError.ERROR_INTERNO, e); } catch (NoSuchProviderException e) { throw new ExcepcionErrorInterno(CodigoError.ERROR_INTERNO, e); } catch (MessagingException e) { throw new ExcepcionErrorInterno(CodigoError.ERROR_INTERNO, e); } catch (CertificateParsingException e) { throw new ExcepcionErrorInterno(CodigoError.ERROR_INTERNO, e); } catch (CertStoreException e) { throw new ExcepcionErrorInterno(CodigoError.ERROR_INTERNO, e); } catch (SMIMEException e) { throw new ExcepcionErrorInterno(CodigoError.ERROR_INTERNO, e); } catch (EmailException e) { throw new ExcepcionErrorInterno(CodigoError.ERROR_INTERNO, e); } } /** * Crea el MIME mensaje aadiendo su contenido, y su destinatario. * @param contentType * * @throws EmailException */ private MultiPartEmail createMultiPartEmail(String subject, String toUser, String fromAddres, String fromAddresDescription, MimeMultipart aMimeMultipart, String contentType) throws MessagingException, EmailException { MultiPartEmail email = new MultiPartEmail(); email.setContent(aMimeMultipart); email.setHostName(smtpHost); email.addTo(toUser); email.setFrom(fromAddres, fromAddresDescription); email.setSubject(subject); // Si el smtp tiene usuario y pass nos logamos if (StringUtils.isNotEmpty(smtpUser) && StringUtils.isNotEmpty(smtpPass)) { Authenticator auth = new Authenticator() { @Override protected javax.mail.PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(smtpUser, smtpPass); } }; log.info("Para mandar el correo nos autenticamos en el SMTP " + smtpHost + " con user " + smtpUser + " y pass " + CadenaUtilities.getCurrentInstance().generarAsteriscos(smtpPass)); email.setAuthenticator(auth); } // email.setDebug(false); email.buildMimeMessage(); return email; } /** * Crea un nuevo mail firmado. Adjuntandole el pkcs7. * * @param key * Clave privada con la que se realiza el proceso de firma. * @param cert * Certificado utilizado. * @param certsAndCRLs * Camino de confianza. * @param dataPart * Cuerpo del email. * @return Mail firmado. * @throws CertStoreException * @throws SMIMEException * @throws NoSuchAlgorithmException * @throws NoSuchProviderException * @throws CertificateParsingException */ private MimeMultipart createMultipartWithSignature(PrivateKey key, X509Certificate cert, CertStore certsAndCRLs, MimeBodyPart dataPart) throws CertStoreException, SMIMEException, NoSuchAlgorithmException, NoSuchProviderException, CertificateParsingException { // Aadimos los tipos soportados ASN1EncodableVector signedAttrs = new ASN1EncodableVector(); SMIMECapabilityVector caps = new SMIMECapabilityVector(); caps.addCapability(SMIMECapability.aES256_CBC); caps.addCapability(SMIMECapability.dES_EDE3_CBC); caps.addCapability(SMIMECapability.rC2_CBC, 128); signedAttrs.add(new SMIMECapabilitiesAttribute(caps)); signedAttrs.add(new SMIMEEncryptionKeyPreferenceAttribute(SMIMEUtil.createIssuerAndSerialNumberFor(cert))); // Creamos el generador SMIMESignedGenerator generador = new SMIMESignedGenerator(); // Establecemos la clave privada y el mtodo de firma generador.addSigner(key, cert, SMIMESignedGenerator.DIGEST_SHA1, new AttributeTable(signedAttrs), null); // Aadimos el camino de confianza adjuntado en el mail. generador.addCertificatesAndCRLs(certsAndCRLs); // Generamos el mail firmado. MimeMultipart mensajeFirmado = generador.generate(dataPart, BouncyCastleProvider.PROVIDER_NAME); // multipart/mixed; boundary="----=_Part_2_29796765.1208556677256" try { String contentType = mensajeFirmado.getBodyPart(0).getContentType(); contentType = contentType.replaceAll("multipart/mixed", "multipart/alternative"); mensajeFirmado.getBodyPart(0).setHeader("Content-Type", contentType); // contentType =mensajeFirmado.getContentType(); // contentType=contentType.replaceAll("application/pkcs7-signature", // "application/x-pkcs7-signature"); // mensajeFirmado.getContentType(); } catch (MessagingException e) { // TODO Auto-generated catch block e.printStackTrace(); } return mensajeFirmado; } }