Package org.ejbca.core.model.services.workers

Source Code of org.ejbca.core.model.services.workers.CertificateExpirationNotifierWorker

/*************************************************************************
*                                                                       *
*  EJBCA: The OpenSource Certificate Authority                          *
*                                                                       *
*  This software is free software; you can redistribute it and/or       *
*  modify it under the terms of the GNU Lesser General Public           *
*  License as published by the Free Software Foundation; either         *
*  version 2.1 of the License, or any later version.                    *
*                                                                       *
*  See terms of license at gnu.org.                                     *
*                                                                       *
*************************************************************************/
package org.ejbca.core.model.services.workers;

import java.security.cert.Certificate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.ejbca.core.ejb.ca.caadmin.CAAdminSessionLocal;
import org.ejbca.core.ejb.ca.store.CertificateStoreSessionLocal;
import org.ejbca.core.ejb.ra.UserAdminSessionLocal;
import org.ejbca.core.model.InternalResources;
import org.ejbca.core.model.SecConst;
import org.ejbca.core.model.ca.caadmin.CAInfo;
import org.ejbca.core.model.log.Admin;
import org.ejbca.core.model.ra.UserDataVO;
import org.ejbca.core.model.ra.UserNotificationParamGen;
import org.ejbca.core.model.services.ServiceExecutionFailedException;
import org.ejbca.core.model.services.actions.MailActionInfo;

/**
* Makes queries about which certificates that is about to expire in a given
* number of days and creates an notification sent to either the end user or the
* administrator.
*
* @author Philip Vendil, Tomas Gustavsson
*
* @version: $Id: CertificateExpirationNotifierWorker.java 11283 2011-01-29 11:03:33Z anatom $
*/
public class CertificateExpirationNotifierWorker extends EmailSendingWorker {

    private static final Logger log = Logger.getLogger(CertificateExpirationNotifierWorker.class);
    /** Internal localization of logs and errors */
    private static final InternalResources intres = InternalResources.getInstance();
   
    private CertificateStoreSessionLocal certificateStoreSession;

    /**
     * Worker that makes a query to the Certificate Store about expiring
     * certificates.
     *
     * @see org.ejbca.core.model.services.IWorker#work()
     */
    public void work(Map<Class<?>, Object> ejbs) throws ServiceExecutionFailedException {
        log.trace(">CertificateExpirationNotifierWorker.work started");
        final CAAdminSessionLocal caAdminSession = ((CAAdminSessionLocal)ejbs.get(CAAdminSessionLocal.class));
        certificateStoreSession = ((CertificateStoreSessionLocal)ejbs.get(CertificateStoreSessionLocal.class));
        final UserAdminSessionLocal userAdminSession = ((UserAdminSessionLocal)ejbs.get(UserAdminSessionLocal.class));

        ArrayList<EmailCertData> userEmailQueue = new ArrayList<EmailCertData>();
        ArrayList<EmailCertData> adminEmailQueue = new ArrayList<EmailCertData>();

        // Build Query
        String cASelectString = "";
        Collection<Integer> ids = getCAIdsToCheck(false);
        if (ids.size() > 0) {
            Iterator<Integer> iter = ids.iterator();
            while (iter.hasNext()) {
                Integer caid = iter.next();
                CAInfo caInfo = caAdminSession.getCAInfo(getAdmin(), caid);
                if (caInfo == null) {
                    String msg = intres.getLocalizedMessage("services.errorworker.errornoca", caid, null);
                    log.info(msg);
                    continue;
                }
                String cadn = caInfo.getSubjectDN();
                if (cASelectString.equals("")) {
                    cASelectString = "issuerDN='" + cadn + "' ";
                } else {
                    cASelectString += " OR issuerDN='" + cadn + "' ";
                }
            }

            /*
             * Algorithm:
             *
             * Inputs: CertificateData.status Which either is ACTIVE or
             * NOTIFIEDABOUTEXPIRATION in order to be candidates for
             * notifications.
             *
             * nextRunTimestamp Tells when the next service run will be
             *
             * currRunTimestamp Tells when the service should run (usually "now"
             * but there may be delayed runs as well if the app-server has been
             * down)
             *
             * thresHold The configured "threshold"
             *
             * We want to accomplish two things:
             *
             * 1. Notify for expirations within the service window 2. Notify
             * _once_ for expirations that occurred before the service window
             * like flagging certificates that have a shorter life-span than the
             * threshold (pathologic test-case...)
             *
             * The first is checked by:
             *
             * notify = currRunTimestamp + thresHold <= ExpireDate <
             * nextRunTimestamp + thresHold AND (status = ACTIVE OR status =
             * NOTIFIEDABOUTEXPIRATION)
             *
             * The second can be checked by:
             *
             * notify = currRunTimestamp + thresHold > ExpireDate AND status =
             * ACTIVE
             *
             * In both case status can be set to NOTIFIEDABOUTEXPIRATION
             *
             * As Tomas pointed out we do not need to flag certificates that
             * have expired already which is a separate test.
             */

            long thresHold = getTimeBeforeExpire();
            long now = new Date().getTime();
            if (!cASelectString.equals("")) {
                try {
                    List<Object[]> fingerprintUsernameList = certificateStoreSession.findExpirationInfo(cASelectString, now, (nextRunTimeStamp + thresHold), (runTimeStamp + thresHold));
                    int count = 0;
                    for (Object[] next : fingerprintUsernameList) {
                        count++;
                        // For each certificate update status.
                        String fingerprint = (String) next[0];
                        String username = (String) next[1];
                        // Get the certificate through a session bean
                        log.debug("Found a certificate we should notify. Username=" + username + ", fp=" + fingerprint);
                        Certificate cert = certificateStoreSession.findCertificateByFingerprint(new Admin(Admin.TYPE_INTERNALUSER), fingerprint);
                        UserDataVO userData = userAdminSession.findUser(getAdmin(), username);
                        if (userData != null) {
                            if (isSendToEndUsers()) {
                                if (userData.getEmail() == null || userData.getEmail().trim().equals("")) {
                                    String msg = intres.getLocalizedMessage("services.errorworker.errornoemail", username);
                                    log.info(msg);
                                } else {
                                    // Populate end user message
                                    log.debug("Adding to email queue for user: " + userData.getEmail());
                                    String message = new UserNotificationParamGen(userData, cert).interpolate(getEndUserMessage());
                                    MailActionInfo mailActionInfo = new MailActionInfo(userData.getEmail(), getEndUserSubject(), message);
                                    userEmailQueue.add(new EmailCertData(fingerprint, mailActionInfo));
                                }
                            }
                        } else {
                            log.debug("Trying to send notification to user, but no UserData can be found for user '" + username
                                    + "', will only send to admin if admin notifications are defined.");
                        }
                        if (isSendToAdmins()) {
                            // If we did not have any user for this, we will simply use empty values for substitution
                            if (userData == null) {
                                userData = new UserDataVO();
                                userData.setUsername(username);
                            }
                            // Populate admin message
                            log.debug("Adding to email queue for admin");
                            String message = new UserNotificationParamGen(userData, cert).interpolate(getAdminMessage());
                            MailActionInfo mailActionInfo = new MailActionInfo(null, getAdminSubject(), message);
                            adminEmailQueue.add(new EmailCertData(fingerprint, mailActionInfo));
                        }
                        if (!isSendToEndUsers() && !isSendToAdmins()) {
                            // a little bit of a kludge to make JUnit testing feasible...
                            log.debug("nobody to notify for cert with fp:" + fingerprint);
                            updateStatus(fingerprint, SecConst.CERT_NOTIFIEDABOUTEXPIRATION);
                        }
                    }
                    if (count == 0) {
                        log.debug("No certificates found for notification.");
                    }

                } catch (Exception fe) {
                    log.error("Error running service work: ", fe);
                    throw new ServiceExecutionFailedException(fe);
                }
                if (isSendToEndUsers()) {
                    sendEmails(userEmailQueue, ejbs);
                }
                if (isSendToAdmins()) {
                    sendEmails(adminEmailQueue, ejbs);
                }
            }

        } else {
            log.debug("No CAs to check");
        }
        log.trace("<CertificateExpirationNotifierWorker.work ended");
    }

    /**
     * Method that must be implemented by all subclasses to EmailSendingWorker,
     * used to update status of a certificate, user, or similar
     *
     * @param pk primary key of object to update
     * @param status status to update to
     */
  @Override
    protected void updateStatus(String pk, int status) {
      if (!certificateStoreSession.setStatus(pk, status)) {
            log.error("Error updating certificate status for certificate with fingerprint: " + pk);
      }
    }
}
TOP

Related Classes of org.ejbca.core.model.services.workers.CertificateExpirationNotifierWorker

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.