From 621d9e5c413e561293d7484b93882d985b3fe15f Mon Sep 17 00:00:00 2001 From: Endi Sukma Dewata Date: Sat, 24 Mar 2012 02:27:47 -0500 Subject: Removed unnecessary pki folder. Previously the source code was located inside a pki folder. This folder was created during svn migration and is no longer needed. This folder has now been removed and the contents have been moved up one level. Ticket #131 --- .../common/src/com/netscape/cms/jobs/AJobBase.java | 301 +++++++++ .../src/com/netscape/cms/jobs/PublishCertsJob.java | 392 ++++++++++++ .../netscape/cms/jobs/RenewalNotificationJob.java | 706 +++++++++++++++++++++ .../com/netscape/cms/jobs/RequestInQueueJob.java | 217 +++++++ .../com/netscape/cms/jobs/UnpublishExpiredJob.java | 385 +++++++++++ 5 files changed, 2001 insertions(+) create mode 100644 base/common/src/com/netscape/cms/jobs/AJobBase.java create mode 100644 base/common/src/com/netscape/cms/jobs/PublishCertsJob.java create mode 100644 base/common/src/com/netscape/cms/jobs/RenewalNotificationJob.java create mode 100644 base/common/src/com/netscape/cms/jobs/RequestInQueueJob.java create mode 100644 base/common/src/com/netscape/cms/jobs/UnpublishExpiredJob.java (limited to 'base/common/src/com/netscape/cms/jobs') diff --git a/base/common/src/com/netscape/cms/jobs/AJobBase.java b/base/common/src/com/netscape/cms/jobs/AJobBase.java new file mode 100644 index 000000000..0da5d2028 --- /dev/null +++ b/base/common/src/com/netscape/cms/jobs/AJobBase.java @@ -0,0 +1,301 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// 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; version 2 of the License. +// +// 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, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cms.jobs; + +import java.io.IOException; +import java.util.Hashtable; + +import netscape.security.x509.X509CertImpl; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.base.ISubsystem; +import com.netscape.certsrv.jobs.IJob; +import com.netscape.certsrv.jobs.IJobCron; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.notification.ENotificationException; +import com.netscape.certsrv.notification.IEmailFormProcessor; +import com.netscape.certsrv.notification.IEmailTemplate; +import com.netscape.certsrv.notification.IMailNotification; +import com.netscape.certsrv.request.IRequest; + +/** + * This abstract class is a base job for real job extentions for the + * Jobs Scheduler. + * + * @version $Revision$, $Date$ + * @see com.netscape.certsrv.jobs.IJob + */ +public abstract class AJobBase implements IJob, Runnable { + // config parameters... + protected static final String PROP_SUMMARY = "summary"; + protected static final String PROP_ENABLED = "enabled"; + protected static final String PROP_EMAIL_SUBJECT = "emailSubject"; + protected static final String PROP_EMAIL_TEMPLATE = "emailTemplate"; + protected static final String PROP_ITEM_TEMPLATE = "itemTemplate"; + protected static final String PROP_SENDER_EMAIL = "senderEmail"; + protected static final String PROP_RECEIVER_EMAIL = "recipientEmail"; + + protected static final String STATUS_FAILURE = "failed"; + protected static final String STATUS_SUCCESS = "succeeded"; + + // variables used by the Job Scheduler Daemon + protected String mImplName = null; + protected IConfigStore mConfig; + protected String mId = null; + protected String mCron = null; + protected IJobCron mJobCron = null; + + protected ILogger mLogger = CMS.getLogger(); + protected static String[] mConfigParams = null; + + protected String mSummaryMailSubject = null; + protected boolean mMailHTML = false; + protected String mMailForm = null; + protected String mItemForm = null; + protected String mSummarySenderEmail = null; + protected String mSummaryReceiverEmail = null; + protected Hashtable mContentParams = new Hashtable(); + protected Hashtable mItemParams = new Hashtable(); + + boolean stopped; + + public AJobBase() { + } + + /** + * tells if the job is enabled + * + * @return a boolean value indicating whether the job is enabled + * or not + */ + public boolean isEnabled() { + boolean enabled = false; + + try { + enabled = mConfig.getBoolean(PROP_ENABLED, false); + } catch (EBaseException e) { + } + return enabled; + } + + /*********************** + * abstract methods + ***********************/ + public abstract void init(ISubsystem owner, String id, String implName, IConfigStore + config) throws EBaseException; + + public abstract void run(); + + /*********************** + * public methods + ***********************/ + + /** + * get instance id. + * + * @return a String identifier + */ + public String getId() { + return mId; + } + + /** + * set instance id. + * + * @param id String id of the instance + */ + public void setId(String id) { + mId = id; + } + + /** + * get cron string associated with this job + * + * @return a JobCron object that represents the schedule of this job + */ + public IJobCron getJobCron() { + return mJobCron; + } + + /** + * gets the plugin name of this job. + * + * @return a String that is the name of this implementation + */ + public String getImplName() { + return mImplName; + } + + /** + * Gets the configuration substore used by this job + * + * @return configuration store + */ + public IConfigStore getConfigStore() { + return mConfig; + } + + /* + * get form file content from disk + */ + protected String getTemplateContent(String templatePath) { + String templateString = null; + + /* + * get template file from disk + */ + IEmailTemplate template = CMS.getEmailTemplate(templatePath); + + if (template != null) { + if (!template.init()) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("JOBS_TEMPLATE_INIT_ERROR")); + return null; + } + + // this should take care of inner tempaltes not being html + // we go with the outter template + if (template.isHTML()) { + mMailHTML = true; + } + templateString = template.toString(); + } else { + log(ILogger.LL_FAILURE, CMS.getLogMessage("JOBS_TEMPLATE_INIT_ERROR")); + } + + return templateString; + } + + protected void mailSummary(String content) { + // no need for email resolver here... + IMailNotification mn = CMS.getMailNotification(); + + mn.setFrom(mSummarySenderEmail); + mn.setTo(mSummaryReceiverEmail); + mn.setSubject(mSummaryMailSubject); + if (mMailHTML == true) { + mn.setContentType("text/html"); + } + + mn.setContent(content); + try { + mn.sendNotification(); + } catch (ENotificationException e) { + // already logged, lets audit + mLogger.log(ILogger.EV_AUDIT, null, + ILogger.S_OTHER, + ILogger.LL_FAILURE, CMS.getLogMessage("JOBS_SEND_NOTIFICATION", e.toString())); + } catch (IOException e) { + // already logged, lets audit + mLogger.log(ILogger.EV_AUDIT, null, + ILogger.S_OTHER, + ILogger.LL_FAILURE, CMS.getLogMessage("JOBS_SEND_NOTIFICATION", e.toString())); + } + } + + protected void buildItemParams(X509CertImpl cert) { + mItemParams.put(IEmailFormProcessor.TOKEN_SERIAL_NUM, + cert.getSerialNumber().toString()); + mItemParams.put(IEmailFormProcessor.TOKEN_HEX_SERIAL_NUM, + cert.getSerialNumber().toString(16)); + mItemParams.put(IEmailFormProcessor.TOKEN_ISSUER_DN, + cert.getIssuerDN().toString()); + mItemParams.put(IEmailFormProcessor.TOKEN_SUBJECT_DN, + cert.getSubjectDN().toString()); + mItemParams.put(IEmailFormProcessor.TOKEN_NOT_AFTER, + cert.getNotAfter().toString()); + mItemParams.put(IEmailFormProcessor.TOKEN_NOT_BEFORE, + cert.getNotBefore().toString()); + // ... and more + } + + protected void buildItemParams(IRequest r) { + String re = r.getExtDataInString(IRequest.HTTP_PARAMS, "csrRequestorEmail"); + + if (re != null) { + mItemParams.put(IEmailFormProcessor.TOKEN_REQUESTOR_EMAIL, re); + } + + String ct = r.getExtDataInString(IRequest.HTTP_PARAMS, IRequest.CERT_TYPE); + + if (ct != null) { + mItemParams.put(IEmailFormProcessor.TOKEN_CERT_TYPE, ct); + } + + String rt = r.getExtDataInString(IRequest.REQ_TYPE); + + if (rt != null) { + mItemParams.put(IEmailFormProcessor.TOKEN_REQUEST_TYPE, rt); + } + } + + protected void buildItemParams(String name, String val) { + if (val != null) + mItemParams.put(name, val); + else { + CMS.debug("AJobBase: buildItemParams: null value for name= " + name); + mItemParams.put(name, ""); + } + } + + protected void buildContentParams(String name, String val) { + if (val != null) + mContentParams.put(name, val); + else { + CMS.debug("AJobBase: buildContentParams: null value for name= " + name); + mContentParams.put(name, ""); + } + } + + /** + * logs an entry in the log file. Used by classes extending this class. + * + * @param level log level + * @param msg log message in String + */ + public void log(int level, String msg) { + if (mLogger == null) + return; + mLogger.log(ILogger.EV_SYSTEM, null, ILogger.S_OTHER, + level, mId + ": " + msg); + } + + /** + * capable of logging multiline entry in the log file. Used by classes extending this class. + * + * @param level log level + * @param msg log message in String + * @param multiline boolean indicating whether the message is a + * multi-lined message. + */ + public void log(int level, String msg, boolean multiline) { + if (mLogger == null) + return; + mLogger.log(ILogger.EV_SYSTEM, null, ILogger.S_OTHER, + level, mId + ": " + msg, multiline); + } + + public void stop() { + stopped = true; + } + + public boolean isStopped() { + return stopped; + } +} diff --git a/base/common/src/com/netscape/cms/jobs/PublishCertsJob.java b/base/common/src/com/netscape/cms/jobs/PublishCertsJob.java new file mode 100644 index 000000000..28268dfab --- /dev/null +++ b/base/common/src/com/netscape/cms/jobs/PublishCertsJob.java @@ -0,0 +1,392 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// 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; version 2 of the License. +// +// 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, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cms.jobs; + +import java.text.DateFormat; +import java.util.Date; +import java.util.Enumeration; +import java.util.Locale; + +import netscape.security.x509.X509CertImpl; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.base.IExtendedPluginInfo; +import com.netscape.certsrv.base.ISubsystem; +import com.netscape.certsrv.base.MetaInfo; +import com.netscape.certsrv.ca.ICertificateAuthority; +import com.netscape.certsrv.dbs.certdb.ICertRecord; +import com.netscape.certsrv.dbs.certdb.ICertificateRepository; +import com.netscape.certsrv.jobs.IJob; +import com.netscape.certsrv.jobs.IJobCron; +import com.netscape.certsrv.jobs.IJobsScheduler; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.notification.IEmailFormProcessor; +import com.netscape.certsrv.publish.IPublisherProcessor; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.IRequestQueue; +import com.netscape.certsrv.request.RequestId; + +/** + * a job for the Jobs Scheduler. This job checks in the internal ldap + * db for valid certs that have not been published to the + * publishing directory. + *

+ * the $TOKENS that are available for the this jobs's summary outer form are:
+ *

    + * $Status $InstanceID $SummaryItemList $SummaryTotalNum $SummaryTotalSuccess $SummaryTotalfailure $ExecutionTime + *
+ * and for the inner list items: + *
    + * $SerialNumber $IssuerDN $SubjectDN $NotAfter $NotBefore $RequestorEmail $CertType + *
+ * + * @version $Revision$, $Date$ + */ +public class PublishCertsJob extends AJobBase + implements IJob, Runnable, IExtendedPluginInfo { + + ICertificateAuthority mCa = null; + IRequestQueue mReqQ = null; + ICertificateRepository mRepository = null; + IPublisherProcessor mPublisherProcessor = null; + private boolean mSummary = false; + + /* Holds configuration parameters accepted by this implementation. + * This list is passed to the configuration console so configuration + * for instances of this implementation can be configured through the + * console. + */ + protected static String[] mConfigParams = + new String[] { + "enabled", + "cron", + "summary.enabled", + "summary.emailSubject", + "summary.emailTemplate", + "summary.itemTemplate", + "summary.senderEmail", + "summary.recipientEmail" + }; + + public String[] getExtendedPluginInfo(Locale locale) { + String s[] = { + IExtendedPluginInfo.HELP_TEXT + + "; A job that checks for valid certificates in the " + + "database, that have not been published and publish them to " + + "the publishing directory", + "cron;string;Format: minute hour dayOfMonth month " + + "dayOfWeek. Use '*' for 'every'. For dayOfWeek, 0 is Sunday", + "summary.senderEmail;string;Specify the address to be used " + + "as the email's 'sender'. Bounces go to this address.", + "summary.recipientEmail;string;Who should receive summaries", + "enabled;boolean;Enable this plugin", + "summary.enabled;boolean;Enable the summary. You must enabled " + + "this for the job to work.", + "summary.emailSubject;string;Subject of summary email", + "summary.emailTemplate;string;Fully qualified pathname of " + + "template file of email to be sent", + "summary.itemTemplate;string;Fully qualified pathname of " + + "file containing template for each item", + IExtendedPluginInfo.HELP_TOKEN + + ";configuration-jobrules-unpublishexpiredjobs", + }; + + return s; + } + + /** + * initialize from the configuration file + */ + public void init(ISubsystem owner, String id, String implName, IConfigStore config) throws + EBaseException { + mConfig = config; + mId = id; + mImplName = implName; + + mCa = (ICertificateAuthority) + CMS.getSubsystem("ca"); + if (mCa == null) { + return; + } + + mReqQ = mCa.getRequestQueue(); + mRepository = mCa.getCertificateRepository(); + mPublisherProcessor = mCa.getPublisherProcessor(); + + // read from the configuration file + mCron = mConfig.getString(IJobCron.PROP_CRON); + if (mCron == null) { + return; + } + + // parse cron string into a JobCron class + IJobsScheduler scheduler = (IJobsScheduler) owner; + + mJobCron = scheduler.createJobCron(mCron); + + // initialize the summary related config info + IConfigStore sc = mConfig.getSubStore(PROP_SUMMARY); + + if (sc.getBoolean(PROP_ENABLED, false)) { + mSummary = true; + mSummaryMailSubject = sc.getString(PROP_EMAIL_SUBJECT); + mMailForm = sc.getString(PROP_EMAIL_TEMPLATE); + mItemForm = sc.getString(PROP_ITEM_TEMPLATE); + mSummarySenderEmail = sc.getString(PROP_SENDER_EMAIL); + mSummaryReceiverEmail = sc.getString(PROP_RECEIVER_EMAIL); + } else { + mSummary = false; + } + } + + /** + * look in the internal db for certificateRecords that are + * valid but not published + * The publish() method should set InLdapPublishDir flag accordingly. + * if publish unsuccessfully, log it -- unsuccessful certs should be + * picked up and attempted again at the next scheduled run + */ + public void run() { + CMS.debug("in PublishCertsJob " + + getId() + " : run()"); + // get time now..."now" is before the loop + Date date = CMS.getCurrentDate(); + DateFormat dateFormat = DateFormat.getDateTimeInstance(); + String nowString = dateFormat.format(date); + + // form filter + String filter = // might need to use "metaInfo" + "(!(certMetainfo=" + ICertRecord.META_LDAPPUBLISH + + ":true))"; + + Enumeration unpublishedCerts = null; + + try { + unpublishedCerts = mRepository.findCertRecs(filter); + // bug 399150 + /* + CertRecordList list = null; + list = mRepository.findCertRecordsInList(filter, null, "serialno", 5); + int size = list.getSize(); + expired = list.getCertRecords(0, size - 1); + */ + } catch (EBaseException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("OPERATION_ERROR", e.toString())); + } + + int count = 0; // how many have been published successfully + int negCount = 0; // how many have NOT been published successfully + String contentForm = null; + String itemForm = null; + String itemListContent = null; + + if (mSummary == true) { + contentForm = getTemplateContent(mMailForm); + itemForm = getTemplateContent(mItemForm); + } + + // filter out the invalid ones and publish them + // publish() will set inLdapPublishDir flag + while (unpublishedCerts != null && unpublishedCerts.hasMoreElements()) { + ICertRecord rec = (ICertRecord) unpublishedCerts.nextElement(); + + if (rec == null) + break; + X509CertImpl cert = rec.getCertificate(); + Date notAfter = cert.getNotAfter(); + + // skip CA certs + if (cert.getBasicConstraintsIsCA() == true) + continue; + + // skip the expired certs + if (notAfter.before(date)) + continue; + + if (mSummary == true) + buildItemParams(cert); + + // get request id from cert record MetaInfo + MetaInfo minfo = null; + + try { + minfo = (MetaInfo) rec.get(ICertRecord.ATTR_META_INFO); + } catch (EBaseException e) { + negCount += 1; + if (mSummary == true) + buildItemParams(IEmailFormProcessor.TOKEN_STATUS, + STATUS_FAILURE); + log(ILogger.LL_FAILURE, + CMS.getLogMessage("JOBS_META_INFO_ERROR", + cert.getSerialNumber().toString(16) + + e.toString())); + } + + String ridString = null; + + try { + if (minfo != null) + ridString = (String) minfo.get(ICertRecord.META_REQUEST_ID); + } catch (EBaseException e) { + negCount += 1; + if (mSummary == true) + buildItemParams(IEmailFormProcessor.TOKEN_STATUS, + STATUS_FAILURE); + log(ILogger.LL_FAILURE, + CMS.getLogMessage("JOBS_META_REQUEST_ERROR", + cert.getSerialNumber().toString(16) + + e.toString())); + } catch (NullPointerException e) { + // no requestId in MetaInfo...skip to next record + negCount += 1; + if (mSummary == true) + buildItemParams(IEmailFormProcessor.TOKEN_STATUS, + STATUS_FAILURE); + log(ILogger.LL_FAILURE, + CMS.getLogMessage("JOBS_META_REQUEST_ERROR", + cert.getSerialNumber().toString(16) + + e.toString())); + } + + if (ridString != null) { + RequestId rid = new RequestId(ridString); + + // get request from request id + IRequest req = null; + + try { + req = mReqQ.findRequest(rid); + if (req != null) { + if (mSummary == true) + buildItemParams(req); + } + } catch (EBaseException e) { + negCount += 1; + if (mSummary == true) + buildItemParams(IEmailFormProcessor.TOKEN_STATUS, + STATUS_FAILURE); + log(ILogger.LL_FAILURE, + CMS.getLogMessage("JOBS_FIND_REQUEST_ERROR", + cert.getSerialNumber().toString(16) + + e.toString())); + } + try { + if ((mPublisherProcessor != null) && + mPublisherProcessor.enabled()) { + mPublisherProcessor.publishCert(cert, req); + if (mSummary == true) + buildItemParams(IEmailFormProcessor.TOKEN_STATUS, + STATUS_SUCCESS); + count += 1; + } else { + negCount += 1; + } + } catch (Exception e) { + negCount += 1; + if (mSummary == true) + buildItemParams(IEmailFormProcessor.TOKEN_STATUS, + STATUS_FAILURE); + log(ILogger.LL_FAILURE, + CMS.getLogMessage("JOBS_PUBLISH_ERROR", + cert.getSerialNumber().toString(16) + + e.toString())); + } + } // ridString != null + else { + try { + if ((mPublisherProcessor != null) && + mPublisherProcessor.enabled()) { + mPublisherProcessor.publishCert(cert, null); + + if (mSummary == true) + buildItemParams(IEmailFormProcessor.TOKEN_STATUS, + STATUS_SUCCESS); + count += 1; + } else { + negCount += 1; + } + } catch (Exception e) { + negCount += 1; + + if (mSummary == true) + buildItemParams(IEmailFormProcessor.TOKEN_STATUS, + STATUS_FAILURE); + + log(ILogger.LL_FAILURE, + CMS.getLogMessage("JOBS_PUBLISH_ERROR", + cert.getSerialNumber().toString(16) + + e.toString())); + } + } // ridString == null + + // inLdapPublishDir flag should have been set by the + // publish() method + + // if summary is enabled, form the item content + if (mSummary) { + IEmailFormProcessor emailItemFormProcessor = + CMS.getEmailFormProcessor(); + String c = emailItemFormProcessor.getEmailContent(itemForm, + mItemParams); + + // add item content to the item list + if (itemListContent == null) { + itemListContent = c; + } else { + itemListContent += c; + } + } + } + + // time for summary + if (mSummary == true) { + buildContentParams(IEmailFormProcessor.TOKEN_ID, + mId); + buildContentParams(IEmailFormProcessor.TOKEN_SUMMARY_ITEM_LIST, + itemListContent); + buildContentParams(IEmailFormProcessor.TOKEN_SUMMARY_TOTAL_NUM, + String.valueOf(count + negCount)); + buildContentParams(IEmailFormProcessor.TOKEN_SUMMARY_SUCCESS_NUM, + String.valueOf(count)); + buildContentParams(IEmailFormProcessor.TOKEN_SUMMARY_FAILURE_NUM, + String.valueOf(negCount)); + buildContentParams(IEmailFormProcessor.TOKEN_EXECUTION_TIME, + nowString); + + IEmailFormProcessor emailFormProcessor = CMS.getEmailFormProcessor(); + String mailContent = + emailFormProcessor.getEmailContent(contentForm, + mContentParams); + + mailSummary(mailContent); + } + } + + /** + * Returns a list of configuration parameter names. + * The list is passed to the configuration console so instances of + * this implementation can be configured through the console. + * + * @return String array of configuration parameter names. + */ + public String[] getConfigParams() { + return mConfigParams; + } +} diff --git a/base/common/src/com/netscape/cms/jobs/RenewalNotificationJob.java b/base/common/src/com/netscape/cms/jobs/RenewalNotificationJob.java new file mode 100644 index 000000000..5ca581445 --- /dev/null +++ b/base/common/src/com/netscape/cms/jobs/RenewalNotificationJob.java @@ -0,0 +1,706 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// 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; version 2 of the License. +// +// 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, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cms.jobs; + +import java.io.IOException; +import java.text.DateFormat; +import java.util.Date; +import java.util.Enumeration; +import java.util.Locale; +import java.util.StringTokenizer; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.base.IExtendedPluginInfo; +import com.netscape.certsrv.base.ISubsystem; +import com.netscape.certsrv.base.MetaInfo; +import com.netscape.certsrv.ca.ICertificateAuthority; +import com.netscape.certsrv.dbs.IElementProcessor; +import com.netscape.certsrv.dbs.certdb.ICertRecord; +import com.netscape.certsrv.dbs.certdb.ICertificateRepository; +import com.netscape.certsrv.jobs.IJob; +import com.netscape.certsrv.jobs.IJobCron; +import com.netscape.certsrv.jobs.IJobsScheduler; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.notification.ENotificationException; +import com.netscape.certsrv.notification.IEmailFormProcessor; +import com.netscape.certsrv.notification.IEmailResolver; +import com.netscape.certsrv.notification.IEmailResolverKeys; +import com.netscape.certsrv.notification.IMailNotification; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.RequestId; + +/** + * A job for the Jobs Scheduler. This job checks in the internal ldap + * db for certs about to expire within the next configurable days and + * sends email notifications to the appropriate recipients. + * + * the $TOKENS that are available for the this jobs's summary outer form are:
+ *
    + *
  • $Status + *
  • $InstanceID + *
  • $SummaryItemList + *
  • $SummaryTotalNum + *
  • $SummaryTotalSuccess + *
  • $SummaryTotalfailure + *
  • $ExecutionTime + *
+ * and for the inner list items: + *
    + *
  • $SerialNumber + *
  • $IssuerDN + *
  • $SubjectDN + *
  • $NotAfter + *
  • $NotBefore + *
  • $RequestorEmail + *
  • $CertType + *
  • $RequestType + *
  • $HttpHost + *
  • $HttpPort + *
+ * + * @version $Revision$, $Date$ + * @see com.netscape.certsrv.jobs.IJob + * @see com.netscape.cms.jobs.AJobBase + */ +public class RenewalNotificationJob + extends AJobBase + implements IJob, Runnable, IExtendedPluginInfo { + + // config parameters... + public static final String PROP_CRON = "cron"; + + /** + * Profile ID specifies which profile approves the certificate. + */ + public static final String PROP_PROFILE_ID = "profileId"; + + /** + * This job will send notification at this much time before the + * enpiration date + */ + public static final String PROP_NOTIFYTRIGGEROFFSET = + "notifyTriggerOffset"; + + /** + * This job will stop sending notification this much time after + * the expiration date + */ + public static final String PROP_NOTIFYENDOFFSET = "notifyEndOffset"; + + /** + * sender email address as appeared on the notification email + */ + public static final String PROP_SENDEREMAIL = + "senderEmail"; + + /** + * email subject line as appeared on the notification email + */ + public static final String PROP_EMAILSUBJECT = + "emailSubject"; + + /** + * location of the template file used for email notification + */ + public static final String PROP_EMAILTEMPLATE = "emailTemplate"; + public static final String PROP_MAXNOTIFYCOUNT = "maxNotifyCount"; + + /** + * sender email as appeared on the notification summary email + */ + public static final String PROP_SUMMARY_SENDEREMAIL = "summary.senderEmail"; + + /** + * recipient of the notification summary email + */ + public static final String PROP_SUMMARY_RECIPIENTEMAIL = "summary.recipientEmail"; + + /** + * email subject as appeared on the notification summary email + */ + public static final String PROP_SUMMARY_SUBJECT = "summary.emailSubject"; + + /** + * location of the email template used for notification summary + */ + public static final String PROP_SUMMARY_TEMPLATE = "summary.emailTemplate"; + + /** + * location of the template file for each item appeared on the + * notification summary + */ + public static final String PROP_SUMMARY_ITEMTEMPLATE = "summary.itemTemplate"; + + /* + * Holds configuration parameters accepted by this implementation. + * This list is passed to the configuration console so configuration + * for instances of this implementation can be configured through the + * console. + */ + protected static String[] mConfigParams = + new String[] { + "enabled", + PROP_CRON, + PROP_PROFILE_ID, + PROP_NOTIFYTRIGGEROFFSET, + PROP_NOTIFYENDOFFSET, + PROP_SENDEREMAIL, + PROP_EMAILSUBJECT, + PROP_EMAILTEMPLATE, + "summary.enabled", + PROP_SUMMARY_RECIPIENTEMAIL, + PROP_SUMMARY_SENDEREMAIL, + PROP_SUMMARY_SUBJECT, + PROP_SUMMARY_ITEMTEMPLATE, + PROP_SUMMARY_TEMPLATE, + }; + + protected ICertificateRepository mCertDB = null; + protected ICertificateAuthority mCA = null; + protected boolean mSummary = false; + protected String mEmailSender = null; + protected String mEmailSubject = null; + protected String mEmailTemplateName = null; + protected String mSummaryItemTemplateName = null; + protected String mSummaryTemplateName = null; + protected boolean mSummaryHTML = false; + protected boolean mHTML = false; + + protected String mHttpHost = null; + protected String mHttpPort = null; + + private int mPreDays = 0; + private long mPreMS = 0; + private int mPostDays = 0; + private long mPostMS = 0; + private int mMaxNotifyCount = 1; + private String[] mProfileId = null; + + /** + * class constructor + */ + public RenewalNotificationJob() { + } + + /** + * holds help text for this plugin + */ + public String[] getExtendedPluginInfo(Locale locale) { + String s[] = { + IExtendedPluginInfo.HELP_TEXT + + "; A job that checks for expiring or expired certs" + + "notifyTriggerOffset before and notifyEndOffset after " + + "the expiration date", + + PROP_PROFILE_ID + ";string;Specify the ID of the profile which " + + "approved the certificates that are about to expire. For multiple " + + "profiles, each entry is separated by white space. For example, " + + "if the administrator just wants to give automated notification " + + "when the SSL server certificates are about to expire, then " + + "he should enter \"caServerCert caAgentServerCert\" in the profileId textfield. " + + "Blank field means all profiles.", + PROP_NOTIFYTRIGGEROFFSET + ";number,required;How long (in days) before " + + "certificate expiration will the first notification " + + "be sent", + PROP_NOTIFYENDOFFSET + ";number,required;How long (in days) after " + + "certificate expiration will notifications " + + "continue to be resent if certificate is not renewed", + PROP_CRON + ";string,required;Format: minute hour dayOfMonth Mmonth " + + "dayOfWeek. Use '*' for 'every'. For dayOfWeek, 0 is Sunday", + PROP_SENDEREMAIL + ";string,required;Specify the address to be used " + + "as the email's 'sender'. Bounces go to this address.", + PROP_EMAILSUBJECT + ";string,required;Email subject", + PROP_EMAILTEMPLATE + ";string,required;Fully qualified pathname of " + + "template file of email to be sent", + "enabled;boolean;Enable this plugin", + "summary.enabled;boolean;Enabled sending of summaries", + PROP_SUMMARY_SENDEREMAIL + ";string,required;Sender email address of summary", + PROP_SUMMARY_RECIPIENTEMAIL + ";string,required;Who should receive summaries", + PROP_SUMMARY_SUBJECT + ";string,required;Subject of summary email", + PROP_SUMMARY_TEMPLATE + ";string,required;Fully qualified pathname of " + + "template file of email to be sent", + PROP_SUMMARY_ITEMTEMPLATE + ";string,required;Fully qualified pathname of " + + "file with template to be used for each summary item", + IExtendedPluginInfo.HELP_TOKEN + + ";configuration-jobrules-renewalnotification", + }; + + return s; + } + + /** + * Initialize from the configuration file. + * + * @param id String name of this instance + * @param implName string name of this implementation + * @param config configuration store for this instance + * @exception EBaseException + */ + public void init(ISubsystem owner, String id, String implName, IConfigStore config) throws + EBaseException { + mConfig = config; + mId = id; + mImplName = implName; + + mCA = (ICertificateAuthority) + CMS.getSubsystem("ca"); + if (mCA == null) { + mSummary = false; + return; + } + + mCertDB = mCA.getCertificateRepository(); + + mCron = mConfig.getString(IJobCron.PROP_CRON); + if (mCron == null) { + return; + } + + // parse cron string into a JobCron class + IJobsScheduler scheduler = (IJobsScheduler) owner; + + mJobCron = scheduler.createJobCron(mCron); + } + + /** + * finds out which cert needs notification and notifies the + * responsible parties + */ + public void run() { + // for forming renewal URL at template + mHttpHost = CMS.getEEHost(); + mHttpPort = CMS.getEESSLPort(); + + // read from the configuration file + try { + mPreDays = mConfig.getInteger(PROP_NOTIFYTRIGGEROFFSET, 30); // in days + mPostDays = mConfig.getInteger(PROP_NOTIFYENDOFFSET, 15); // in days + + mEmailSender = mConfig.getString(PROP_SENDEREMAIL); + mEmailSubject = mConfig.getString(PROP_EMAILSUBJECT); + mEmailTemplateName = mConfig.getString(PROP_EMAILTEMPLATE); + + // initialize the summary related config info + IConfigStore sc = mConfig.getSubStore(PROP_SUMMARY); + + if (sc.getBoolean(PROP_ENABLED, false)) { + mSummary = true; + mSummaryItemTemplateName = + mConfig.getString(PROP_SUMMARY_ITEMTEMPLATE); + mSummarySenderEmail = + mConfig.getString(PROP_SUMMARY_SENDEREMAIL); + mSummaryReceiverEmail = + mConfig.getString(PROP_SUMMARY_RECIPIENTEMAIL); + mSummaryMailSubject = + mConfig.getString(PROP_SUMMARY_SUBJECT); + mSummaryTemplateName = + mConfig.getString(PROP_SUMMARY_TEMPLATE); + } else { + mSummary = false; + } + + long msperday = 86400 * 1000; + long mspredays = mPreDays; + long mspostdays = mPostDays; + + mPreMS = mspredays * msperday; + mPostMS = mspostdays * msperday; + + Date now = CMS.getCurrentDate(); + DateFormat dateFormat = DateFormat.getDateTimeInstance(); + String nowString = dateFormat.format(now); + + /* + * look in the internal db for certificateRecords that are + * 1. within the expiration notification period + * 2. has not yet been renewed + * 3. notify - use EmailTemplateProcessor to formulate + * content, then send + * if notified successfully, mark "STATUS_SUCCESS", + * else, if notified unsuccessfully, mark "STATUS_FAILURE". + */ + + /* 1) make target notAfter string */ + + Date expiryDate = null; + Date stopDate = null; + + /* 2) Assemble ldap Search filter string */ + // date format: 19991215125306Z + long expiryMS = now.getTime() + mPreMS; + long stopMS = now.getTime() - mPostMS; + + expiryDate = new Date(expiryMS); + stopDate = new Date(stopMS); + + // All cert records which: + // 1) expire before the deadline + // 2) have not already been renewed + // filter format: + // (& (notafter<='time')(!(certAutoRenew=DONE))(!certAutoRenew=DISABLED)) + + StringBuffer f = new StringBuffer(); + String profileId = ""; + try { + profileId = mConfig.getString(PROP_PROFILE_ID, ""); + } catch (EBaseException ee) { + } + + if (profileId != null && profileId.length() > 0) { + StringTokenizer tokenizer = new StringTokenizer(profileId); + int num = tokenizer.countTokens(); + mProfileId = new String[num]; + for (int i = 0; i < num; i++) + mProfileId[i] = tokenizer.nextToken(); + } + + f.append("(&"); + if (mProfileId != null) { + if (mProfileId.length == 1) + f.append("(" + ICertRecord.ATTR_META_INFO + "=" + + ICertRecord.META_PROFILE_ID + ":" + mProfileId[0] + ")"); + else { + f.append("(|"); + for (int i = 0; i < mProfileId.length; i++) { + f.append("(" + ICertRecord.ATTR_META_INFO + "=" + + ICertRecord.META_PROFILE_ID + ":" + mProfileId[i] + ")"); + } + f.append(")"); + } + } + + f.append("(" + ICertRecord.ATTR_X509CERT + ".notAfter" + "<=" + expiryDate.getTime() + ")"); + f.append("(" + ICertRecord.ATTR_X509CERT + ".notAfter" + ">=" + stopDate.getTime() + ")"); + f.append("(!(" + ICertRecord.ATTR_AUTO_RENEW + "=" + ICertRecord.AUTO_RENEWAL_DONE + "))"); + f.append("(!(" + ICertRecord.ATTR_AUTO_RENEW + "=" + ICertRecord.AUTO_RENEWAL_DISABLED + "))"); + f.append("(!(" + ICertRecord.ATTR_CERT_STATUS + "=" + ICertRecord.STATUS_REVOKED + "))"); + f.append("(!(" + ICertRecord.ATTR_CERT_STATUS + "=" + ICertRecord.STATUS_REVOKED_EXPIRED + "))"); + f.append(")"); + String filter = f.toString(); + + String emailTemplate = + getTemplateContent(mEmailTemplateName); + + mHTML = mMailHTML; + + try { + String summaryItemTemplate = null; + + if (mSummary == true) { + summaryItemTemplate = + getTemplateContent(mSummaryItemTemplateName); + } + + ItemCounter ic = new ItemCounter(); + CertRecProcessor cp = new CertRecProcessor(this, emailTemplate, summaryItemTemplate, ic); + //CertRecordList list = mCertDB.findCertRecordsInList(filter, null, "serialno", 5); + //list.processCertRecords(0, list.getSize() - 1, cp); + + Enumeration en = mCertDB.findCertRecs(filter); + + while (en.hasMoreElements()) { + Object element = en.nextElement(); + + try { + cp.process(element); + } catch (Exception e) { + //Don't abort the entire operation. The error should already be logged + log(ILogger.LL_FAILURE, CMS.getLogMessage("JOBS_FAILED_PROCESS", e.toString())); + } + } + + // Now send the summary + + if (mSummary == true) { + try { + String summaryTemplate = + getTemplateContent(mSummaryTemplateName); + + mSummaryHTML = mMailHTML; + + buildContentParams(IEmailFormProcessor.TOKEN_ID, + mId); + + buildContentParams(IEmailFormProcessor.TOKEN_SUMMARY_ITEM_LIST, + ic.mItemListContent); + buildContentParams(IEmailFormProcessor.TOKEN_SUMMARY_TOTAL_NUM, + String.valueOf(ic.mNumFail + ic.mNumSuccessful)); + buildContentParams(IEmailFormProcessor.TOKEN_SUMMARY_SUCCESS_NUM, + String.valueOf(ic.mNumSuccessful)); + buildContentParams(IEmailFormProcessor.TOKEN_SUMMARY_FAILURE_NUM, + String.valueOf(ic.mNumFail)); + + buildContentParams(IEmailFormProcessor.TOKEN_EXECUTION_TIME, + nowString); + + IEmailFormProcessor summaryEmfp = CMS.getEmailFormProcessor(); + + String summaryContent = + summaryEmfp.getEmailContent(summaryTemplate, + mContentParams); + + if (summaryContent == null) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("JOBS_SUMMARY_CONTENT_NULL")); + mailSummary(" no summaryContent"); + } else { + mMailHTML = mSummaryHTML; + mailSummary(summaryContent); + } + } catch (Exception e) { + // log error + log(ILogger.LL_FAILURE, CMS.getLogMessage("JOBS_EXCEPTION_IN_RUN", e.toString())); + } + } + } catch (EBaseException e) { + // log error + log(ILogger.LL_FAILURE, CMS.getLogMessage("OPERATION_ERROR", e.toString())); + } + } catch (EBaseException ex) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("Configuration error:", ex.toString())); + } + } + + /** + * get instance id. + * + * @return a String identifier + */ + public String getId() { + return mId; + } + + /** + * set instance id. + * + * @param id String id of the instance + */ + public void setId(String id) { + mId = id; + } + + /** + * get cron string associated with this job + * + * @return a JobCron object that represents the schedule of this job + */ + public IJobCron getJobCron() { + return mJobCron; + } + + /** + * gets the plugin name of this job. + * + * @return a String that is the name of this implementation + */ + public String getImplName() { + return mImplName; + } + + /** + * Gets the configuration substore used by this job + * + * @return configuration store + */ + public IConfigStore getConfigStore() { + return mConfig; + } + + protected void mailUser(String subject, + String msg, + String sender, + IRequest req, + ICertRecord cr) + throws IOException, ENotificationException, EBaseException { + + IMailNotification mn = CMS.getMailNotification(); + + String rcp = null; + // boolean sendFailed = false; + Exception sendFailedException = null; + + IEmailResolverKeys keys = CMS.getEmailResolverKeys(); + + try { + if (req != null) { + keys.set(IEmailResolverKeys.KEY_REQUEST, req); + } + if (cr != null) { + Object c = cr.getCertificate(); + + if (c != null) { + keys.set(IEmailResolverKeys.KEY_CERT, cr.getCertificate()); + } + } + + IEmailResolver er = CMS.getReqCertSANameEmailResolver(); + + rcp = er.getEmail(keys); + + } catch (Exception e) { + // already logged by the resolver + // sendFailed = true; + sendFailedException = e; + throw (ENotificationException) sendFailedException; + } + + mn.setTo(rcp); + + if (sender != null) + mn.setFrom(sender); + else + mn.setFrom("nobody"); + + if (subject != null) + mn.setSubject(subject); + else + mn.setFrom("Important message from Certificate Authority"); + + if (mHTML == true) + mn.setContentType("text/html"); + + mn.setContent(msg); + + mn.sendNotification(); + } + + /** + * Returns a list of configuration parameter names. + * The list is passed to the configuration console so instances of + * this implementation can be configured through the console. + * + * @return String array of configuration parameter names. + */ + public String[] getConfigParams() { + return (mConfigParams); + } +} + +class CertRecProcessor implements IElementProcessor { + protected RenewalNotificationJob mJob; + protected String mEmailTemplate; + protected String mSummaryItemTemplate; + protected ItemCounter mIC; + + public CertRecProcessor(RenewalNotificationJob job, String emailTemplate, + String summaryItemTemplate, ItemCounter ic) { + mJob = job; + mEmailTemplate = emailTemplate; + mSummaryItemTemplate = summaryItemTemplate; + mIC = ic; + } + + public void process(Object o) throws EBaseException { + + // Get each certRecord + ICertRecord cr = (ICertRecord) o; + + String ridString = null; + boolean numFailCounted = false; + + if (cr != null) { + mJob.buildItemParams(cr.getCertificate()); + mJob.buildItemParams(IEmailFormProcessor.TOKEN_HTTP_HOST, + mJob.mHttpHost); + mJob.buildItemParams(IEmailFormProcessor.TOKEN_HTTP_PORT, mJob.mHttpPort); + + MetaInfo metaInfo = null; + + metaInfo = (MetaInfo) cr.get(ICertRecord.ATTR_META_INFO); + if (metaInfo == null) { + mIC.mNumFail++; + numFailCounted = true; + if (mJob.mSummary == true) + mJob.buildItemParams(IEmailFormProcessor.TOKEN_STATUS, + AJobBase.STATUS_FAILURE); + mJob.log(ILogger.LL_FAILURE, + CMS.getLogMessage("JOBS_GET_CERT_ERROR", + cr.getCertificate().getSerialNumber().toString(16))); + } else { + ridString = (String) metaInfo.get(ICertRecord.META_REQUEST_ID); + } + } + + IRequest req = null; + + if (ridString != null) { + RequestId rid = new RequestId(ridString); + + try { + req = mJob.mCA.getRequestQueue().findRequest(rid); + } catch (Exception e) { + // it is ok not to be able to get the request. The main reason + // to get the request is to retrieve the requestor's email. + // We can retrieve the email from the CertRecord. + CMS.debug("huh RenewalNotificationJob Exception: " + e.toString()); + } + + if (req != null) + mJob.buildItemParams(req); + } // ridString != null + + try { + // send mail to user + + IEmailFormProcessor emfp = CMS.getEmailFormProcessor(); + String message = emfp.getEmailContent(mEmailTemplate, + mJob.mItemParams); + + mJob.mailUser(mJob.mEmailSubject, + message, + mJob.mEmailSender, + req, + cr); + + mJob.buildItemParams(IEmailFormProcessor.TOKEN_STATUS, + AJobBase.STATUS_SUCCESS); + + mIC.mNumSuccessful++; + + } catch (Exception e) { + CMS.debug("RenewalNotificationJob Exception: " + e.toString()); + mJob.buildItemParams(IEmailFormProcessor.TOKEN_STATUS, AJobBase.STATUS_FAILURE); + mJob.log(ILogger.LL_FAILURE, e.toString(), ILogger.L_MULTILINE); + if (numFailCounted == false) { + mIC.mNumFail++; + } + } + + if (mJob.mSummary == true) { + IEmailFormProcessor summaryItemEmfp = + CMS.getEmailFormProcessor(); + String c = + summaryItemEmfp.getEmailContent(mSummaryItemTemplate, + mJob.mItemParams); + + if (mIC.mItemListContent == null) { + mIC.mItemListContent = c; + } else { + mIC.mItemListContent += c; + } + } + } +} + +class ItemCounter { + public int mNumSuccessful = 0; + public int mNumFail = 0; + public String mItemListContent = null; +} diff --git a/base/common/src/com/netscape/cms/jobs/RequestInQueueJob.java b/base/common/src/com/netscape/cms/jobs/RequestInQueueJob.java new file mode 100644 index 000000000..b04461941 --- /dev/null +++ b/base/common/src/com/netscape/cms/jobs/RequestInQueueJob.java @@ -0,0 +1,217 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// 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; version 2 of the License. +// +// 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, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cms.jobs; + +import java.text.DateFormat; +import java.util.Date; +import java.util.Locale; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.authority.IAuthority; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.base.IExtendedPluginInfo; +import com.netscape.certsrv.base.ISubsystem; +import com.netscape.certsrv.jobs.IJob; +import com.netscape.certsrv.jobs.IJobCron; +import com.netscape.certsrv.jobs.IJobsScheduler; +import com.netscape.certsrv.notification.IEmailFormProcessor; +import com.netscape.certsrv.request.IRequestList; +import com.netscape.certsrv.request.IRequestQueue; +import com.netscape.certsrv.request.RequestStatus; + +/** + * A job for the Jobs Scheduler. This job checks in the internal ldap + * db for requests currently in the request queue and send a summary + * report to the administrator + *

+ * the $TOKENS that are available for the this jobs's summary outer form are:
+ *

    + * $InstanceID $SummaryTotalNum $ExecutionTime + *
+ * + * @version $Revision$, $Date$ + * @see com.netscape.certsrv.jobs.IJob + * @see com.netscape.cms.jobs.AJobBase + */ +public class RequestInQueueJob extends AJobBase + implements IJob, Runnable, IExtendedPluginInfo { + protected static final String PROP_SUBSYSTEM_ID = "subsystemId"; + + IAuthority mSub = null; + IRequestQueue mReqQ = null; + private boolean mSummary = false; + + /* Holds configuration parameters accepted by this implementation. + * This list is passed to the configuration console so configuration + * for instances of this implementation can be configured through the + * console. + */ + protected static String[] mConfigParams = + new String[] { + "enabled", + "cron", + "subsystemId", + "summary.enabled", + "summary.emailSubject", + "summary.emailTemplate", + "summary.senderEmail", + "summary.recipientEmail" + }; + + /** + * holds help text for this plugin + */ + public String[] getExtendedPluginInfo(Locale locale) { + String s[] = { + IExtendedPluginInfo.HELP_TEXT + + "; A job that checks for enrollment requests in the " + + "queue, and reports to recipientEmail", + "cron;string;Format: minute hour dayOfMonth month " + + "dayOfWeek. Use '*' for 'every'. For dayOfWeek, 0 is Sunday", + "summary.senderEmail;string;Specify the address to be used " + + "as the email's 'sender'. Bounces go to this address.", + "summary.recipientEmail;string;Who should receive summaries", + "enabled;boolean;Enable this plugin", + "summary.enabled;boolean;Enable the summary. You must enabled " + + "this for the job to work.", + "summary.emailSubject;string;Subject of summary email", + "summary.emailTemplate;string;Fully qualified pathname of " + + "template file of email to be sent", + "subsystemId;choice(ca,ra);The type of subsystem this job is " + + "for", + IExtendedPluginInfo.HELP_TOKEN + + ";configuration-jobrules-requestinqueuejob", + }; + + return s; + } + + /** + * initialize from the configuration file + * + * @param id String name of this instance + * @param implName string name of this implementation + * @param config configuration store for this instance + * @exception EBaseException + */ + public void init(ISubsystem owner, String id, String implName, IConfigStore config) throws + EBaseException { + mConfig = config; + mId = id; + mImplName = implName; + + // read from the configuration file + String sub = mConfig.getString(PROP_SUBSYSTEM_ID); + + mSub = (IAuthority) + CMS.getSubsystem(sub); + if (mSub == null) { + // take this as disable + mSummary = false; + return; + } + + mReqQ = mSub.getRequestQueue(); + + mCron = mConfig.getString(IJobCron.PROP_CRON); + if (mCron == null) { + return; + } + + // parse cron string into a JobCron class + IJobsScheduler scheduler = (IJobsScheduler) owner; + + mJobCron = scheduler.createJobCron(mCron); + + // initialize the summary related config info + IConfigStore sc = mConfig.getSubStore(PROP_SUMMARY); + + if (sc.getBoolean(PROP_ENABLED, false)) { + mSummary = true; + mSummaryMailSubject = sc.getString(PROP_EMAIL_SUBJECT); + mMailForm = sc.getString(PROP_EMAIL_TEMPLATE); + // mItemForm = sc.getString(PROP_ITEM_TEMPLATE); + mSummarySenderEmail = sc.getString(PROP_SENDER_EMAIL); + mSummaryReceiverEmail = sc.getString(PROP_RECEIVER_EMAIL); + } else { + mSummary = false; + } + } + + /** + * summarize the queue status and mail it + */ + public void run() { + if (mSummary == false) + return; + + Date date = CMS.getCurrentDate(); + DateFormat dateFormat = DateFormat.getDateTimeInstance(); + String nowString = dateFormat.format(date); + + int count = 0; + IRequestList list = + mReqQ.listRequestsByStatus(RequestStatus.PENDING); + + while (list != null && list.hasMoreElements()) { + list.nextRequestId(); + + /* This is way too slow + // get request from request id + IRequest req = null; + try { + req = mReqQ.findRequest(rid); + } catch (EBaseException e) { + System.out.println(e.toString()); + } + */ + count++; + } + + // if (count == 0) return; + + String contentForm = null; + + contentForm = getTemplateContent(mMailForm); + + buildContentParams(IEmailFormProcessor.TOKEN_ID, mId); + buildContentParams(IEmailFormProcessor.TOKEN_SUMMARY_TOTAL_NUM, + String.valueOf(count)); + buildContentParams(IEmailFormProcessor.TOKEN_EXECUTION_TIME, + nowString); + + IEmailFormProcessor emailFormProcessor = CMS.getEmailFormProcessor(); + String mailContent = + emailFormProcessor.getEmailContent(contentForm, + mContentParams); + + mailSummary(mailContent); + } + + /** + * Returns a list of configuration parameter names. + * The list is passed to the configuration console so instances of + * this implementation can be configured through the console. + * + * @return String array of configuration parameter names. + */ + public String[] getConfigParams() { + return mConfigParams; + } +} diff --git a/base/common/src/com/netscape/cms/jobs/UnpublishExpiredJob.java b/base/common/src/com/netscape/cms/jobs/UnpublishExpiredJob.java new file mode 100644 index 000000000..2f4a6ad75 --- /dev/null +++ b/base/common/src/com/netscape/cms/jobs/UnpublishExpiredJob.java @@ -0,0 +1,385 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// 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; version 2 of the License. +// +// 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, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cms.jobs; + +import java.security.cert.X509Certificate; +import java.text.DateFormat; +import java.util.Date; +import java.util.Enumeration; +import java.util.Locale; + +import netscape.security.x509.X509CertImpl; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.base.IExtendedPluginInfo; +import com.netscape.certsrv.base.ISubsystem; +import com.netscape.certsrv.base.MetaInfo; +import com.netscape.certsrv.ca.ICertificateAuthority; +import com.netscape.certsrv.dbs.certdb.ICertRecord; +import com.netscape.certsrv.dbs.certdb.ICertificateRepository; +import com.netscape.certsrv.jobs.IJob; +import com.netscape.certsrv.jobs.IJobCron; +import com.netscape.certsrv.jobs.IJobsScheduler; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.notification.IEmailFormProcessor; +import com.netscape.certsrv.publish.IPublisherProcessor; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.IRequestQueue; +import com.netscape.certsrv.request.RequestId; + +/** + * a job for the Jobs Scheduler. This job checks in the internal ldap + * db for certs that have expired and remove them from the ldap + * publishing directory. + *

+ * the $TOKENS that are available for the this jobs's summary outer form are:
+ *

    + * $Status $InstanceID $SummaryItemList $SummaryTotalNum $SummaryTotalSuccess $SummaryTotalfailure $ExecutionTime + *
+ * and for the inner list items: + *
    + * $SerialNumber $IssuerDN $SubjectDN $NotAfter $NotBefore $RequestorEmail $CertType + *
+ * + * @version $Revision$, $Date$ + */ +public class UnpublishExpiredJob extends AJobBase + implements IJob, Runnable, IExtendedPluginInfo { + + ICertificateAuthority mCa = null; + IRequestQueue mReqQ = null; + ICertificateRepository mRepository = null; + IPublisherProcessor mPublisherProcessor = null; + private boolean mSummary = false; + + /* Holds configuration parameters accepted by this implementation. + * This list is passed to the configuration console so configuration + * for instances of this implementation can be configured through the + * console. + */ + protected static String[] mConfigParams = + new String[] { + "enabled", + "cron", + "summary.enabled", + "summary.emailSubject", + "summary.emailTemplate", + "summary.itemTemplate", + "summary.senderEmail", + "summary.recipientEmail" + }; + + public String[] getExtendedPluginInfo(Locale locale) { + String s[] = { + IExtendedPluginInfo.HELP_TEXT + + "; A job that checks for expired certificates in the " + + "database, and removes them from the publishing " + + "directory", + "cron;string;Format: minute hour dayOfMonth month " + + "dayOfWeek. Use '*' for 'every'. For dayOfWeek, 0 is Sunday", + "summary.senderEmail;string;Specify the address to be used " + + "as the email's 'sender'. Bounces go to this address.", + "summary.recipientEmail;string;Who should receive summaries", + "enabled;boolean;Enable this plugin", + "summary.enabled;boolean;Enable the summary. You must enabled " + + "this for the job to work.", + "summary.emailSubject;string;Subject of summary email", + "summary.emailTemplate;string;Fully qualified pathname of " + + "template file of email to be sent", + "summary.itemTemplate;string;Fully qualified pathname of " + + "file containing template for each item", + IExtendedPluginInfo.HELP_TOKEN + + ";configuration-jobrules-unpublishexpiredjobs", + }; + + return s; + } + + /** + * initialize from the configuration file + */ + public void init(ISubsystem owner, String id, String implName, IConfigStore config) throws + EBaseException { + mConfig = config; + mId = id; + mImplName = implName; + + mCa = (ICertificateAuthority) + CMS.getSubsystem("ca"); + if (mCa == null) { + return; + } + + mReqQ = mCa.getRequestQueue(); + mRepository = mCa.getCertificateRepository(); + mPublisherProcessor = mCa.getPublisherProcessor(); + + // read from the configuration file + mCron = mConfig.getString(IJobCron.PROP_CRON); + if (mCron == null) { + return; + } + + // parse cron string into a JobCron class + IJobsScheduler scheduler = (IJobsScheduler) owner; + + mJobCron = scheduler.createJobCron(mCron); + + // initialize the summary related config info + IConfigStore sc = mConfig.getSubStore(PROP_SUMMARY); + + if (sc.getBoolean(PROP_ENABLED, false)) { + mSummary = true; + mSummaryMailSubject = sc.getString(PROP_EMAIL_SUBJECT); + mMailForm = sc.getString(PROP_EMAIL_TEMPLATE); + mItemForm = sc.getString(PROP_ITEM_TEMPLATE); + mSummarySenderEmail = sc.getString(PROP_SENDER_EMAIL); + mSummaryReceiverEmail = sc.getString(PROP_RECEIVER_EMAIL); + } else { + mSummary = false; + } + } + + /** + * look in the internal db for certificateRecords that are + * expired. + * remove them from ldap publishing directory + * if remove successfully, mark false on the + * InLdapPublishDir flag, + * else, if remove unsuccessfully, log it + */ + public void run() { + // System.out.println("in ExpiredUnpublishJob "+ + // getId()+ " : run()"); + // get time now..."now" is before the loop + Date date = CMS.getCurrentDate(); + long now = date.getTime(); + DateFormat dateFormat = DateFormat.getDateTimeInstance(); + String nowString = dateFormat.format(date); + + // form filter + String filter = "(&(x509Cert.notAfter<=" + now + + ")(!(x509Cert.notAfter=" + now + "))" + + "(" + "certMetainfo=" + ICertRecord.META_LDAPPUBLISH + + ":true))"; + // a test for without CertRecord.META_LDAPPUBLISH + //String filter = "(x509Cert.notAfter<="+ now +")"; + + Enumeration expired = null; + + try { + expired = mRepository.findCertRecs(filter); + // bug 399150 + /* + CertRecordList list = null; + list = mRepository.findCertRecordsInList(filter, null, "serialno", 5); + int size = list.getSize(); + expired = list.getCertRecords(0, size - 1); + */ + } catch (EBaseException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("OPERATION_ERROR", e.toString())); + } + + int count = 0; // how many have been unpublished successfully + int negCount = 0; // how many have NOT been unpublished successfully + String contentForm = null; + String itemForm = null; + String itemListContent = null; + + if (mSummary == true) { + contentForm = getTemplateContent(mMailForm); + itemForm = getTemplateContent(mItemForm); + } + + // unpublish them and unpublish() will set inLdapPublishDir flag + while (expired != null && expired.hasMoreElements()) { + ICertRecord rec = (ICertRecord) expired.nextElement(); + + if (rec == null) + break; + X509CertImpl cert = rec.getCertificate(); + + if (mSummary == true) + buildItemParams(cert); + + // get request id from cert record MetaInfo + MetaInfo minfo = null; + + try { + minfo = (MetaInfo) rec.get(ICertRecord.ATTR_META_INFO); + } catch (EBaseException e) { + negCount += 1; + if (mSummary == true) + buildItemParams(IEmailFormProcessor.TOKEN_STATUS, + STATUS_FAILURE); + log(ILogger.LL_FAILURE, + CMS.getLogMessage("JOBS_META_INFO_ERROR", + cert.getSerialNumber().toString(16) + + e.toString())); + } + + String ridString = null; + + try { + if (minfo != null) + ridString = (String) minfo.get(ICertRecord.META_REQUEST_ID); + } catch (EBaseException e) { + negCount += 1; + if (mSummary == true) + buildItemParams(IEmailFormProcessor.TOKEN_STATUS, + STATUS_FAILURE); + log(ILogger.LL_FAILURE, + CMS.getLogMessage("JOBS_META_REQUEST_ERROR", + cert.getSerialNumber().toString(16) + + e.toString())); + } catch (NullPointerException e) { + // no requestId in MetaInfo...skip to next record + negCount += 1; + if (mSummary == true) + buildItemParams(IEmailFormProcessor.TOKEN_STATUS, + STATUS_FAILURE); + log(ILogger.LL_FAILURE, + CMS.getLogMessage("JOBS_META_REQUEST_ERROR", + cert.getSerialNumber().toString(16) + + e.toString())); + } + + if (ridString != null) { + RequestId rid = new RequestId(ridString); + + // get request from request id + IRequest req = null; + + try { + req = mReqQ.findRequest(rid); + if (req != null) { + if (mSummary == true) + buildItemParams(req); + } + } catch (EBaseException e) { + negCount += 1; + if (mSummary == true) + buildItemParams(IEmailFormProcessor.TOKEN_STATUS, + STATUS_FAILURE); + log(ILogger.LL_FAILURE, + CMS.getLogMessage("JOBS_FIND_REQUEST_ERROR", + cert.getSerialNumber().toString(16) + + e.toString())); + } + try { + if ((mPublisherProcessor != null) && + mPublisherProcessor.enabled()) { + mPublisherProcessor.unpublishCert((X509Certificate) cert, req); + if (mSummary == true) + buildItemParams(IEmailFormProcessor.TOKEN_STATUS, + STATUS_SUCCESS); + count += 1; + } else { + negCount += 1; + } + } catch (Exception e) { + negCount += 1; + if (mSummary == true) + buildItemParams(IEmailFormProcessor.TOKEN_STATUS, + STATUS_FAILURE); + log(ILogger.LL_FAILURE, + CMS.getLogMessage("JOBS_UNPUBLISH_ERROR", + cert.getSerialNumber().toString(16) + + e.toString())); + } + } // ridString != null + else { + try { + if ((mPublisherProcessor != null) && + mPublisherProcessor.enabled()) { + mPublisherProcessor.unpublishCert((X509Certificate) cert, null); + if (mSummary == true) + buildItemParams(IEmailFormProcessor.TOKEN_STATUS, + STATUS_SUCCESS); + count += 1; + } else { + negCount += 1; + } + } catch (Exception e) { + negCount += 1; + if (mSummary == true) + buildItemParams(IEmailFormProcessor.TOKEN_STATUS, + STATUS_FAILURE); + log(ILogger.LL_FAILURE, + CMS.getLogMessage("JOBS_UNPUBLISH_ERROR", + cert.getSerialNumber().toString(16) + + e.toString())); + } + } // ridString == null + + // inLdapPublishDir flag should have been set by the + // unpublish() method + + // if summary is enabled, form the item content + if (mSummary) { + IEmailFormProcessor emailItemFormProcessor = + CMS.getEmailFormProcessor(); + String c = emailItemFormProcessor.getEmailContent(itemForm, + mItemParams); + + // add item content to the item list + if (itemListContent == null) { + itemListContent = c; + } else { + itemListContent += c; + } + } + } + + // time for summary + if (mSummary == true) { + buildContentParams(IEmailFormProcessor.TOKEN_ID, + mId); + buildContentParams(IEmailFormProcessor.TOKEN_SUMMARY_ITEM_LIST, + itemListContent); + buildContentParams(IEmailFormProcessor.TOKEN_SUMMARY_TOTAL_NUM, + String.valueOf(count + negCount)); + buildContentParams(IEmailFormProcessor.TOKEN_SUMMARY_SUCCESS_NUM, + String.valueOf(count)); + buildContentParams(IEmailFormProcessor.TOKEN_SUMMARY_FAILURE_NUM, + String.valueOf(negCount)); + buildContentParams(IEmailFormProcessor.TOKEN_EXECUTION_TIME, + nowString); + + IEmailFormProcessor emailFormProcessor = CMS.getEmailFormProcessor(); + String mailContent = + emailFormProcessor.getEmailContent(contentForm, + mContentParams); + + mailSummary(mailContent); + } + } + + /** + * Returns a list of configuration parameter names. + * The list is passed to the configuration console so instances of + * this implementation can be configured through the console. + * + * @return String array of configuration parameter names. + */ + public String[] getConfigParams() { + return (mConfigParams); + } +} -- cgit