package com.netscape.cms.servlet.profile; import java.math.BigInteger; import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Date; import java.util.Enumeration; import java.util.LinkedHashSet; import java.util.Locale; import java.util.StringTokenizer; import javax.servlet.ServletConfig; import javax.servlet.ServletException; 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.authority.IAuthority; import com.netscape.certsrv.base.EBaseException; import com.netscape.certsrv.base.MetaInfo; import com.netscape.certsrv.base.SessionContext; import com.netscape.certsrv.dbs.certdb.ICertRecord; 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.IProfile; import com.netscape.certsrv.profile.IProfileAuthenticator; import com.netscape.certsrv.profile.IProfileContext; import com.netscape.certsrv.profile.IProfileInput; import com.netscape.certsrv.profile.IProfileSubsystem; import com.netscape.certsrv.request.INotify; import com.netscape.certsrv.request.IRequest; import com.netscape.certsrv.request.IRequestQueue; import com.netscape.certsrv.request.RequestId; import com.netscape.certsrv.request.RequestStatus; import com.netscape.certsrv.util.IStatsSubsystem; import com.netscape.cms.servlet.common.AuthCredentials; import com.netscape.cms.servlet.request.model.EnrollmentRequestData; import com.netscape.cmsutil.util.Utils; public class ProfileSubmitServlet2 extends ProfileServlet { /** * */ private static final long serialVersionUID = 7557922703180866442L; private static final String ARG_AUTH_TOKEN = "auth_token"; private static final String ARG_REQUEST_OWNER = "requestOwner"; private static final String PROP_PROFILE_ID = "profileId"; private static final String PROP_AUTHORITY_ID = "authorityId"; private String mProfileId = null; private String mProfileSubId = null; private String mAuthorityId = null; // stats private LinkedHashSet statEvents = null; private final static String LOGGING_SIGNED_AUDIT_CERT_REQUEST_PROCESSED = "LOGGING_SIGNED_AUDIT_CERT_REQUEST_PROCESSED_5"; private final static String LOGGING_SIGNED_AUDIT_AUTH_FAIL = "LOGGING_SIGNED_AUDIT_AUTH_FAIL_4"; private final static String LOGGING_SIGNED_AUDIT_AUTH_SUCCESS = "LOGGING_SIGNED_AUDIT_AUTH_SUCCESS_3"; public ProfileSubmitServlet2() { } /** * initialize the servlet. And instance of this servlet can * be set up to always issue certificates against a certain profile * by setting the 'profileId' configuration in the servletConfig * If not, the user must specify the profileID when submitting the request * * "ImportCert.template" to process the response. * * @param sc servlet configuration, read from the web.xml file */ public void init(ServletConfig sc) throws ServletException { super.init(sc); mAuthorityId = sc.getInitParameter(PROP_AUTHORITY_ID); mProfileId = sc.getInitParameter(PROP_PROFILE_ID); statEvents = new LinkedHashSet(); } private void setInputsIntoContext(HttpServletRequest request, IProfile profile, IProfileContext ctx) { // passing inputs into context Enumeration inputIds = profile.getProfileInputIds(); if (inputIds != null) { while (inputIds.hasMoreElements()) { String inputId = inputIds.nextElement(); IProfileInput profileInput = profile.getProfileInput(inputId); Enumeration inputNames = profileInput.getValueNames(); while (inputNames.hasMoreElements()) { String inputName = inputNames.nextElement(); if (request.getParameter(inputName) != null) { // all subject name parameters start with sn_, no other input parameters do if (inputName.matches("^sn_.*")) { ctx.set(inputName, escapeValueRfc1779(request.getParameter(inputName), false).toString()); } else { ctx.set(inputName, request.getParameter(inputName)); } } } } } } /* * 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 inputIds = profile.getProfileInputIds(); if (inputIds != null) { while (inputIds.hasMoreElements()) { String inputId = inputIds.nextElement(); IProfileInput profileInput = profile.getProfileInput(inputId); Enumeration inputNames = profileInput.getValueNames(); while (inputNames.hasMoreElements()) { String inputName = inputNames.nextElement(); String inputValue = ""; CMS.debug("ProfileSubmitServlet: setInputsIntoContext() getting input name= " + inputName); try { inputValue = profileInput.getValue(inputName, locale, request); } catch (Exception e) { CMS.debug("ProfileSubmitServlet: setInputsIntoContext() getvalue() failed: " + e.toString()); } if (inputValue != null) { CMS.debug("ProfileSubmitServlet: setInputsIntoContext() setting value in ctx:" + inputValue); ctx.set(inputName, inputValue); } else { CMS.debug("ProfileSubmitServlet: setInputsIntoContext() value null"); } } } } } private void setCredentialsIntoContext(HttpServletRequest request, IProfileAuthenticator authenticator, IProfileContext ctx) { Enumeration authIds = authenticator.getValueNames(); if (authIds != null) { CMS.debug("ProfileSubmitServlet:setCredentialsIntoContext() authNames not null"); while (authIds.hasMoreElements()) { String authName = authIds.nextElement(); CMS.debug("ProfileSubmitServlet:setCredentialsIntoContext() authName:" + authName); if (request.getParameter(authName) != null) { CMS.debug("ProfileSubmitServlet:setCredentialsIntoContext() authName found in request"); ctx.set(authName, request.getParameter(authName)); } else { CMS.debug("ProfileSubmitServlet:setCredentialsIntoContext() authName not found in request"); } } } else { CMS.debug("ProfileSubmitServlet:setCredentialsIntoContext() authIds` null"); } } String getUidFromDN(String userdn) { StringTokenizer st = new StringTokenizer(userdn, ","); while (st.hasMoreTokens()) { String t = st.nextToken(); int i = t.indexOf("="); if (i == -1) { continue; } String n = t.substring(0, i); if (n.equalsIgnoreCase("uid")) { String v = t.substring(i + 1); CMS.debug("ProfileSubmitServlet:: getUidFromDN(): uid found:" + v); return v; } else { continue; } } return null; } /* * authenticate for renewal - more to add necessary params/values * to the session context */ public IAuthToken authenticate(IProfileAuthenticator authenticator, HttpServletRequest request, IRequest origReq, SessionContext context) throws EBaseException { IAuthToken authToken = authenticate(authenticator, request); // For renewal, fill in necessary params if (authToken != null) { String ouid = origReq.getExtDataInString("auth_token.uid"); // if the orig cert was manually approved, then there was // no auth token uid. Try to get the uid from the cert dn // itself, if possible if (ouid == null) { String sdn = (String) context.get("origSubjectDN"); if (sdn != null) { ouid = getUidFromDN(sdn); if (ouid != null) CMS.debug("ProfileSubmitServlet: renewal: authToken original uid not found"); } } else { CMS.debug("ProfileSubmitServlet: renewal: authToken original uid found in orig request auth_token"); } String auid = authToken.getInString("uid"); if (auid != null) { // not through ssl client auth CMS.debug("ProfileSubmitServlet: renewal: authToken uid found:" + auid); // authenticated with uid // put "orig_req.auth_token.uid" so that authz with // UserOrigReqAccessEvaluator will work if (ouid != null) { context.put("orig_req.auth_token.uid", ouid); CMS.debug("ProfileSubmitServlet: renewal: authToken original uid found:" + ouid); } else { CMS.debug("ProfileSubmitServlet: renewal: authToken original uid not found"); } } else { // through ssl client auth? CMS.debug("ProfileSubmitServlet: renewal: authToken uid not found:"); // put in orig_req's uid if (ouid != null) { CMS.debug("ProfileSubmitServlet: renewal: origReq uid not null:" + ouid + ". Setting authtoken"); authToken.set("uid", ouid); context.put(SessionContext.USER_ID, ouid); } else { CMS.debug("ProfileSubmitServlet: renewal: origReq uid not found"); // throw new EBaseException("origReq uid not found"); } } String userdn = origReq.getExtDataInString("auth_token.userdn"); if (userdn != null) { CMS.debug("ProfileSubmitServlet: renewal: origReq userdn not null:" + userdn + ". Setting authtoken"); authToken.set("userdn", userdn); } else { CMS.debug("ProfileSubmitServlet: renewal: origReq userdn not found"); // throw new EBaseException("origReq userdn not found"); } } else { CMS.debug("ProfileSubmitServlet: renewal: authToken null"); } return authToken; } public IAuthToken authenticate(IProfileAuthenticator authenticator, HttpServletRequest request) throws EBaseException { AuthCredentials credentials = new AuthCredentials(); // build credential Enumeration authNames = authenticator.getValueNames(); if (authNames != null) { while (authNames.hasMoreElements()) { String authName = authNames.nextElement(); credentials.set(authName, request.getParameter(authName)); } } credentials.set("clientHost", request.getRemoteHost()); IAuthToken authToken = authenticator.authenticate(credentials); SessionContext sc = SessionContext.getContext(); if (sc != null) { sc.put(SessionContext.AUTH_MANAGER_ID, authenticator.getName()); String userid = authToken.getInString(IAuthToken.USER_ID); if (userid != null) { sc.put(SessionContext.USER_ID, userid); } } return authToken; } private void setInputsIntoRequest(HttpServletRequest request, IProfile profile, IRequest req) { Enumeration inputIds = profile.getProfileInputIds(); if (inputIds != null) { while (inputIds.hasMoreElements()) { String inputId = inputIds.nextElement(); IProfileInput profileInput = profile.getProfileInput(inputId); Enumeration inputNames = profileInput.getValueNames(); if (inputNames != null) { while (inputNames.hasMoreElements()) { String inputName = inputNames.nextElement(); if (request.getParameter(inputName) != null) { // special characters in subject names parameters must be escaped if (inputName.matches("^sn_.*")) { req.setExtData(inputName, escapeValueRfc1779(request.getParameter(inputName), false) .toString()); } else { req.setExtData(inputName, request.getParameter(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 inputIds = profile.getProfileInputIds(); if (inputIds != null) { while (inputIds.hasMoreElements()) { String inputId = inputIds.nextElement(); IProfileInput profileInput = profile.getProfileInput(inputId); Enumeration inputNames = profileInput.getValueNames(); while (inputNames.hasMoreElements()) { String inputName = inputNames.nextElement(); String inputValue = ""; CMS.debug("ProfileSubmitServlet: setInputsIntoRequest() getting input name= " + inputName); try { inputValue = profileInput.getValue(inputName, locale, request); } catch (Exception e) { CMS.debug("ProfileSubmitServlet: setInputsIntoRequest() getvalue() failed: " + e.toString()); } if (inputValue != null) { CMS.debug("ProfileSubmitServlet: setInputsIntoRequest() setting value in ctx:" + inputValue); req.setExtData(inputName, inputValue); } else { CMS.debug("ProfileSubmitServlet: setInputsIntoRequest() value null"); } } } } } private void startTiming(String event) { IStatsSubsystem statsSub = (IStatsSubsystem) CMS.getSubsystem("stats"); if (statsSub != null) { statsSub.startTiming(event, true); } statEvents.add(event); } private void endTiming(String event) { IStatsSubsystem statsSub = (IStatsSubsystem) CMS.getSubsystem("stats"); if (statsSub != null) { statsSub.endTiming(event); } statEvents.remove(event); } private void errorExit(String msg) throws EBaseException { CMS.debug("ProfileSubmitServlet" + msg); for (String event : statEvents) { endTiming(event); } throw new EBaseException(msg); } /** * Process the HTTP request *

* * (Certificate Request Processed - either an automated "EE" profile based cert acceptance, or an automated "EE" * profile based cert rejection) *

* *

    *
  • http.param profileId ID of profile to use to process request *
  • signed.audit LOGGING_SIGNED_AUDIT_CERT_REQUEST_PROCESSED used when a certificate request has just been * through the approval process *
* * @param cmsReq the object holding the request and response information * @exception EBaseException an error has occurred */ public ArrayList processEnrollment(EnrollmentRequestData data) throws EBaseException { HttpServletRequest request = cmsReq.getHttpReq(); boolean xmlOutput = false; startTiming("enrollment"); Locale locale = getLocale(request); if (CMS.debugOn()) { printParameterValues(request); } CMS.debug("ProfileSubmitServlet: start serving"); // if we did not configure profileId in xml file, // then accept the user-provided one String profileId = (mProfileId == null) ? data.getProfileId() : mProfileId; CMS.debug("ProfileSubmitServlet: profileId " + profileId); IProfile profile = getProfile(locale, profileId); IProfileContext ctx = profile.createContext(); IProfileAuthenticator authenticator = getAuthenticator(request, profile, ctx); CMS.debug("ProfileSubmitServlet: set Inputs into profile Context"); setInputsIntoContext(request, profile, ctx); // for ssl authentication; pass in servlet for retrieving // ssl client certificates and 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("ProfileSubmitServlet: set sslClientCertProvider"); // before creating the request, authenticate the request IAuthToken authToken = authenticate(request, false, locale, null, authenticator, context); //authentication success, now authorizing authorize(locale, profileId, profile, authToken); /////////////////////////////////////////////// // create and populate request /////////////////////////////////////////////// startTiming("request_population"); IRequest reqs[] = null; try { reqs = profile.createRequests(ctx, locale); } catch (Exception e) { e.printStackTrace(); errorExit("ProfileSubmitServlet: createRequests " + e.toString()); } populateRequest(request, false, locale, profileId, profile, null, null, null, ctx, authenticator, authToken, reqs); endTiming("request_population"); /////////////////////////////////////////////// // submit request /////////////////////////////////////////////// String errorCode = submitRequest(locale, profile, authToken, reqs); ArrayList ret = new ArrayList(); for (IRequest req : reqs) { ret.add(req.getRequestId()); } // if there is an error we need to return the error code/ error reason // maybe as an exception? SessionContext.releaseContext(); endTiming("enrollment"); return ret; } private IProfileAuthenticator getAuthenticator(HttpServletRequest request, IProfile profile, IProfileContext ctx) throws EBaseException { IProfileAuthenticator authenticator = null; try { authenticator = profile.getAuthenticator(); } catch (EProfileException e) { // authenticator not installed correctly e.printStackTrace(); errorExit("renewal: exception:" + e.toString()); } if (authenticator != null) { CMS.debug("ProfileSubmitServlet: authenticator " + authenticator.getName() + " found"); setCredentialsIntoContext(request, authenticator, ctx); } return authenticator; } private IProfile getProfile(Locale locale, String profileId) throws EBaseException { IProfile profile = null; if (mProfileSubId == null || mProfileSubId.equals("")) { mProfileSubId = IProfileSubsystem.ID; } CMS.debug("ProfileSubmitServlet: SubId=" + mProfileSubId); IProfileSubsystem ps = (IProfileSubsystem) CMS.getSubsystem(mProfileSubId); if (ps == null) { errorExit("ProfileSubsystem not found"); } try { profile = ps.getProfile(profileId); } catch (EProfileException e) { if (profile == null) { CMS.debug("ProfileSubmitServlet: profile not found profileId " + profileId + " " + e.toString()); } } if (profile == null) { errorExit(CMS.getUserMessage(locale, "CMS_PROFILE_NOT_FOUND", profileId)); } if (!ps.isProfileEnable(profileId)) { errorExit("Profile " + profileId + " not enabled"); } return profile; } /* * 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 ArrayList processRenewal(EnrollmentRequestData data) throws EBaseException { HttpServletRequest request = cmsReq.getHttpReq(); boolean xmlOutput = false; boolean isRenewal = true; startTiming("enrollment"); Locale locale = getLocale(request); if (CMS.debugOn()) { printParameterValues(request); } CMS.debug("ProfileSubmitServlet: start serving"); // if we did not configure profileId in xml file, // then accept the user-provided one String renewProfileId = (mProfileId == null) ? data.getProfileId() : mProfileId; CMS.debug("ProfileSubmitServlet: profileId " + renewProfileId); IProfile renewProfile = getProfile(locale, renewProfileId); String serial = request.getParameter("serial_num"); BigInteger certSerial = 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) if (serial != null) { CMS.debug("ProfileSubmitServlet: renewal: found serial_num"); certSerial = new BigInteger(serial); // usr_origreq evaluator should be used to authorize ownership // of the cert } else { certSerial = getSerialNumberFromCert(request); } CMS.debug("ProfileSubmitServlet: renewal: serial number of cert to renew:" + certSerial.toString()); ICertRecord rec = getCertRecord(certSerial); if (rec == null) { errorExit("renewal cert record not found for serial number " + certSerial.toString()); } X509CertImpl origCert = rec.getCertificate(); if (origCert == null) { errorExit("renewal original cert not found in cert record for " + certSerial.toString()); } Date origNotAfter = origCert.getNotAfter(); CMS.debug("ProfileSubmitServlet: renewal: origNotAfter =" + origNotAfter.toString()); String origSubjectDN = origCert.getSubjectDN().getName(); CMS.debug("ProfileSubmitServlet: renewal: orig subj dn =" + origSubjectDN); IRequest origReq = getOriginalRequest(certSerial, rec); if (origReq == null) { errorExit("ProfileSubmitServlet: renewal original request not found"); } String profileId = origReq.getExtDataInString("profileId"); Integer origSeqNum = origReq.getExtDataInInteger(IEnrollProfile.REQUEST_SEQ_NUM); IProfile profile = getProfile(locale, profileId); IProfileContext ctx = profile.createContext(); IProfileAuthenticator authenticator = getAuthenticator(request, renewProfile, ctx); IProfileAuthenticator origAuthenticator = getAuthenticator(request, profile, ctx); // for renewal, input needs to be retrieved from the orig req record CMS.debug("ProfileSubmitServlet: 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 and 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("ProfileSubmitServlet: set sslClientCertProvider"); if (origSubjectDN != null) context.put("origSubjectDN", origSubjectDN); // before creating the request, authenticate the request IAuthToken authToken = authenticate(request, isRenewal, locale, origReq, authenticator, context); // authentication success, now doing authorization authorize(locale, profileId, renewProfile, authToken); /////////////////////////////////////////////// // create and populate request /////////////////////////////////////////////// startTiming("request_population"); IRequest reqs[] = null; try { reqs = profile.createRequests(ctx, locale); } catch (Exception e) { e.printStackTrace(); errorExit("ProfileSubmitServlet: createRequests " + e.toString()); } populateRequest(request, isRenewal, locale, profileId, profile, origReq, origNotAfter, origSubjectDN, ctx, authenticator, authToken, reqs); endTiming("request_population"); /////////////////////////////////////////////// // submit request /////////////////////////////////////////////// String errorCode = submitRequest(locale, profile, authToken, reqs); ArrayList ret = new ArrayList(); for (IRequest req : reqs) { ret.add(req.getRequestId()); } // if there is an error we need to return the error code/ error reason // maybe as an exception? SessionContext.releaseContext(); endTiming("enrollment"); return ret; } private IRequest getOriginalRequest(BigInteger certSerial, ICertRecord rec) throws EBaseException { IAuthority authority = (IAuthority) CMS.getSubsystem(mAuthorityId); if (authority == null) { errorExit("renewal: Authority " + mAuthorityId + " not found"); } IRequestQueue queue = authority.getRequestQueue(); if (queue == null) { errorExit("renewal: Request Queue of " + mAuthorityId + " not found"); } MetaInfo metaInfo = (MetaInfo) rec.get(ICertRecord.ATTR_META_INFO); if (metaInfo == null) { errorExit("ProfileSubmitServlet: renewal: cert record locating MetaInfo failed for serial number " + certSerial.toString()); } String rid = (String) metaInfo.get(ICertRecord.META_REQUEST_ID); if (rid == null) { errorExit("ProfileSubmitServlet: renewal: cert record locating request id in MetaInfo failed " + "for serial number " + certSerial.toString()); } CMS.debug("ProfileSubmiServlet: renewal: reuest id is " + rid); IRequest origReq = queue.findRequest(new RequestId(rid)); return origReq; } private BigInteger getSerialNumberFromCert(HttpServletRequest request) throws EBaseException { BigInteger certSerial; CMS.debug("ProfileSubmitServlet: renewal: serial_num not found, must do ssl client auth"); // 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 SSLClientCertProvider sslCCP = new SSLClientCertProvider(request); X509Certificate[] certs = sslCCP.getClientCertificateChain(); certSerial = null; if (certs == null || certs.length == 0) { errorExit("renewal: no ssl client cert chain"); } else { // has ssl client cert CMS.debug("ProfileSubmitServlet: 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("ProfileSubmitServlet: renewal: found leaf cert"); break; } else { CMS.debug("ProfileSubmitServlet: 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("ProfileSubmitServlet: renewal: found CA cert in chain"); break; } // else found a ca cert, continue } } catch (Exception e) { errorExit("renewal: exception:" + e.toString()); } } } if (clientCert == null) { errorExit("renewal: no client cert in chain"); } // convert to java X509 cert interface try { byte[] certEncoded = clientCert.getEncoded(); clientCert = new X509CertImpl(certEncoded); } catch (Exception e) { errorExit("renewal: exception:" + e.toString()); } certSerial = clientCert.getSerialNumber(); } return certSerial; } private String submitRequest(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 (int k = 0; k < reqs.length; k++) { try { // reset the "auditRequesterID" auditRequesterID = auditRequesterID(reqs[k]); // print request debug if (reqs[k] != null) { Enumeration reqKeys = reqs[k].getExtDataKeys(); while (reqKeys.hasMoreElements()) { String reqKey = reqKeys.nextElement(); String reqVal = reqs[k].getExtDataInString(reqKey); if (reqVal != null) { CMS.debug("ProfileSubmitServlet: key=$request." + reqKey + "$ value=" + reqVal); } } } profile.submit(authToken, reqs[k]); reqs[k].setRequestStatus(RequestStatus.COMPLETE); // reset the "auditInfoCertValue" auditInfoCertValue = auditInfoCertValue(reqs[k]); 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 reqs[k].setRequestStatus(RequestStatus.PENDING); // need to notify INotify notify = profile.getRequestQueue().getPendingNotify(); if (notify != null) { notify.notify(reqs[k]); } CMS.debug("ProfileSubmitServlet: 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 reqs[k].setRequestStatus(RequestStatus.REJECTED); CMS.debug("ProfileSubmitServlet: 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("ProfileSubmitServlet: 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(reqs[k]); } else { profile.getRequestQueue().updateRequest(reqs[k]); } } catch (EBaseException e) { e.printStackTrace(); CMS.debug("ProfileSubmitServlet: updateRequest " + e.toString()); } } return errorCode; } private void populateRequest(HttpServletRequest request, boolean isRenewal, Locale locale, String profileId, IProfile profile, IRequest origReq, Date origNotAfter, String origSubjectDN, IProfileContext ctx, IProfileAuthenticator authenticator, IAuthToken authToken, IRequest[] reqs) throws EBaseException { for (int k = 0; k < reqs.length; k++) { boolean fromRA = false; String uid = ""; // adding parameters to request if (isRenewal) { setInputsIntoRequest(origReq, profile, reqs[k], locale); // set orig expiration date to be used in Validity constraint reqs[k].setExtData("origNotAfter", BigInteger.valueOf(origNotAfter.getTime())); // set subjectDN to be used in subject name default reqs[k].setExtData(IProfileAuthenticator.AUTHENTICATED_NAME, origSubjectDN); // set request type reqs[k].setRequestType("renewal"); } else setInputsIntoRequest(request, profile, reqs[k]); // serial auth token into request if (authToken != null) { Enumeration 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++) { reqs[k].setExtData(ARG_AUTH_TOKEN + "." + tokenName + "[" + i + "]", tokenVals[i]); } } else { String tokenVal = authToken.getInString(tokenName); if (tokenVal != null) { reqs[k].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("ProfileSubmitServlet: request from RA: " + uid); reqs[k].setExtData(ARG_REQUEST_OWNER, uid); } // put profile framework parameters into the request reqs[k].setExtData(ARG_PROFILE, "true"); reqs[k].setExtData(ARG_PROFILE_ID, profileId); if (isRenewal) reqs[k].setExtData(ARG_RENEWAL_PROFILE_ID, request.getParameter("profileId")); reqs[k].setExtData(ARG_PROFILE_APPROVED_BY, profile.getApprovedBy()); String setId = profile.getPolicySetId(reqs[k]); if (setId == null) { errorExit(CMS.getUserMessage("CMS_PROFILE_NO_POLICY_SET_FOUND")); } CMS.debug("ProfileSubmitServlet profileSetid=" + setId); reqs[k].setExtData(ARG_PROFILE_SET_ID, setId); reqs[k].setExtData(ARG_PROFILE_REMOTE_HOST, request.getRemoteHost()); reqs[k].setExtData(ARG_PROFILE_REMOTE_ADDR, request.getRemoteAddr()); CMS.debug("ProfileSubmitServlet: request " + reqs[k].getRequestId().toString()); try { CMS.debug("ProfileSubmitServlet: populating request inputs"); // give authenticator a chance to populate the request if (authenticator != null) { authenticator.populate(authToken, reqs[k]); } profile.populateInput(ctx, reqs[k]); profile.populate(reqs[k]); } catch (EProfileException e) { e.printStackTrace(); //TODO - user message error errorExit("exception in populate: " + reqs[k].getRequestId().toString()); } catch (Throwable e) { e.printStackTrace(); errorExit(CMS.getUserMessage(locale, "CMS_INTERNAL_ERROR") + " " + reqs[k].getRequestId().toString()); } } } private void authorize(Locale locale, String profileId, IProfile profile, IAuthToken authToken) throws EBaseException { if (authToken != null) { CMS.debug("ProfileSubmitServlet authToken not null"); // do profile authorization String acl = profile.getAuthzAcl(); CMS.debug("ProfileSubmitServlet: authz using acl: " + acl); if (acl != null && acl.length() > 0) { try { String resource = profileId + ".authz.acl"; authorize(mAclMethod, resource, authToken, acl); } catch (Exception e) { errorExit(CMS.getUserMessage(locale, "CMS_AUTHORIZATION_ERROR")); } } } } private IAuthToken authenticate(HttpServletRequest request, boolean isRenewal, Locale locale, IRequest origReq, IProfileAuthenticator authenticator, SessionContext context) throws EBaseException { IAuthToken authToken = null; startTiming("profile_authentication"); if (authenticator != null) { CMS.debug("ProfileSubmitServlet: authentication required."); String uid_cred = "Unidentified"; String uid_attempted_cred = "Unidentified"; Enumeration authIds = authenticator.getValueNames(); //Attempt to possibly fetch attemped uid, may not always be available. if (authIds != null) { while (authIds.hasMoreElements()) { String authName = authIds.nextElement(); String value = request.getParameter(authName); if (value != null) { if (authName.equals("uid")) { uid_attempted_cred = value; } } } } String authSubjectID = auditSubjectID(); String authMgrID = authenticator.getName(); String auditMessage = null; try { if (isRenewal) { CMS.debug("ProfileSubmitServlet: renewal authenticate begins"); authToken = authenticate(authenticator, request, origReq, context); CMS.debug("ProfileSubmitServlet: renewal authenticate ends"); } else { authToken = authenticate(authenticator, request); } } catch (EBaseException e) { //audit log our authentication failure authSubjectID += " : " + uid_cred; auditMessage = CMS.getLogMessage( LOGGING_SIGNED_AUDIT_AUTH_FAIL, authSubjectID, ILogger.FAILURE, authMgrID, uid_attempted_cred); audit(auditMessage); errorExit(CMS.getUserMessage(locale, "CMS_AUTHENTICATION_ERROR")); } //Log successful authentication //Attempt to get uid from authToken, most tokens respond to the "uid" cred. uid_cred = authToken.getInString("uid"); if (uid_cred == null || uid_cred.length() == 0) { uid_cred = "Unidentified"; } authSubjectID = authSubjectID + " : " + uid_cred; // store a message in the signed audit log file auditMessage = CMS.getLogMessage( LOGGING_SIGNED_AUDIT_AUTH_SUCCESS, authSubjectID, ILogger.SUCCESS, authMgrID); audit(auditMessage); } endTiming("profile_authentication"); return authToken; } private void printParameterValues(HttpServletRequest request) { CMS.debug("Start of ProfileSubmitServlet Input Parameters"); @SuppressWarnings("unchecked") Enumeration paramNames = request.getParameterNames(); while (paramNames.hasMoreElements()) { String paramName = paramNames.nextElement(); // added this facility so that password can be hidden, // all sensitive parameters should be prefixed with // __ (double underscores); however, in the event that // a security parameter slips through, we perform multiple // additional checks to insure that it is NOT displayed if (paramName.startsWith("__") || paramName.endsWith("password") || paramName.endsWith("passwd") || paramName.endsWith("pwd") || paramName.equalsIgnoreCase("admin_password_again") || paramName.equalsIgnoreCase("directoryManagerPwd") || paramName.equalsIgnoreCase("bindpassword") || paramName.equalsIgnoreCase("bindpwd") || paramName.equalsIgnoreCase("passwd") || paramName.equalsIgnoreCase("password") || paramName.equalsIgnoreCase("pin") || paramName.equalsIgnoreCase("pwd") || paramName.equalsIgnoreCase("pwdagain") || paramName.equalsIgnoreCase("uPasswd")) { CMS.debug("ProfileSubmitServlet Input Parameter " + paramName + "='(sensitive)'"); } else { CMS.debug("ProfileSubmitServlet Input Parameter " + paramName + "='" + request.getParameter(paramName) + "'"); } } CMS.debug("End of ProfileSubmitServlet Input Parameters"); } /** * Signed Audit Log Requester ID * * This method is called to obtain the "RequesterID" for * a signed audit log message. *

* * @param request the actual request * @return id string containing the signed audit log message RequesterID */ private String auditRequesterID(IRequest request) { // if no signed audit object exists, bail if (mSignedAuditLogger == null) { return null; } String requesterID = ILogger.UNIDENTIFIED; if (request != null) { // overwrite "requesterID" if and only if "id" != null String id = request.getRequestId().toString(); if (id != null) { requesterID = id.trim(); } } return requesterID; } /** * Signed Audit Log Info Certificate Value * * This method is called to obtain the certificate from the passed in * "X509CertImpl" for a signed audit log message. *

* * @param request request containing an X509CertImpl * @return cert string containing the certificate */ private String auditInfoCertValue(IRequest request) { // if no signed audit object exists, bail if (mSignedAuditLogger == null) { return null; } X509CertImpl x509cert = request.getExtDataInCert( IEnrollProfile.REQUEST_ISSUED_CERT); if (x509cert == null) { return ILogger.SIGNED_AUDIT_EMPTY_VALUE; } byte rawData[] = null; try { rawData = x509cert.getEncoded(); } catch (CertificateEncodingException e) { return ILogger.SIGNED_AUDIT_EMPTY_VALUE; } String cert = null; // convert "rawData" into "base64Data" if (rawData != null) { String base64Data = null; base64Data = Utils.base64encode(rawData).trim(); // extract all line separators from the "base64Data" StringBuffer sb = new StringBuffer(); for (int i = 0; i < base64Data.length(); i++) { if (!Character.isWhitespace(base64Data.charAt(i))) { sb.append(base64Data.charAt(i)); } } cert = sb.toString(); } if (cert != null) { cert = cert.trim(); if (cert.equals("")) { return ILogger.SIGNED_AUDIT_EMPTY_VALUE; } else { return cert; } } else { return ILogger.SIGNED_AUDIT_EMPTY_VALUE; } } }