From 621d9e5c413e561293d7484b93882d985b3fe15f Mon Sep 17 00:00:00 2001 From: Endi Sukma Dewata Date: Sat, 24 Mar 2012 02:27:47 -0500 Subject: Removed unnecessary pki folder. Previously the source code was located inside a pki folder. This folder was created during svn migration and is no longer needed. This folder has now been removed and the contents have been moved up one level. Ticket #131 --- .../cms/servlet/connector/CloneServlet.java | 579 +++++++++++++++++++++ 1 file changed, 579 insertions(+) create mode 100644 base/common/src/com/netscape/cms/servlet/connector/CloneServlet.java (limited to 'base/common/src/com/netscape/cms/servlet/connector/CloneServlet.java') diff --git a/base/common/src/com/netscape/cms/servlet/connector/CloneServlet.java b/base/common/src/com/netscape/cms/servlet/connector/CloneServlet.java new file mode 100644 index 000000000..f9085a5bc --- /dev/null +++ b/base/common/src/com/netscape/cms/servlet/connector/CloneServlet.java @@ -0,0 +1,579 @@ +// --- 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 java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import netscape.security.x509.X509CertImpl; +import netscape.security.x509.X509CertInfo; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.authentication.AuthCredentials; +import com.netscape.certsrv.authentication.AuthToken; +import com.netscape.certsrv.authentication.EInvalidCredentials; +import com.netscape.certsrv.authentication.IAuthManager; +import com.netscape.certsrv.authentication.IAuthSubsystem; +import com.netscape.certsrv.authentication.IAuthToken; +import com.netscape.certsrv.authority.IAuthority; +import com.netscape.certsrv.authorization.AuthzToken; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.SessionContext; +import com.netscape.certsrv.connector.IPKIMessage; +import com.netscape.certsrv.connector.IRequestEncoder; +import com.netscape.certsrv.logging.AuditFormat; +import com.netscape.certsrv.logging.ILogger; +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.cms.servlet.base.CMSServlet; +import com.netscape.cms.servlet.common.CMSRequest; + +/** + * 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 { + /** + * + */ + private static final long serialVersionUID = -3474557834182380981L; + 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."); + + 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; + + // 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; + 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; + } +} -- cgit