summaryrefslogtreecommitdiffstats
path: root/base/common/src/com/netscape/cms/servlet/cert
diff options
context:
space:
mode:
authorAde Lee <alee@redhat.com>2012-05-13 23:04:36 -0400
committerAde Lee <alee@redhat.com>2012-07-03 13:58:45 -0400
commit9ce810c0b2fef9f70178dbeee8a3523755a2a260 (patch)
treea25cd9e9969898506ed2a4cb17a3cfbeb68496cf /base/common/src/com/netscape/cms/servlet/cert
parent0f3451befbc14bd6ec29d9e1e3845f970f288653 (diff)
downloadpki-9ce810c0b2fef9f70178dbeee8a3523755a2a260.tar.gz
pki-9ce810c0b2fef9f70178dbeee8a3523755a2a260.tar.xz
pki-9ce810c0b2fef9f70178dbeee8a3523755a2a260.zip
Adding restful interface to create certificate requests and issue certificates.
Refactored ProfileSubmitServlet to make the flow clearer. Both the legacy servlets and the new RESTful servlets use common ProfileProcessor objects that contain the main business logic, so that the amount of duplicated code is minimized. Refactored ProfileProcessServlet to use the new common classes. Addressed review comments. Removed an unneeded class and reverted some unneeded jaxb annotations. Added factory methods.
Diffstat (limited to 'base/common/src/com/netscape/cms/servlet/cert')
-rw-r--r--base/common/src/com/netscape/cms/servlet/cert/CertProcessor.java351
-rw-r--r--base/common/src/com/netscape/cms/servlet/cert/EnrollmentProcessor.java205
-rw-r--r--base/common/src/com/netscape/cms/servlet/cert/RenewalProcessor.java345
-rw-r--r--base/common/src/com/netscape/cms/servlet/cert/RequestProcessor.java475
4 files changed, 1376 insertions, 0 deletions
diff --git a/base/common/src/com/netscape/cms/servlet/cert/CertProcessor.java b/base/common/src/com/netscape/cms/servlet/cert/CertProcessor.java
new file mode 100644
index 000000000..13b0072b4
--- /dev/null
+++ b/base/common/src/com/netscape/cms/servlet/cert/CertProcessor.java
@@ -0,0 +1,351 @@
+// --- 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) 2012 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cms.servlet.cert;
+
+import java.math.BigInteger;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.authentication.IAuthToken;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.EPropertyNotFound;
+import com.netscape.certsrv.logging.ILogger;
+import com.netscape.certsrv.profile.EDeferException;
+import com.netscape.certsrv.profile.ERejectException;
+import com.netscape.certsrv.profile.IProfile;
+import com.netscape.certsrv.profile.IProfileAuthenticator;
+import com.netscape.certsrv.profile.IProfileContext;
+import com.netscape.certsrv.profile.IProfileInput;
+import com.netscape.certsrv.request.INotify;
+import com.netscape.certsrv.request.IRequest;
+import com.netscape.certsrv.request.RequestStatus;
+import com.netscape.cms.servlet.processors.Processor;
+import com.netscape.cms.servlet.profile.model.ProfileInput;
+import com.netscape.cms.servlet.request.model.EnrollmentRequestData;
+
+public class CertProcessor extends Processor {
+
+ public CertProcessor(String id, Locale locale) throws EPropertyNotFound, EBaseException {
+ super(id, locale);
+ }
+
+ protected void setCredentialsIntoContext(HttpServletRequest request, IProfileAuthenticator authenticator,
+ IProfileContext ctx) {
+ Enumeration<String> authIds = authenticator.getValueNames();
+
+ if (authIds != null) {
+ CMS.debug("CertRequestSubmitter:setCredentialsIntoContext() authNames not null");
+ while (authIds.hasMoreElements()) {
+ String authName = authIds.nextElement();
+
+ CMS.debug("CertRequestSubmitter:setCredentialsIntoContext() authName:" +
+ authName);
+ if (request.getParameter(authName) != null) {
+ CMS.debug("CertRequestSubmitter:setCredentialsIntoContext() authName found in request");
+ ctx.set(authName, request.getParameter(authName));
+ } else {
+ CMS.debug("CertRequestSubmitter:setCredentialsIntoContext() authName not found in request");
+ }
+ }
+ } else {
+ CMS.debug("CertRequestSubmitter:setCredentialsIntoContext() authIds` null");
+ }
+ }
+
+ private void setInputsIntoRequest(EnrollmentRequestData data, IProfile profile, IRequest req) {
+ // put profile inputs into a local map
+ HashMap<String, String> dataInputs = new HashMap<String, String>();
+ for (ProfileInput input : data.getInputs()) {
+ Map<String, String> attrs = input.getAttributes();
+ for (Map.Entry<String, String> entry : attrs.entrySet()) {
+ dataInputs.put(entry.getKey(), entry.getValue());
+ }
+ }
+
+ // iterate over inputs in profile
+ Enumeration<String> inputIds = profile.getProfileInputIds();
+ if (inputIds != null) {
+ while (inputIds.hasMoreElements()) {
+ String inputId = inputIds.nextElement();
+ IProfileInput profileInput = profile.getProfileInput(inputId);
+ Enumeration<String> inputNames = profileInput.getValueNames();
+
+ if (inputNames != null) {
+ while (inputNames.hasMoreElements()) {
+ String inputName = inputNames.nextElement();
+ if (dataInputs.containsKey(inputName)) {
+ // special characters in subject names parameters must be escaped
+ if (inputName.matches("^sn_.*")) {
+ req.setExtData(inputName,
+ escapeValueRfc1779(dataInputs.get(inputName), false)
+ .toString());
+ } else {
+ req.setExtData(inputName, dataInputs.get(inputName));
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ * fill input info from orig request to the renew request.
+ * This is expected to be used by renewal where the request
+ * is retrieved from request record
+ */
+ private void setInputsIntoRequest(IRequest request, IProfile profile, IRequest req, Locale locale) {
+ // passing inputs into request
+ Enumeration<String> inputIds = profile.getProfileInputIds();
+
+ if (inputIds != null) {
+ while (inputIds.hasMoreElements()) {
+ String inputId = inputIds.nextElement();
+ IProfileInput profileInput = profile.getProfileInput(inputId);
+ Enumeration<String> inputNames = profileInput.getValueNames();
+
+ while (inputNames.hasMoreElements()) {
+ String inputName = inputNames.nextElement();
+ String inputValue = "";
+ CMS.debug("CertRequestSubmitter: setInputsIntoRequest() getting input name= " + inputName);
+ try {
+ inputValue = profileInput.getValue(inputName, locale, request);
+ } catch (Exception e) {
+ CMS.debug("CertRequestSubmitter: setInputsIntoRequest() getvalue() failed: " + e.toString());
+ }
+
+ if (inputValue != null) {
+ CMS.debug("CertRequestSubmitter: setInputsIntoRequest() setting value in ctx:" + inputValue);
+ req.setExtData(inputName, inputValue);
+ } else {
+ CMS.debug("CertRequestSubmitter: setInputsIntoRequest() value null");
+ }
+ }
+ }
+ }
+
+ }
+
+ protected String codeToReason(Locale locale, String errorCode) {
+ if (errorCode == null) return null;
+ if (errorCode.equals("1")) {
+ return CMS.getUserMessage(locale, "CMS_INTERNAL_ERROR");
+ } else if (errorCode.equals("2")) {
+ return CMS.getUserMessage(locale, "CMS_PROFILE_DEFERRED");
+ } else if (errorCode.equals("3")) {
+ return CMS.getUserMessage(locale, "CMS_PROFILE_REJECTED");
+ }
+ return null;
+ }
+
+ protected String submitRequests(Locale locale, IProfile profile, IAuthToken authToken, IRequest[] reqs) {
+ String auditMessage = null;
+ String auditSubjectID = auditSubjectID();
+ String auditRequesterID = ILogger.UNIDENTIFIED;
+ String auditInfoCertValue = ILogger.SIGNED_AUDIT_EMPTY_VALUE;
+ String errorCode = null;
+ String errorReason = null;
+
+ for (IRequest req : reqs) {
+ try {
+ // reset the "auditRequesterID"
+ auditRequesterID = auditRequesterID(req);
+
+ // print request debug
+ if (req != null) {
+ Enumeration<String> reqKeys = req.getExtDataKeys();
+ while (reqKeys.hasMoreElements()) {
+ String reqKey = reqKeys.nextElement();
+ String reqVal = req.getExtDataInString(reqKey);
+ if (reqVal != null) {
+ CMS.debug("CertRequestSubmitter: key=$request." + reqKey + "$ value=" + reqVal);
+ }
+ }
+ }
+
+ profile.submit(authToken, req);
+ req.setRequestStatus(RequestStatus.COMPLETE);
+
+ // reset the "auditInfoCertValue"
+ auditInfoCertValue = auditInfoCertValue(req);
+
+ if (auditInfoCertValue != null) {
+ if (!(auditInfoCertValue.equals(
+ ILogger.SIGNED_AUDIT_EMPTY_VALUE))) {
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_CERT_REQUEST_PROCESSED,
+ auditSubjectID,
+ ILogger.SUCCESS,
+ auditRequesterID,
+ ILogger.SIGNED_AUDIT_ACCEPTANCE,
+ auditInfoCertValue);
+
+ audit(auditMessage);
+ }
+ }
+ } catch (EDeferException e) {
+ // return defer message to the user
+ req.setRequestStatus(RequestStatus.PENDING);
+ // need to notify
+ INotify notify = profile.getRequestQueue().getPendingNotify();
+ if (notify != null) {
+ notify.notify(req);
+ }
+
+ CMS.debug("CertRequestSubmitter: submit " + e.toString());
+ errorCode = "2";
+ errorReason = CMS.getUserMessage(locale, "CMS_PROFILE_DEFERRED", e.toString());
+
+ // do NOT store a message in the signed audit log file
+ // as this errorCode indicates that a process has been
+ // deferred for manual acceptance/cancellation/rejection
+ } catch (ERejectException e) {
+ // return error to the user
+ req.setRequestStatus(RequestStatus.REJECTED);
+ CMS.debug("CertRequestSubmitter: submit " + e.toString());
+ errorCode = "3";
+ errorReason = CMS.getUserMessage(locale, "CMS_PROFILE_REJECTED", e.toString());
+
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_CERT_REQUEST_PROCESSED,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRequesterID,
+ ILogger.SIGNED_AUDIT_REJECTION,
+ errorReason);
+
+ audit(auditMessage);
+ } catch (Throwable e) {
+ // return error to the user
+ e.printStackTrace();
+ CMS.debug("CertRequestSubmitter: submit " + e.toString());
+ errorCode = "1";
+ errorReason = CMS.getUserMessage(locale, "CMS_INTERNAL_ERROR");
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_CERT_REQUEST_PROCESSED,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRequesterID,
+ ILogger.SIGNED_AUDIT_REJECTION,
+ errorReason);
+
+ audit(auditMessage);
+ }
+
+ try {
+ if (errorCode == null) {
+ profile.getRequestQueue().markAsServiced(req);
+ } else {
+ profile.getRequestQueue().updateRequest(req);
+ }
+ } catch (EBaseException e) {
+ e.printStackTrace();
+ CMS.debug("CertRequestSubmitter: updateRequest " + e.toString());
+ }
+ }
+ return errorCode;
+ }
+
+ protected void populateRequests(EnrollmentRequestData data, boolean isRenewal,
+ Locale locale, Date origNotAfter, String origSubjectDN, IRequest origReq, String profileId,
+ IProfile profile, IProfileContext ctx, IProfileAuthenticator authenticator, IAuthToken authToken,
+ IRequest[] reqs) throws EBaseException {
+ for (IRequest req : reqs) {
+ boolean fromRA = false;
+ String uid = "";
+
+ // adding parameters to request
+ if (isRenewal) {
+ setInputsIntoRequest(origReq, profile, req, locale);
+ req.setExtData("origNotAfter", BigInteger.valueOf(origNotAfter.getTime()));
+ req.setExtData(IProfileAuthenticator.AUTHENTICATED_NAME, origSubjectDN);
+ req.setRequestType("renewal");
+ } else {
+ setInputsIntoRequest(data, profile, req);
+ }
+
+ // serial auth token into request
+ if (authToken != null) {
+ Enumeration<String> tokenNames = authToken.getElements();
+ while (tokenNames.hasMoreElements()) {
+ String tokenName = tokenNames.nextElement();
+ String[] tokenVals = authToken.getInStringArray(tokenName);
+ if (tokenVals != null) {
+ for (int i = 0; i < tokenVals.length; i++) {
+ req.setExtData(ARG_AUTH_TOKEN + "." + tokenName + "[" + i + "]", tokenVals[i]);
+ }
+ } else {
+ String tokenVal = authToken.getInString(tokenName);
+ if (tokenVal != null) {
+ req.setExtData(ARG_AUTH_TOKEN + "." + tokenName, tokenVal);
+ // if RA agent, auto assign the request
+ if (tokenName.equals("uid"))
+ uid = tokenVal;
+ if (tokenName.equals("group") && tokenVal.equals("Registration Manager Agents")) {
+ fromRA = true;
+ }
+ }
+ }
+ }
+ }
+
+ if (fromRA) {
+ CMS.debug("CertRequestSubmitter: request from RA: " + uid);
+ req.setExtData(ARG_REQUEST_OWNER, uid);
+ }
+
+ // put profile framework parameters into the request
+ req.setExtData(ARG_PROFILE, "true");
+ req.setExtData(ARG_PROFILE_ID, profileId);
+ if (isRenewal)
+ req.setExtData(ARG_RENEWAL_PROFILE_ID, data.getProfileId());
+ req.setExtData(ARG_PROFILE_APPROVED_BY, profile.getApprovedBy());
+ String setId = profile.getPolicySetId(req);
+
+ if (setId == null) {
+ // no profile set found
+ CMS.debug("CertRequestSubmitter: no profile policy set found");
+ throw new EBaseException(CMS.getUserMessage(locale, "CMS_PROFILE_NO_POLICY_SET_FOUND"));
+ }
+
+ CMS.debug("CertRequestSubmitter profileSetid=" + setId);
+ req.setExtData(ARG_PROFILE_SET_ID, setId);
+ req.setExtData(ARG_PROFILE_REMOTE_HOST, data.getRemoteHost());
+ req.setExtData(ARG_PROFILE_REMOTE_ADDR, data.getRemoteAddr());
+
+ CMS.debug("CertRequestSubmitter: request " + req.getRequestId().toString());
+
+ CMS.debug("CertRequestSubmitter: populating request inputs");
+ // give authenticator a chance to populate the request
+ if (authenticator != null) {
+ authenticator.populate(authToken, req);
+ }
+ profile.populateInput(ctx, req);
+ profile.populate(req);
+ }
+ }
+
+}
diff --git a/base/common/src/com/netscape/cms/servlet/cert/EnrollmentProcessor.java b/base/common/src/com/netscape/cms/servlet/cert/EnrollmentProcessor.java
new file mode 100644
index 000000000..8b48f0d73
--- /dev/null
+++ b/base/common/src/com/netscape/cms/servlet/cert/EnrollmentProcessor.java
@@ -0,0 +1,205 @@
+// --- 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) 2012 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cms.servlet.cert;
+
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.authentication.IAuthToken;
+import com.netscape.certsrv.base.BadRequestDataException;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.EPropertyNotFound;
+import com.netscape.certsrv.base.SessionContext;
+import com.netscape.certsrv.profile.IProfile;
+import com.netscape.certsrv.profile.IProfileAuthenticator;
+import com.netscape.certsrv.profile.IProfileContext;
+import com.netscape.certsrv.profile.IProfileInput;
+import com.netscape.certsrv.request.IRequest;
+import com.netscape.cms.servlet.common.CMSRequest;
+import com.netscape.cms.servlet.profile.SSLClientCertProvider;
+import com.netscape.cms.servlet.profile.model.ProfileInput;
+import com.netscape.cms.servlet.request.model.EnrollmentRequestData;
+import com.netscape.cms.servlet.request.model.EnrollmentRequestDataFactory;
+
+public class EnrollmentProcessor extends CertProcessor {
+
+ public EnrollmentProcessor(String id, Locale locale) throws EPropertyNotFound, EBaseException {
+ super(id, locale);
+ }
+
+ private void setInputsIntoContext(EnrollmentRequestData data, IProfile profile, IProfileContext ctx) {
+ // put profile inputs into a local map
+ HashMap<String, String> dataInputs = new HashMap<String, String>();
+ for (ProfileInput input : data.getInputs()) {
+ Map<String, String> attrs = input.getAttributes();
+ for (Map.Entry<String, String> entry : attrs.entrySet()) {
+ dataInputs.put(entry.getKey(), entry.getValue());
+ }
+ }
+
+ // iterate through inputs in profile and put those in context
+ Enumeration<String> inputIds = profile.getProfileInputIds();
+ if (inputIds != null) {
+ while (inputIds.hasMoreElements()) {
+ String inputId = inputIds.nextElement();
+ IProfileInput profileInput = profile.getProfileInput(inputId);
+ Enumeration<String> inputNames = profileInput.getValueNames();
+
+ while (inputNames.hasMoreElements()) {
+ String inputName = inputNames.nextElement();
+ if (dataInputs.containsKey(inputName)) {
+ // all subject name parameters start with sn_, no other input parameters do
+ if (inputName.matches("^sn_.*")) {
+ ctx.set(inputName, escapeValueRfc1779(dataInputs.get(inputName), false).toString());
+ } else {
+ ctx.set(inputName, dataInputs.get(inputName));
+ }
+ }
+ }
+ }
+ }
+
+ }
+
+ /**
+ * Called by the legacy servlets to access the Processor function
+ * @param request
+ * @return
+ * @throws EBaseException
+ */
+ public HashMap<String, Object> processEnrollment(CMSRequest cmsReq) throws EBaseException {
+ HttpServletRequest req = cmsReq.getHttpReq();
+ String profileId = (this.profileID == null) ? req.getParameter("profileId") : this.profileID;
+ IProfile profile = ps.getProfile(profileId);
+
+ if (profile == null) {
+ CMS.debug(CMS.getUserMessage(locale, "CMS_PROFILE_NOT_FOUND", profileId));
+ throw new BadRequestDataException(CMS.getUserMessage(locale, "CMS_PROFILE_NOT_FOUND", profileId));
+ }
+
+ EnrollmentRequestData data = EnrollmentRequestDataFactory.create(cmsReq, profile, locale);
+ return processEnrollment(data, cmsReq.getHttpReq());
+ }
+
+ /**
+ * Process the HTTP request
+ * <P>
+ *
+ * (Certificate Request Processed - either an automated "EE" profile based cert acceptance, or an automated "EE"
+ * profile based cert rejection)
+ * <P>
+ *
+ * <ul>
+ * <li>http.param profileId ID of profile to use to process request
+ * <li>signed.audit LOGGING_SIGNED_AUDIT_CERT_REQUEST_PROCESSED used when a certificate request has just been
+ * through the approval process
+ * </ul>
+ *
+ * @param cmsReq the object holding the request and response information
+ * @exception EBaseException an error has occurred
+ */
+ public HashMap<String, Object> processEnrollment(EnrollmentRequestData data, HttpServletRequest request)
+ throws EBaseException {
+
+ try {
+ if (CMS.debugOn()) {
+ HashMap<String,String> params = data.toParams();
+ printParameterValues(params);
+ }
+
+ CMS.debug("EnrollmentSubmitter: isRenewal false");
+ startTiming("enrollment");
+
+ // if we did not configure profileId in xml file,
+ // then accept the user-provided one
+ String profileId = (this.profileID == null) ? data.getProfileId() : this.profileID;
+ CMS.debug("EnrollmentSubmitter: profileId " + profileId);
+
+ IProfile profile = ps.getProfile(profileId);
+ if (profile == null) {
+ CMS.debug(CMS.getUserMessage(locale, "CMS_PROFILE_NOT_FOUND", profileId));
+ throw new BadRequestDataException(CMS.getUserMessage(locale, "CMS_PROFILE_NOT_FOUND", profileId));
+ }
+ if (!ps.isProfileEnable(profileId)) {
+ CMS.debug("EnrollmentSubmitter: Profile " + profileId + " not enabled");
+ throw new BadRequestDataException("Profile " + profileId + " not enabled");
+ }
+
+ IProfileContext ctx = profile.createContext();
+ CMS.debug("EnrollmentSubmitter: set Inputs into profile Context");
+ setInputsIntoContext(data, profile, ctx);
+
+ IProfileAuthenticator authenticator = profile.getAuthenticator();
+ if (authenticator != null) {
+ CMS.debug("EnrollmentSubmitter: authenticator " + authenticator.getName() + " found");
+ setCredentialsIntoContext(request, authenticator, ctx);
+ }
+
+ // for ssl authentication; pass in servlet for retrieving ssl client certificates
+ // insert profile context so that input parameter can be retrieved
+ SessionContext context = SessionContext.getContext();
+ context.put("profileContext", ctx);
+ context.put("sslClientCertProvider", new SSLClientCertProvider(request));
+ CMS.debug("EnrollmentSubmitter: set sslClientCertProvider");
+
+ // before creating the request, authenticate the request
+ IAuthToken authToken = authenticate(request, null, authenticator, context, false);
+
+ // authentication success, now authorize
+ authorize(profileId, profile, authToken);
+
+ ///////////////////////////////////////////////
+ // create and populate request
+ ///////////////////////////////////////////////
+ startTiming("request_population");
+ IRequest[] reqs = profile.createRequests(ctx, locale);
+ populateRequests(data, false, locale, null, null, null, profileId, profile,
+ ctx, authenticator, authToken, reqs);
+ endTiming("request_population");
+
+ ///////////////////////////////////////////////
+ // submit request
+ ///////////////////////////////////////////////
+ String errorCode = submitRequests(locale, profile, authToken, reqs);
+ String errorReason = codeToReason(locale, errorCode);
+
+ HashMap<String, Object> ret = new HashMap<String, Object>();
+ ret.put(ARG_REQUESTS, reqs);
+ ret.put(ARG_ERROR_CODE, errorCode);
+ ret.put(ARG_ERROR_REASON, errorReason);
+ ret.put(ARG_PROFILE, profile);
+
+ CMS.debug("EnrollmentSubmitter: done serving");
+ endTiming("enrollment");
+
+ return ret;
+ } finally {
+ SessionContext.releaseContext();
+ endAllEvents();
+ }
+ }
+
+
+
+
+}
diff --git a/base/common/src/com/netscape/cms/servlet/cert/RenewalProcessor.java b/base/common/src/com/netscape/cms/servlet/cert/RenewalProcessor.java
new file mode 100644
index 000000000..cc4dd12ae
--- /dev/null
+++ b/base/common/src/com/netscape/cms/servlet/cert/RenewalProcessor.java
@@ -0,0 +1,345 @@
+// --- 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) 2012 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cms.servlet.cert;
+
+import java.math.BigInteger;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Locale;
+
+import javax.servlet.http.HttpServletRequest;
+
+import netscape.security.x509.BasicConstraintsExtension;
+import netscape.security.x509.X509CertImpl;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.authentication.IAuthToken;
+import com.netscape.certsrv.base.BadRequestDataException;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.EPropertyNotFound;
+import com.netscape.certsrv.base.SessionContext;
+import com.netscape.certsrv.dbs.certdb.ICertRecord;
+import com.netscape.certsrv.profile.IEnrollProfile;
+import com.netscape.certsrv.profile.IProfile;
+import com.netscape.certsrv.profile.IProfileAuthenticator;
+import com.netscape.certsrv.profile.IProfileContext;
+import com.netscape.certsrv.profile.IProfileInput;
+import com.netscape.certsrv.request.IRequest;
+import com.netscape.cms.servlet.common.CMSRequest;
+import com.netscape.cms.servlet.profile.SSLClientCertProvider;
+import com.netscape.cms.servlet.request.model.EnrollmentRequestData;
+import com.netscape.cms.servlet.request.model.EnrollmentRequestDataFactory;
+
+public class RenewalProcessor extends CertProcessor {
+
+ public RenewalProcessor(String id, Locale locale) throws EPropertyNotFound, EBaseException {
+ super(id, locale);
+ }
+
+ public HashMap<String, Object> processRenewal(CMSRequest cmsReq) throws EBaseException {
+ HttpServletRequest req = cmsReq.getHttpReq();
+ String profileId = (this.profileID == null) ? req.getParameter("profileId") : this.profileID;
+ IProfile profile = ps.getProfile(profileId);
+ if (profile == null) {
+ throw new BadRequestDataException(CMS.getUserMessage(locale, "CMS_PROFILE_NOT_FOUND", profileId));
+ }
+
+ EnrollmentRequestData data = EnrollmentRequestDataFactory.create(cmsReq, profile, locale);
+
+ //only used in renewal
+ data.setSerialNum(req.getParameter("serial_num"));
+
+ return processRenewal(data, req);
+ }
+
+ /*
+ * Renewal - Renewal is retrofitted into the Profile Enrollment
+ * Framework. The authentication and authorization are taken from
+ * the renewal profile, while the input (with requests) and grace
+ * period constraint are taken from the original cert's request record.
+ *
+ * Things to note:
+ * * the renew request will contain the original profile instead of the new
+ */
+ public HashMap<String, Object> processRenewal(EnrollmentRequestData data, HttpServletRequest request)
+ throws EBaseException {
+ try {
+ if (CMS.debugOn()) {
+ HashMap<String,String> params = data.toParams();
+ printParameterValues(params);
+ }
+ CMS.debug("RenewalSubmitter: isRenewal true");
+
+ startTiming("enrollment");
+ request.setAttribute("reqType", "renewal");
+
+ // in case of renew, "profile" is the orig profile
+ // while "renewProfile" is the current profile used for renewal
+ String renewProfileId = (this.profileID == null) ? data.getProfileId() : this.profileID;
+ CMS.debug("processRenewal: renewProfileId " + renewProfileId);
+
+ IProfile renewProfile = ps.getProfile(renewProfileId);
+ if (renewProfile == null) {
+ CMS.debug(CMS.getUserMessage(locale, "CMS_PROFILE_NOT_FOUND", renewProfileId));
+ throw new BadRequestDataException(CMS.getUserMessage(locale, "CMS_PROFILE_NOT_FOUND", renewProfileId));
+ }
+ if (!ps.isProfileEnable(renewProfileId)) {
+ CMS.debug("RenewalSubmitter: Profile " + renewProfileId + " not enabled");
+ throw new BadRequestDataException("Profile " + renewProfileId + " not enabled");
+ }
+
+ String serial = data.getSerialNum();
+ BigInteger certSerial = null;
+
+ if (serial != null) {
+ // if serial number is sent with request, then the authentication
+ // method is not ssl client auth. In this case, an alternative
+ // authentication method is used (default: ldap based)
+ // usr_origreq evaluator should be used to authorize ownership
+ // of the cert
+ CMS.debug("RenewalSubmitter: renewal: found serial_num");
+ certSerial = new BigInteger(serial);
+ } else {
+ // ssl client auth is to be used
+ // this is not authentication. Just use the cert to search
+ // for orig request and find the right profile
+ CMS.debug("RenewalSubmitter: renewal: serial_num not found, must do ssl client auth");
+ certSerial = getSerialNumberFromCert(request);
+ if (certSerial == null) {
+ CMS.debug(CMS.getUserMessage(locale, "CMS_INTERNAL_ERROR"));
+ throw new EBaseException(CMS.getUserMessage(locale, "CMS_INTERNAL_ERROR"));
+ }
+ }
+ CMS.debug("processRenewal: serial number of cert to renew:" + certSerial.toString());
+ ICertRecord rec = certdb.readCertificateRecord(certSerial);
+ if (rec == null) {
+ CMS.debug("processRenewal: cert record not found for serial number " + certSerial.toString());
+ throw new EBaseException(CMS.getUserMessage(locale, "CMS_INTERNAL_ERROR"));
+ }
+
+ // check to see if the cert is revoked or revoked_expired
+ if ((rec.getStatus().equals(ICertRecord.STATUS_REVOKED))
+ || (rec.getStatus().equals(ICertRecord.STATUS_REVOKED_EXPIRED))) {
+ CMS.debug("processRenewal: cert found to be revoked. Serial number = "
+ + certSerial.toString());
+ throw new BadRequestDataException(CMS.getUserMessage(locale, "CMS_CA_CANNOT_RENEW_REVOKED_CERT"));
+ }
+
+ X509CertImpl origCert = rec.getCertificate();
+ if (origCert == null) {
+ CMS.debug("processRenewal: original cert not found in cert record for serial number "
+ + certSerial.toString());
+ throw new EBaseException(CMS.getUserMessage(locale, "CMS_INTERNAL_ERROR"));
+ }
+
+ Date origNotAfter = origCert.getNotAfter();
+ CMS.debug("processRenewal: origNotAfter =" + origNotAfter.toString());
+
+ String origSubjectDN = origCert.getSubjectDN().getName();
+ CMS.debug("processRenewal: orig subj dn =" + origSubjectDN);
+
+ IRequest origReq = getOriginalRequest(certSerial, rec);
+ if (origReq == null) {
+ CMS.debug("processRenewal: original request not found");
+ throw new EBaseException(CMS.getUserMessage(locale, "CMS_INTERNAL_ERROR"));
+ }
+
+ String profileId = origReq.getExtDataInString("profileId");
+ CMS.debug("RenewalSubmitter: renewal original profileId=" + profileId);
+
+ Integer origSeqNum = origReq.getExtDataInInteger(IEnrollProfile.REQUEST_SEQ_NUM);
+ IProfile profile = ps.getProfile(profileId);
+ if (profile == null) {
+ CMS.debug(CMS.getUserMessage(locale, "CMS_PROFILE_NOT_FOUND", profileId));
+ throw new EBaseException(CMS.getUserMessage(locale, "CMS_PROFILE_NOT_FOUND", profileId));
+ }
+ if (!ps.isProfileEnable(profileId)) {
+ CMS.debug("RenewalSubmitter: Profile " + profileId + " not enabled");
+ throw new BadRequestDataException("Profile " + profileId + " not enabled");
+ }
+
+ IProfileContext ctx = profile.createContext();
+ IProfileAuthenticator authenticator = renewProfile.getAuthenticator();
+ IProfileAuthenticator origAuthenticator = profile.getAuthenticator();
+
+ if (authenticator != null) {
+ CMS.debug("RenewalSubmitter: authenticator " + authenticator.getName() + " found");
+ setCredentialsIntoContext(request, authenticator, ctx);
+ }
+
+ // for renewal, this will override or add auth info to the profile context
+ if (origAuthenticator != null) {
+ CMS.debug("RenewalSubmitter: for renewal, original authenticator " +
+ origAuthenticator.getName() + " found");
+ setCredentialsIntoContext(request, origAuthenticator, ctx);
+ }
+
+ // for renewal, input needs to be retrieved from the orig req record
+ CMS.debug("processRenewal: set original Inputs into profile Context");
+ setInputsIntoContext(origReq, profile, ctx, locale);
+ ctx.set(IEnrollProfile.CTX_RENEWAL, "true");
+ ctx.set("renewProfileId", renewProfileId);
+ ctx.set(IEnrollProfile.CTX_RENEWAL_SEQ_NUM, origSeqNum.toString());
+
+ // for ssl authentication; pass in servlet for retrieving
+ // ssl client certificates
+ SessionContext context = SessionContext.getContext();
+ context.put("profileContext", ctx);
+ context.put("sslClientCertProvider", new SSLClientCertProvider(request));
+ CMS.debug("RenewalSubmitter: set sslClientCertProvider");
+ if (origSubjectDN != null)
+ context.put("origSubjectDN", origSubjectDN);
+
+ // before creating the request, authenticate the request
+ IAuthToken authToken = authenticate(request, origReq, authenticator, context, true);
+
+ // authentication success, now authorize
+ authorize(profileId, renewProfile, authToken);
+
+ ///////////////////////////////////////////////
+ // create and populate requests
+ ///////////////////////////////////////////////
+ startTiming("request_population");
+ IRequest[] reqs = profile.createRequests(ctx, locale);
+ populateRequests(data, true, locale, origNotAfter, origSubjectDN, origReq, profileId,
+ profile, ctx, authenticator, authToken, reqs);
+ endTiming("request_population");
+
+ ///////////////////////////////////////////////
+ // submit request
+ ///////////////////////////////////////////////
+ String errorCode = submitRequests(locale, profile, authToken, reqs);
+ String errorReason = codeToReason(locale, errorCode);
+
+ HashMap<String, Object> ret = new HashMap<String, Object>();
+ ret.put(ARG_REQUESTS, reqs);
+ ret.put(ARG_ERROR_CODE, errorCode);
+ ret.put(ARG_ERROR_REASON, errorReason);
+ ret.put(ARG_PROFILE, profile);
+
+ CMS.debug("RenewalSubmitter: done serving");
+ endTiming("enrollment");
+
+ return ret;
+ } finally {
+ SessionContext.releaseContext();
+ endAllEvents();
+ }
+ }
+
+ private BigInteger getSerialNumberFromCert(HttpServletRequest request) throws EBaseException {
+ BigInteger certSerial;
+ SSLClientCertProvider sslCCP = new SSLClientCertProvider(request);
+ X509Certificate[] certs = sslCCP.getClientCertificateChain();
+ certSerial = null;
+ if (certs == null || certs.length == 0) {
+ CMS.debug("RenewalSubmitter: renewal: no ssl client cert chain");
+ return null;
+ } else { // has ssl client cert
+ CMS.debug("RenewalSubmitter: renewal: has ssl client cert chain");
+ // shouldn't expect leaf cert to be always at the
+ // same location
+ X509Certificate clientCert = null;
+ for (int i = 0; i < certs.length; i++) {
+ clientCert = certs[i];
+ byte[] extBytes = clientCert.getExtensionValue("2.5.29.19");
+ // try to see if this is a leaf cert
+ // look for BasicConstraint extension
+ if (extBytes == null) {
+ // found leaf cert
+ CMS.debug("RenewalSubmitter: renewal: found leaf cert");
+ break;
+ } else {
+ CMS.debug("RenewalSubmitter: renewal: found cert having BasicConstraints ext");
+ // it's got BasicConstraints extension
+ // so it's not likely to be a leaf cert,
+ // however, check the isCA field regardless
+ try {
+ BasicConstraintsExtension bce =
+ new BasicConstraintsExtension(true, extBytes);
+ if (bce != null) {
+ if (!(Boolean) bce.get("is_ca")) {
+ CMS.debug("RenewalSubmitter: renewal: found CA cert in chain");
+ break;
+ } // else found a ca cert, continue
+ }
+ } catch (Exception e) {
+ CMS.debug("RenewalSubmitter: renewal: exception:" + e.toString());
+ return null;
+ }
+ }
+ }
+ if (clientCert == null) {
+ CMS.debug("RenewalSubmitter: renewal: no client cert in chain");
+ return null;
+ }
+ // convert to java X509 cert interface
+ try {
+ byte[] certEncoded = clientCert.getEncoded();
+ clientCert = new X509CertImpl(certEncoded);
+ } catch (Exception e) {
+ e.printStackTrace();
+ CMS.debug("RenewalSubmitter: renewal: exception:" + e.toString());
+ return null;
+ }
+
+ certSerial = clientCert.getSerialNumber();
+ }
+ return certSerial;
+ }
+
+ /*
+ * fill input info from "request" to context.
+ * This is expected to be used by renewal where the request
+ * is retrieved from request record
+ */
+ private void setInputsIntoContext(IRequest request, IProfile profile, IProfileContext ctx, Locale locale) {
+ // passing inputs into context
+ Enumeration<String> inputIds = profile.getProfileInputIds();
+
+ if (inputIds != null) {
+ while (inputIds.hasMoreElements()) {
+ String inputId = inputIds.nextElement();
+ IProfileInput profileInput = profile.getProfileInput(inputId);
+ Enumeration<String> inputNames = profileInput.getValueNames();
+
+ while (inputNames.hasMoreElements()) {
+ String inputName = inputNames.nextElement();
+ String inputValue = "";
+ CMS.debug("RenewalSubmitter: setInputsIntoContext() getting input name= " + inputName);
+ try {
+ inputValue = profileInput.getValue(inputName, locale, request);
+ } catch (Exception e) {
+ CMS.debug("RenewalSubmitter: setInputsIntoContext() getvalue() failed: " + e.toString());
+ }
+
+ if (inputValue != null) {
+ CMS.debug("RenewalSubmitter: setInputsIntoContext() setting value in ctx:" + inputValue);
+ ctx.set(inputName, inputValue);
+ } else {
+ CMS.debug("RenewalSubmitter: setInputsIntoContext() value null");
+ }
+ }
+ }
+ }
+
+ }
+
+}
diff --git a/base/common/src/com/netscape/cms/servlet/cert/RequestProcessor.java b/base/common/src/com/netscape/cms/servlet/cert/RequestProcessor.java
new file mode 100644
index 000000000..9bb0c4b64
--- /dev/null
+++ b/base/common/src/com/netscape/cms/servlet/cert/RequestProcessor.java
@@ -0,0 +1,475 @@
+// --- 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) 2012 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cms.servlet.cert;
+
+import java.security.cert.X509Certificate;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+
+import javax.servlet.http.HttpServletRequest;
+
+import netscape.security.x509.X509CertImpl;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.authentication.IAuthToken;
+import com.netscape.certsrv.authorization.AuthzToken;
+import com.netscape.certsrv.authorization.EAuthzException;
+import com.netscape.certsrv.base.BadRequestDataException;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.EPropertyNotFound;
+import com.netscape.certsrv.base.IConfigStore;
+import com.netscape.certsrv.logging.ILogger;
+import com.netscape.certsrv.profile.EDeferException;
+import com.netscape.certsrv.profile.EProfileException;
+import com.netscape.certsrv.profile.ERejectException;
+import com.netscape.certsrv.profile.IEnrollProfile;
+import com.netscape.certsrv.profile.IPolicyConstraint;
+import com.netscape.certsrv.profile.IPolicyDefault;
+import com.netscape.certsrv.profile.IProfile;
+import com.netscape.certsrv.profile.IProfileOutput;
+import com.netscape.certsrv.profile.IProfilePolicy;
+import com.netscape.certsrv.property.EPropertyException;
+import com.netscape.certsrv.request.IRequest;
+import com.netscape.certsrv.request.RequestId;
+import com.netscape.certsrv.request.RequestStatus;
+import com.netscape.cms.profile.common.ProfilePolicy;
+import com.netscape.cms.servlet.common.CMSRequest;
+import com.netscape.cms.servlet.profile.model.PolicyDefault;
+import com.netscape.cms.servlet.profile.model.ProfileAttribute;
+import com.netscape.cms.servlet.profile.model.ProfileOutput;
+import com.netscape.cms.servlet.profile.model.ProfileOutputFactory;
+import com.netscape.cms.servlet.profile.model.ProfilePolicySet;
+import com.netscape.cms.servlet.request.model.AgentEnrollmentRequestData;
+import com.netscape.cms.servlet.request.model.AgentEnrollmentRequestDataFactory;
+
+public class RequestProcessor extends CertProcessor {
+
+ public RequestProcessor(String id, Locale locale) throws EPropertyNotFound, EBaseException {
+ super(id, locale);
+ }
+
+ public AgentEnrollmentRequestData processRequest(CMSRequest cmsReq, IRequest request, String op) throws EBaseException {
+ HttpServletRequest req = cmsReq.getHttpReq();
+ IRequest ireq = cmsReq.getIRequest();
+
+ String profileId = ireq.getExtDataInString("profileId");
+ IProfile profile = ps.getProfile(profileId);
+ AgentEnrollmentRequestData data = AgentEnrollmentRequestDataFactory.create(cmsReq, profile, nonces, locale);
+
+ processRequest(req, data, request, op);
+ return data;
+ }
+
+ public void processRequest(HttpServletRequest request, AgentEnrollmentRequestData data, IRequest req, String op)
+ throws EBaseException {
+ try {
+
+ startTiming("approval");
+
+ IAuthToken authToken = null;
+
+ if (CMS.debugOn()) {
+ HashMap<String, String> params = data.toParams();
+ printParameterValues(params);
+ CMS.debug("processRequest op is " + op);
+ }
+
+ if (authMgr != null) {
+ authToken = authenticate(request);
+ }
+
+ AuthzToken authzToken = authorize(aclMethod, authToken, authzResourceName, "approve");
+ if (authzToken == null) {
+ throw new EAuthzException(CMS.getUserMessage(locale, "CMS_AUTHORIZATION_ERROR"));
+ }
+
+ if (nonces != null) {
+ String requestNonce = data.getNonce();
+ boolean nonceVerified = false;
+ if (requestNonce != null) {
+ long nonce = Long.parseLong(requestNonce.trim());
+ X509Certificate cert1 = nonces.getCertificate(nonce);
+ X509Certificate cert2 = getSSLClientCertificate(request);
+ if (cert1 == null) {
+ CMS.debug("CertRequestExecutor: Unknown nonce");
+ } else if (cert1 != null && cert2 != null && cert1.equals(cert2)) {
+ nonceVerified = true;
+ nonces.removeNonce(nonce);
+ }
+ } else {
+ CMS.debug("CertRequestExecutor: Missing nonce");
+ }
+ CMS.debug("CertRequestExecutor: nonceVerified=" + nonceVerified);
+ if (!nonceVerified) {
+ CMS.debug("nonce not verified");
+ throw new EAuthzException(CMS.getUserMessage(locale, "CMS_AUTHORIZATION_ERROR"));
+ }
+ }
+
+ CMS.debug("CertRequestExecutor: processRequest: start serving");
+
+ RequestId requestId = data.getRequestId();
+ if (requestId == null || requestId.equals("")) {
+ CMS.debug(CMS.getUserMessage(locale, "CMS_REQUEST_ID_NOT_FOUND"));
+ throw new BadRequestDataException(CMS.getUserMessage(locale, "CMS_REQUEST_ID_NOT_FOUND"));
+ }
+ CMS.debug("CertRequestExecutor: requestId=" + requestId);
+
+ // check if the request is in one of the terminal states
+ if (!req.getRequestStatus().equals(RequestStatus.PENDING)) {
+ CMS.debug(CMS.getUserMessage(locale, "CMS_REQUEST_NOT_PENDING", requestId.toString()));
+ throw new BadRequestDataException(CMS.getUserMessage(locale, "CMS_REQUEST_NOT_PENDING",
+ requestId.toString()));
+ }
+
+ // save auth token in request
+ saveAuthToken(authToken, req);
+
+ String profileId = req.getExtDataInString("profileId");
+ if (profileId == null || profileId.equals("")) {
+ CMS.debug("CertRequestExecutor: Profile Id not found in request");
+ throw new EBaseException(CMS.getUserMessage(locale, "CMS_PROFILE_ID_NOT_FOUND"));
+ }
+ CMS.debug("CertRequestExecutor: profileId=" + profileId);
+
+ IProfile profile = ps.getProfile(profileId);
+ if (profile == null) {
+ CMS.debug(CMS.getUserMessage(locale, "CMS_PROFILE_NOT_FOUND", profileId));
+ throw new BadRequestDataException(CMS.getUserMessage(locale, "CMS_PROFILE_NOT_FOUND", profileId));
+ }
+ if (!ps.isProfileEnable(profileId)) {
+ CMS.debug("CertRequestExecutor: Profile " + profileId + " not enabled");
+ throw new BadRequestDataException("Profile " + profileId + " not enabled");
+ }
+
+ if (op.equals("assign")) {
+ String owner = req.getRequestOwner();
+
+ // assigned owner
+ if (owner != null && owner.length() > 0) {
+ if (!grantPermission(req, authToken)) {
+ CMS.debug("CertRequestExecutor: Permission not granted to assign request.");
+ throw new EAuthzException(CMS.getUserMessage(locale, "CMS_PROFILE_DENY_OPERATION"));
+ }
+ }
+ String id = auditSubjectID();
+ req.setRequestOwner(id);
+ } else {
+ if (grantPermission(req, authToken)) {
+ if (op.equals("approve")) {
+ checkProfileVersion(profile, req);
+ updateValues(data, req, profile, locale);
+ updateNotes(data, req);
+ approveRequest(req, data, profile, locale);
+ } else if (op.equals("reject")) {
+ updateNotes(data, req);
+ rejectRequest(req);
+ } else if (op.equals("cancel")) {
+ updateNotes(data, req);
+ cancelRequest(req);
+ } else if (op.equals("update")) {
+ checkProfileVersion(profile, req);
+ updateValues(data, req, profile, locale);
+ updateNotes(data, req);
+ } else if (op.equals("validate")) {
+ updateValues(data, req, profile, locale);
+ } else if (op.equals("unassign")) {
+ req.setRequestOwner("");
+ }
+ } else {
+ CMS.debug("CertRequestExecutor: Permission not granted to approve/reject/cancel/update/validate/unassign request.");
+ throw new EAuthzException(CMS.getUserMessage(locale, "CMS_PROFILE_DENY_OPERATION"));
+ }
+ }
+
+ // commit request to the storage
+ if (!op.equals("validate")) {
+ if (op.equals("approve")) {
+ queue.markAsServiced(req);
+ } else {
+ queue.updateRequest(req);
+ }
+ }
+ endTiming("approval");
+ } finally {
+ endAllEvents();
+ }
+ }
+
+ private boolean grantPermission(IRequest req, IAuthToken token) {
+ boolean enable = false;
+ try {
+ enable = CMS.getConfigStore().getBoolean("request.assignee.enable", false);
+ } catch (EBaseException e) {
+ }
+
+ if (!enable)
+ return true;
+ String owner = req.getRequestOwner();
+
+ // unassigned owner
+ if (owner == null || owner.length() == 0)
+ return true;
+ String uid = token.getInString(IAuthToken.USER_ID);
+ if (uid.equals(owner))
+ return true;
+
+ return false;
+ }
+
+ /**
+ * Check if the request creation time is older than the profile
+ * lastModified attribute.
+ */
+ private void checkProfileVersion(IProfile profile, IRequest req) throws EProfileException {
+ IConfigStore profileConfig = profile.getConfigStore();
+ if (profileConfig != null) {
+ String lastModified = null;
+
+ try {
+ lastModified = profileConfig.getString("lastModified", "");
+ } catch (EBaseException e) {
+ }
+
+ if (!lastModified.equals("")) {
+ Date profileModifiedAt = new Date(Long.parseLong(lastModified));
+ CMS.debug("CertRequestExecutor: Profile Last Modified=" +
+ profileModifiedAt);
+ Date reqCreatedAt = req.getCreationTime();
+ CMS.debug("CertRequestExecutor: Request Created At=" +
+ reqCreatedAt);
+ if (profileModifiedAt.after(reqCreatedAt)) {
+ CMS.debug("Profile Newer Than Request");
+ throw new ERejectException("Profile Newer Than Request");
+ }
+ }
+ }
+ }
+
+ /**
+ * Cancel request
+ * <P>
+ *
+ * (Certificate Request Processed - a manual "agent" profile based cert cancellation)
+ * <P>
+ *
+ * <ul>
+ * <li>signed.audit LOGGING_SIGNED_AUDIT_CERT_REQUEST_PROCESSED used when a certificate request has just been
+ * through the approval process
+ * </ul>
+ *
+ *
+ * @param req the certificate request
+ * @exception EProfileException an error related to this profile has
+ * occurred
+ */
+ private void cancelRequest(IRequest req) throws EProfileException {
+ String auditMessage = null;
+ String auditSubjectID = auditSubjectID();
+ String auditRequesterID = auditRequesterID(req);
+ String auditInfoValue = auditInfoValue(req);
+
+ req.setRequestStatus(RequestStatus.CANCELED);
+
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_CERT_REQUEST_PROCESSED,
+ auditSubjectID,
+ ILogger.SUCCESS,
+ auditRequesterID,
+ ILogger.SIGNED_AUDIT_CANCELLATION,
+ auditInfoValue);
+
+ audit(auditMessage);
+ }
+
+ /**
+ * Reject request
+ * <P>
+ *
+ * (Certificate Request Processed - a manual "agent" profile based cert rejection)
+ * <P>
+ *
+ * <ul>
+ * <li>signed.audit LOGGING_SIGNED_AUDIT_CERT_REQUEST_PROCESSED used when a certificate request has just been
+ * through the approval process
+ * </ul>
+ *
+ * @param req the certificate request
+ * @exception EProfileException an error related to this profile has
+ * occurred
+ */
+ private void rejectRequest(IRequest req) throws EProfileException {
+ String auditMessage = null;
+ String auditSubjectID = auditSubjectID();
+ String auditRequesterID = auditRequesterID(req);
+ String auditInfoValue = auditInfoValue(req);
+
+ req.setRequestStatus(RequestStatus.REJECTED);
+
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_CERT_REQUEST_PROCESSED,
+ auditSubjectID,
+ ILogger.SUCCESS,
+ auditRequesterID,
+ ILogger.SIGNED_AUDIT_REJECTION,
+ auditInfoValue);
+
+ audit(auditMessage);
+ }
+
+ /**
+ * Approve request
+ * <P>
+ *
+ * (Certificate Request Processed - a manual "agent" profile based cert acceptance)
+ * <P>
+ *
+ * <ul>
+ * <li>signed.audit LOGGING_SIGNED_AUDIT_CERT_REQUEST_PROCESSED used when a certificate request has just been
+ * through the approval process
+ * </ul>
+ *
+ * @param request the servlet request
+ * @param req the certificate request
+ * @param profile this profile
+ * @param locale the system locale
+ * @exception EProfileException an error related to this profile has
+ * occurred
+ */
+ private void approveRequest(IRequest req, AgentEnrollmentRequestData data, IProfile profile, Locale locale)
+ throws EProfileException {
+ String auditMessage = null;
+ String auditSubjectID = auditSubjectID();
+ String auditRequesterID = auditRequesterID(req);
+
+ try {
+ profile.execute(req);
+ req.setRequestStatus(RequestStatus.COMPLETE);
+
+ Enumeration<String> outputIds = profile.getProfileOutputIds();
+ while (outputIds.hasMoreElements()) {
+ IProfileOutput output = profile.getProfileOutput(outputIds.nextElement());
+ ProfileOutput addOutput = ProfileOutputFactory.create(output, req, locale);
+ data.addOutput(addOutput);
+ }
+
+ // retrieve the certificate
+ X509CertImpl theCert = req.getExtDataInCert(
+ IEnrollProfile.REQUEST_ISSUED_CERT);
+
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_CERT_REQUEST_PROCESSED,
+ auditSubjectID,
+ ILogger.SUCCESS,
+ auditRequesterID,
+ ILogger.SIGNED_AUDIT_ACCEPTANCE,
+ auditInfoCertValue(theCert));
+
+ audit(auditMessage);
+
+ } catch (EProfileException eAudit1) {
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_CERT_REQUEST_PROCESSED,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditRequesterID,
+ ILogger.SIGNED_AUDIT_ACCEPTANCE,
+ ILogger.SIGNED_AUDIT_EMPTY_VALUE);
+
+ audit(auditMessage);
+
+ CMS.debug("CertRequestExecutor: about to throw EProfileException because of bad profile execute.");
+ throw eAudit1;
+ }
+ }
+
+ private void updateValues(AgentEnrollmentRequestData data, IRequest req,
+ IProfile profile, Locale locale)
+ throws ERejectException, EDeferException, EPropertyException {
+
+ // put request policy defaults in a local hash
+ HashMap<String, String> policyData = new HashMap<String,String>();
+ for (ProfilePolicySet policySet: data.getPolicySets()) {
+ for (com.netscape.cms.servlet.profile.model.ProfilePolicy policy: policySet.getPolicies()) {
+ PolicyDefault def = policy.getDef();
+ List<ProfileAttribute> attrs = def.getAttributes();
+ for (ProfileAttribute attr: attrs) {
+ policyData.put(attr.getName(), attr.getValue());
+ }
+ }
+ }
+
+ String profileSetId = req.getExtDataInString("profileSetId");
+
+ Enumeration<ProfilePolicy> policies = profile.getProfilePolicies(profileSetId);
+ int count = 0;
+
+ while (policies.hasMoreElements()) {
+ ProfilePolicy policy = policies.nextElement();
+
+ setValue(locale, count, policy, req, policyData);
+ count++;
+ }
+
+ policies = profile.getProfilePolicies(profileSetId);
+ count = 0;
+ while (policies.hasMoreElements()) {
+ ProfilePolicy policy = policies.nextElement();
+
+ validate(count, policy, req);
+ count++;
+ }
+
+ }
+
+ private void updateNotes(AgentEnrollmentRequestData data, IRequest req) {
+ String notes = data.getRequestNotes();
+
+ if (notes != null) {
+ req.setExtData("requestNotes", notes);
+ }
+ }
+
+ private void validate(int count, IProfilePolicy policy, IRequest req)
+ throws ERejectException, EDeferException {
+ IPolicyConstraint con = policy.getConstraint();
+
+ con.validate(req);
+ }
+
+ private void setValue(Locale locale, int count, IProfilePolicy policy, IRequest req,
+ HashMap<String, String> data) throws EPropertyException {
+ // handle default policy
+ IPolicyDefault def = policy.getDefault();
+ Enumeration<String> defNames = def.getValueNames();
+
+ while (defNames.hasMoreElements()) {
+ String defName = defNames.nextElement();
+ String defValue = data.get(defName);
+
+ def.setValue(defName, locale, req, defValue);
+ }
+ }
+}