summaryrefslogtreecommitdiffstats
path: root/pki/base/common/src/com/netscape/cms/servlet/connector/CloneServlet.java
diff options
context:
space:
mode:
Diffstat (limited to 'pki/base/common/src/com/netscape/cms/servlet/connector/CloneServlet.java')
-rw-r--r--pki/base/common/src/com/netscape/cms/servlet/connector/CloneServlet.java567
1 files changed, 567 insertions, 0 deletions
diff --git a/pki/base/common/src/com/netscape/cms/servlet/connector/CloneServlet.java b/pki/base/common/src/com/netscape/cms/servlet/connector/CloneServlet.java
new file mode 100644
index 000000000..0b147c58d
--- /dev/null
+++ b/pki/base/common/src/com/netscape/cms/servlet/connector/CloneServlet.java
@@ -0,0 +1,567 @@
+// --- 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.servlet.connector;
+
+
+import com.netscape.cms.servlet.common.*;
+import com.netscape.cms.servlet.base.*;
+
+import javax.servlet.*;
+import javax.servlet.http.*;
+import netscape.security.x509.*;
+
+import java.security.cert.*;
+
+import java.io.*;
+
+import com.netscape.certsrv.base.*;
+import com.netscape.certsrv.logging.*;
+import com.netscape.certsrv.authority.*;
+import com.netscape.certsrv.connector.*;
+
+import com.netscape.certsrv.request.*;
+import com.netscape.certsrv.authentication.*;
+import com.netscape.certsrv.authorization.*;
+import com.netscape.certsrv.authentication.AuthCredentials;
+
+import com.netscape.certsrv.apps.*;
+
+
+/**
+ * Clone servlet - part of the Clone Authority (CLA)
+ * processes Revoked certs from its dependant clone CAs
+ * service request and return status.
+ *
+ * @version $Revision$, $Date$
+ */
+public class CloneServlet extends CMSServlet {
+ public static final String INFO = "Clone Servlet";
+ public final static String PROP_AUTHORITY = "authority";
+ protected ServletConfig mConfig = null;
+ protected IAuthority mAuthority = null;
+ protected IRequestEncoder mReqEncoder = null;
+ protected IAuthSubsystem mAuthSubsystem = null;
+ protected ILogger mLogger = CMS.getLogger();
+
+ public CloneServlet() {
+ }
+
+ public void init(ServletConfig sc) throws ServletException {
+ super.init(sc);
+ mConfig = sc;
+ String authority = sc.getInitParameter(PROP_AUTHORITY);
+
+ if (authority != null)
+ mAuthority = (IAuthority)
+ CMS.getSubsystem(authority);
+ mReqEncoder = CMS.getHttpRequestEncoder();
+ mAuthSubsystem = (IAuthSubsystem) CMS.getSubsystem(CMS.SUBSYSTEM_AUTH);
+ }
+
+ public void service(HttpServletRequest req,
+ HttpServletResponse resp) throws ServletException, IOException {
+ boolean running_state = CMS.isInRunningState();
+
+ if (!running_state)
+ throw new IOException(
+ "CMS server is not ready to serve.");
+
+ ServletContext servletContext = mConfig.getServletContext();
+
+ CMSRequest cmsRequest = newCMSRequest();
+
+ // set argblock
+ cmsRequest.setHttpParams(CMS.createArgBlock(toHashtable(req)));
+
+ // set http request
+ cmsRequest.setHttpReq(req);
+
+ // set http response
+ cmsRequest.setHttpResp(resp);
+
+ // set servlet config.
+ cmsRequest.setServletConfig(mConfig);
+
+ // set servlet context.
+ cmsRequest.setServletContext(mConfig.getServletContext());
+
+ char[] content = null;
+ String encodedreq = null;
+ String method = null;
+ int len = -1;
+ IPKIMessage msg = null;
+ IPKIMessage replymsg = null;
+ IRequest r = null;
+ IRequest reply = null;
+
+ // NOTE must read all bufer before redoing handshake for
+ // ssl client auth for client auth to work.
+
+ // get request method
+ method = req.getMethod();
+
+ // get content length
+ len = req.getContentLength();
+
+ // get content, a base 64 encoded serialized request.
+ if (len > 0) {
+ InputStream in = req.getInputStream();
+ InputStreamReader inreader = new InputStreamReader(in, "UTF8");
+ BufferedReader reader = new BufferedReader(inreader, len);
+
+ content = new char[len];
+ int done = reader.read(content, 0, len);
+ int total = done;
+
+ while (done >= 0 && total < len) {
+ done = reader.read(content, total, len - total);
+ total += done;
+ }
+ reader.close();
+ encodedreq = new String(content);
+ }
+
+ // force client auth handshake, validate clone CA (CCA)
+ // and get CCA's Id.
+ // NOTE must do this after all contents are read for ssl
+ // redohandshake to work
+
+ X509Certificate peerCert;
+
+ try {
+ peerCert = getPeerCert(req);
+ }catch (EBaseException e) {
+ mAuthority.log(ILogger.LL_SECURITY,
+ CMS.getLogMessage("CMSGW_HAS_NO_CLIENT_CERT"));
+ resp.sendError(HttpServletResponse.SC_UNAUTHORIZED);
+ return;
+ }
+
+ if (peerCert == null) {
+ // XXX log something here.
+ resp.sendError(HttpServletResponse.SC_FORBIDDEN);
+ return;
+ }
+
+ // authenticate clone CA (CCA)
+
+ String CCA_Id = null;
+ String CCAUserId = null;
+ IAuthToken token = null;
+
+ try {
+ // cfu +++ authenticate checks both SUBJECT and Signer SUBJECT
+ CMS.debug("CloneServlet: about to authenticate");
+ token = authenticate(peerCert);
+ // cfu maybe don't need CCA_Id, because the above check
+ // was good enough
+ CCAUserId = token.getInString("userid");
+ CCA_Id = (String) peerCert.getSubjectDN().toString();
+ } catch (EInvalidCredentials e) {
+ // already logged.
+ resp.sendError(HttpServletResponse.SC_UNAUTHORIZED);
+ return;
+ } catch (EBaseException e) {
+ // already logged.
+ resp.sendError(HttpServletResponse.SC_FORBIDDEN);
+ return;
+ }
+
+ mAuthority.log(ILogger.LL_INFO,
+ "Clone Certificate Authority authenticated: " + peerCert.getSubjectDN());
+
+ // authorize, any authenticated user are authorized
+ AuthzToken authzToken = null;
+
+ try {
+ authzToken = authorize(mAclMethod, token,
+ mAuthzResourceName, "submit");
+ } catch (Exception e) {
+ // do nothing for now
+ }
+
+ if (authzToken == null) {
+ cmsRequest.setStatus(CMSRequest.UNAUTHORIZED);
+ return;
+ }
+
+ // after cert validated, check http request.
+ if (!method.equalsIgnoreCase("POST")) {
+ resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
+ return;
+ }
+ if (len <= 0) {
+ resp.sendError(HttpServletResponse.SC_LENGTH_REQUIRED);
+ return;
+ }
+
+ // now process CCA request - should just be posting revoked
+ // certs for now
+
+ try {
+ // decode request.
+ CMS.debug("Cloneservlet: before decoding request, encodedreq= " + encodedreq);
+ msg = (IPKIMessage) mReqEncoder.decode(encodedreq);
+ // process request
+ CMS.debug("Cloneservlet: decoded request");
+ replymsg = processRequest(CCA_Id, CCAUserId, msg, token);
+ } catch (IOException e) {
+ e.printStackTrace();
+ mAuthority.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSGW_IO_ERROR_REMOTE_REQUEST", e.toString()));
+ resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
+ return;
+ } catch (EBaseException e) {
+ mAuthority.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSGW_IO_ERROR_REMOTE_REQUEST", e.toString()));
+ resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ return;
+ }
+
+ // encode reply
+ String encodedrep = mReqEncoder.encode(replymsg);
+
+ resp.setStatus(HttpServletResponse.SC_OK);
+ resp.setContentType("text/html");
+ resp.setContentLength(encodedrep.length());
+
+ // send reply
+ OutputStream out = resp.getOutputStream();
+ OutputStreamWriter writer = new OutputStreamWriter(out, "UTF8");
+
+ writer.write(encodedrep);
+ writer.flush();
+ writer.close();
+ out.flush();
+ }
+
+ //cfu ++change this to just check the subject and signer
+ protected IAuthToken authenticate(
+ X509Certificate peerCert)
+ throws EBaseException {
+ try {
+ // XXX using agent authentication now since we're only
+ // verifying that the cert belongs to a user in the db.
+ // XXX change this to ACL in the future.
+
+ // build JAVA X509Certificate from peerCert.
+ X509CertImpl cert = new X509CertImpl(peerCert.getEncoded());
+
+ AuthCredentials creds = new AuthCredentials();
+
+ creds.set(IAuthManager.CRED_SSL_CLIENT_CERT,
+ new X509Certificate[] {cert}
+ );
+
+ IAuthToken token = mAuthSubsystem.authenticate(creds,
+ IAuthSubsystem.CERTUSERDB_AUTHMGR_ID);
+
+ return token;
+ } catch (CertificateException e) {
+ mAuthority.log(ILogger.LL_SECURITY,
+ CMS.getLogMessage("CMSGW_REMOTE_AUTHORITY_AUTH_FAILURE", peerCert.getSubjectDN().toString()));
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString()));
+ } catch (EInvalidCredentials e) {
+ mAuthority.log(ILogger.LL_SECURITY,
+ CMS.getLogMessage("CMSGW_REMOTE_AUTHORITY_AUTH_FAILURE", peerCert.getSubjectDN().toString()));
+ throw e;
+ } catch (EBaseException e) {
+ mAuthority.log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("CMSGW_REMOTE_AUTHORITY_AUTH_FAILURE", peerCert.getSubjectDN().toString()));
+ throw e;
+ }
+ }
+
+ protected IPKIMessage processRequest(
+ String source, String sourceUserId, IPKIMessage msg, IAuthToken token)
+ throws EBaseException {
+ IPKIMessage replymsg = null;
+ IRequest r = null;
+ IRequestQueue queue = mAuthority.getRequestQueue();
+ String srcid = source + ":" + msg.getReqId();
+
+ mAuthority.log(ILogger.LL_INFO, "CFU: in CloneServlet processRequest");
+
+ // find request in request queue and return result.
+ RequestId thisreqid = queue.findRequestBySourceId(srcid);
+ IRequest thisreq = null;
+
+ if (thisreqid != null) {
+ thisreq = queue.findRequest(thisreqid);
+ if (thisreq == null) {
+ // strange case.
+ String errormsg = "Cannot find request in request queue " + thisreqid;
+
+ mAuthority.log(ILogger.LL_FAILURE, errormsg);
+ throw new EBaseException(errormsg);
+ } else {
+ mAuthority.log(ILogger.LL_INFO,
+ "Found request " + thisreqid + " for " + srcid);
+ replymsg = CMS.getHttpPKIMessage();
+ replymsg.fromRequest(thisreq);
+ return replymsg;
+ }
+ }
+
+ // if not found process request.
+ thisreq = queue.newRequest(msg.getReqType());
+ thisreq.setSourceId(srcid);
+ msg.toRequest(thisreq);
+ thisreq.setExtData(IRequest.AUTH_TOKEN, token);
+
+ // setting requestor type must come after copy contents. because
+ // requestor is a regular attribute.
+ thisreq.setExtData(IRequest.REQUESTOR_TYPE,
+ IRequest.REQUESTOR_RA);
+ mAuthority.log(ILogger.LL_INFO, "Processing remote request " + srcid);
+
+ // Set this so that request's updateBy is recorded
+ SessionContext s = SessionContext.getContext();
+
+ if (s.get(SessionContext.USER_ID) == null) {
+ s.put(SessionContext.USER_ID, sourceUserId);
+ }
+
+ queue.processRequest(thisreq);
+ replymsg = CMS.getHttpPKIMessage();
+ replymsg.fromRequest(thisreq);
+
+ //for audit log
+ String agentID = sourceUserId;
+ String initiative = AuditFormat.FROMRA + " trustedManagerID: " +
+ agentID + " remote reqID " + msg.getReqId();
+ String authMgr = AuditFormat.NOAUTH;
+
+ if (token != null) {
+ authMgr =
+ token.getInString(AuthToken.TOKEN_AUTHMGR_INST_NAME);
+ }
+
+ // Get the certificate info from the request
+ X509CertInfo certInfo[] = thisreq.getExtDataInCertInfoArray(IRequest.CERT_INFO);
+
+ try {
+ if (!thisreq.getRequestStatus().equals(RequestStatus.COMPLETE)) {
+ if (certInfo != null) {
+ for (int i = 0; i < certInfo.length; i++) {
+ mLogger.log(ILogger.EV_AUDIT,
+ ILogger.S_OTHER,
+ AuditFormat.LEVEL,
+ AuditFormat.FORMAT,
+ new Object[] {
+ thisreq.getRequestType(),
+ thisreq.getRequestId(),
+ initiative,
+ authMgr,
+ thisreq.getRequestStatus(),
+ certInfo[i].get(X509CertInfo.SUBJECT),
+ ""}
+ );
+ }
+ } else {
+ mLogger.log(ILogger.EV_AUDIT,
+ ILogger.S_OTHER,
+ AuditFormat.LEVEL,
+ AuditFormat.NODNFORMAT,
+ new Object[] {
+ thisreq.getRequestType(),
+ thisreq.getRequestId(),
+ initiative,
+ authMgr,
+ thisreq.getRequestStatus()}
+ );
+ }
+ } else {
+ if
+ (thisreq.getRequestType().equals(IRequest.CLA_CERT4CRL_REQUEST)) {
+ Integer result = thisreq.getExtDataInInteger(IRequest.RESULT);
+
+ if (result.equals(IRequest.RES_ERROR)) {
+ CMS.debug("CloneServlet: error in CLA_CERT4CRL_REQUEST");
+ } else {
+ // the success.
+ CMS.debug("CloneServlet: success in CLA_CERT4CRL_REQUEST");
+ }
+ }
+
+ /* cfu ---
+ if (thisreq.getRequestType().equals(IRequest.ENROLLMENT_REQUEST)) {
+ // XXX make the repeat record.
+ // Get the certificate(s) from the request
+ X509CertImpl issuedCerts[] =
+ (X509CertImpl[])thisreq.get(IRequest.ISSUED_CERTS);
+ // return potentially more than one certificates.
+ if (issuedCerts != null) {
+ for (int i = 0; i < issuedCerts.length; i++) {
+ mLogger.log(ILogger.EV_AUDIT,
+ ILogger.S_OTHER,
+ AuditFormat.LEVEL,
+ AuditFormat.FORMAT,
+ new Object[] {
+ thisreq.getRequestType(),
+ thisreq.getRequestId() ,
+ initiative ,
+ authMgr ,
+ "completed",
+ issuedCerts[i].getSubjectDN() ,
+ "cert issued serial number: 0x" +
+ issuedCerts[i].getSerialNumber().toString(16)}
+ );
+ }
+ } else {
+ mLogger.log(ILogger.EV_AUDIT,
+ ILogger.S_OTHER,
+ AuditFormat.LEVEL,
+ AuditFormat.NODNFORMAT,
+ new Object[] {
+ thisreq.getRequestType(),
+ thisreq.getRequestId() ,
+ initiative ,
+ authMgr ,
+ "completed"}
+ );
+ }
+ } else if (thisreq.getRequestType().equals(IRequest.RENEWAL_REQUEST)) {
+ X509CertImpl[] certs = (X509CertImpl[])thisreq.get(IRequest.OLD_CERTS);
+ X509CertImpl old_cert = certs[0];
+ certs = (X509CertImpl[])thisreq.get(IRequest.ISSUED_CERTS);
+ X509CertImpl renewed_cert = certs[0];
+ if (old_cert != null && renewed_cert != null) {
+ mLogger.log(ILogger.EV_AUDIT, ILogger.S_OTHER,
+ AuditFormat.LEVEL,
+ AuditFormat.RENEWALFORMAT,
+ new Object[] {
+ thisreq.getRequestId(),
+ initiative ,
+ authMgr ,
+ "completed",
+ old_cert.getSubjectDN() ,
+ old_cert.getSerialNumber().toString(16) ,
+ "new serial number: 0x" +
+ renewed_cert.getSerialNumber().toString(16)}
+ );
+ } else {
+ mLogger.log(ILogger.EV_AUDIT,
+ ILogger.S_OTHER,
+ AuditFormat.LEVEL,
+ AuditFormat.NODNFORMAT,
+ new Object[] {
+ thisreq.getRequestType(),
+ thisreq.getRequestId() ,
+ initiative ,
+ authMgr ,
+ "completed with error"}
+ );
+ }
+ } else if (thisreq.getRequestType().equals(IRequest.REVOCATION_REQUEST)) {
+ X509CertImpl[] oldCerts = (X509CertImpl[])thisreq.get(IRequest.OLD_CERTS);
+ RevokedCertImpl crlentries[] =
+ (RevokedCertImpl[])thisreq.get(IRequest.REVOKED_CERTS);
+ CRLExtensions crlExts = crlentries[0].getExtensions();
+ int reason = 0;
+ if (crlExts != null) {
+ Enumeration enum = crlExts.getElements();
+ while(enum.hasMoreElements()){
+ Extension ext = (Extension) enum.nextElement();
+ if (ext instanceof CRLReasonExtension) {
+ reason = ((CRLReasonExtension)ext).getReason().toInt
+ ();
+ break;
+ }
+ }
+ }
+
+ int count = oldCerts.length;
+ Integer result = (Integer)thisreq.get(IRequest.RESULT);
+ if (result.equals(IRequest.RES_ERROR)) {
+ EBaseException ex = (EBaseException)thisreq.get(IRequest.ERROR);
+ EBaseException[] svcErrors =
+ (EBaseException[])thisreq.get(IRequest.SVCERRORS);
+ if (svcErrors != null && svcErrors.length > 0) {
+ for (int i = 0; i < svcErrors.length; i++) {
+ EBaseException err = svcErrors[i];
+ if (err != null) {
+ for (int j = 0; j < count; j++) {
+ if (oldCerts[j] != null) {
+ mLogger.log(ILogger.EV_AUDIT,
+ ILogger.S_OTHER,
+ AuditFormat.LEVEL,
+ AuditFormat.DOREVOKEFORMAT,
+ new Object[] {
+ thisreq.getRequestId(),
+ initiative ,
+ "completed with error: " +
+ err.toString() ,
+ oldCerts[j].getSubjectDN() ,
+ oldCerts[j].getSerialNumber().toString(16),
+ RevocationReason.fromInt(reason).toString()}
+ );
+ }
+ }
+ }
+ }
+ }
+ } else {
+ // the success.
+ for (int j = 0; j < count; j++) {
+ if (oldCerts[j] != null) {
+ mLogger.log(ILogger.EV_AUDIT, ILogger.S_OTHER,
+ AuditFormat.LEVEL,
+ AuditFormat.DOREVOKEFORMAT,
+ new Object[] {
+ thisreq.getRequestId(),
+ initiative ,
+ "completed" ,
+ oldCerts[j].getSubjectDN() ,
+ oldCerts[j].getSerialNumber().toString(16),
+ RevocationReason.fromInt(reason).toString()}
+ );
+ }
+ }
+ }
+ } else {
+ mLogger.log(ILogger.EV_AUDIT,
+ ILogger.S_OTHER,
+ AuditFormat.LEVEL,
+ AuditFormat.NODNFORMAT,
+ new Object[] {
+ thisreq.getRequestType(),
+ thisreq.getRequestId() ,
+ initiative ,
+ authMgr ,
+ "completed"}
+ );
+ }
+ cfu */
+ }
+ } catch (IOException e) {
+ } catch (CertificateException e) {
+ }
+
+ return replymsg;
+ }
+
+ protected X509Certificate
+ getPeerCert(HttpServletRequest req) throws EBaseException {
+ return getSSLClientCertificate(req);
+ }
+
+ public String getServletInfo() {
+ return INFO;
+ }
+}