/** * Licensed to Jasig under one or more contributor license * agreements. See the NOTICE file distributed with this work * for additional information regarding copyright ownership. * Jasig 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 edu.wisc.bnsemail.dao; import java.io.InputStream; import java.security.KeyStore; import java.security.PrivateKey; import java.security.Security; import java.security.cert.CertStore; import java.security.cert.Certificate; import java.security.cert.CollectionCertStoreParameters; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import javax.mail.Address; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeBodyPart; import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMessage.RecipientType; import javax.mail.internet.MimeMultipart; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.mail.smime.SMIMESignedGenerator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.io.Resource; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.stereotype.Service; import edu.wisc.hr.dao.bnsemail.BusinessEmailUpdateNotifier; /** * * @author Eric Dalquist * @version $Revision: 1.1 $ */ @Service("businessEmailUpdateNotifier") public class SmtpBusinessEmailUpdateNotifier implements InitializingBean, BusinessEmailUpdateNotifier { protected final Logger logger = LoggerFactory.getLogger(getClass()); private SMIMESignedGenerator smimeSignedGenerator; private JavaMailSender javaMailSender; private Resource keystore; private String keystorePassword; private String certificateAlias; public void setKeystore(Resource keystore) { this.keystore = keystore; } public void setKeystorePassword(String keystorePassword) { this.keystorePassword = keystorePassword; } public void setCertificateAlias(String certificateAlias) { this.certificateAlias = certificateAlias; } @Autowired public void setJavaMailSender(JavaMailSender javaMailSender) { this.javaMailSender = javaMailSender; } @Override public void afterPropertiesSet() throws Exception { if (this.keystore == null) { this.logger.warn("No S/MIME KeyStore configured. Email update notifications will NOT be signed"); } else { Security.addProvider(new BouncyCastleProvider()); final KeyStore signingKeyStore = KeyStore.getInstance("JKS"); final InputStream keyStoreStream = this.keystore.getInputStream(); try { signingKeyStore.load(keyStoreStream, this.keystorePassword.toCharArray()); } finally { IOUtils.closeQuietly(keyStoreStream); } final List<Certificate> certList = new ArrayList<Certificate>(1); for (final Enumeration<String> aliasesEnum = signingKeyStore.aliases(); aliasesEnum.hasMoreElements();) { final String alias = aliasesEnum.nextElement(); final Certificate cert = signingKeyStore.getCertificate(alias); if (cert != null) { certList.add(cert); } } final PrivateKey signingKey = (PrivateKey) signingKeyStore.getKey(this.certificateAlias, this.keystorePassword.toCharArray()); final X509Certificate signingCert = (X509Certificate) signingKeyStore.getCertificate(this.certificateAlias); // create a CertStore containing the certificates we want carried // in the signature final CertStore certsAndcrls = CertStore.getInstance("Collection", new CollectionCertStoreParameters(certList), "BC"); // create the generator for creating an smime/signed message smimeSignedGenerator = new SMIMESignedGenerator(); // add a signer to the generator - this specifies we are using SHA1 and // adding the smime attributes above to the signed attributes that // will be generated as part of the signature. The encryption algorithm // used is taken from the key - in this RSA with PKCS1Padding smimeSignedGenerator.addSigner(signingKey, signingCert, SMIMESignedGenerator.DIGEST_SHA1); // add our pool of certs and cerls (if any) to go with the signature smimeSignedGenerator.addCertificatesAndCRLs(certsAndcrls); } } /* (non-Javadoc) * @see edu.wisc.bnsemail.dao.BusinessEmailUpdateNotifier#notifyEmailUpdated(java.lang.String, java.lang.String) */ @Override public void notifyEmailUpdated(String oldAddress, String newAddress) { try { //Create the message body final MimeBodyPart msg = new MimeBodyPart(); msg.setContent( "Your Business Email Address has changed\n" + "\n" + "Old Email Address: " + oldAddress + "\n" + "New Email Address: " + newAddress + "\n" + "\n" + "If you have any questions, please contact your Human Resources department.", "text/plain"); final MimeMessage message = this.javaMailSender.createMimeMessage(); final Address[] recipients; if (StringUtils.isNotEmpty(oldAddress)) { recipients = new Address[] { new InternetAddress(oldAddress), new InternetAddress(newAddress) }; } else { recipients = new Address[] { new InternetAddress(newAddress) }; } message.setRecipients(RecipientType.TO, recipients); message.setFrom(new InternetAddress("payroll@ohr.wisc.edu")); message.setSubject("Business Email Address Change"); // sign the message body if (this.smimeSignedGenerator != null) { final MimeMultipart mm = this.smimeSignedGenerator.generate(msg, "BC"); message.setContent(mm, mm.getContentType()); } // no signing keystore configured, send the message unsigned else { message.setContent(msg.getContent(), msg.getContentType()); } message.saveChanges(); this.javaMailSender.send(message); this.logger.info("Sent notification of email address change from {} to {}", oldAddress, newAddress); } catch (Exception e) { this.logger.error("Failed to send notification email for change from " + oldAddress + " to " + newAddress , e); } } }