org.viafirma.util.SendMailUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.viafirma.util.SendMailUtil.java

Source

/* 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;
    }
}