From 1a2947fed2f7cd2cc32fa810ab77d64bf3acb821 Mon Sep 17 00:00:00 2001
From: Ade Lee <alee@redhat.com>
Date: Thu, 26 May 2016 00:48:39 -0400
Subject: [PATCH 317/319] Fix legacy servlets to check realm when requesting
 recovery

---
 .../src/com/netscape/certsrv/kra/IKeyService.java  |  8 +++--
 .../src/com/netscape/kra/KeyRecoveryAuthority.java | 13 +++----
 .../netscape/cms/servlet/key/KeyRequestDAO.java    |  7 ++--
 .../netscape/cms/servlet/key/RecoverBySerial.java  | 42 ++++++++++++++++++----
 4 files changed, 51 insertions(+), 19 deletions(-)

diff --git a/base/common/src/com/netscape/certsrv/kra/IKeyService.java b/base/common/src/com/netscape/certsrv/kra/IKeyService.java
index 9118bc935620039eb1f04c90f4581802ca2e03ab..d3d5ff61e7e510e2555d2d32d7d1d2c692ea2035 100644
--- a/base/common/src/com/netscape/certsrv/kra/IKeyService.java
+++ b/base/common/src/com/netscape/certsrv/kra/IKeyService.java
@@ -20,11 +20,11 @@ package com.netscape.certsrv.kra;
 import java.math.BigInteger;
 import java.util.Hashtable;
 
-import netscape.security.x509.X509CertImpl;
-
 import com.netscape.certsrv.base.EBaseException;
 import com.netscape.certsrv.security.Credential;
 
+import netscape.security.x509.X509CertImpl;
+
 /**
  * An interface representing a recovery service.
  * <P>
@@ -66,10 +66,12 @@ public interface IKeyService {
      *
      * @param kid key identifier
      * @param cert certificate embedded in PKCS12
+     * @param agent agent requesting recovery
+     * @param realm authorization realm
      * @return requestId
      * @exception EBaseException failed to initiate async recovery
      */
-    public String initAsyncKeyRecovery(BigInteger kid, X509CertImpl cert, String agent)
+    public String initAsyncKeyRecovery(BigInteger kid, X509CertImpl cert, String agent, String realm)
             throws EBaseException;
 
     /**
diff --git a/base/kra/src/com/netscape/kra/KeyRecoveryAuthority.java b/base/kra/src/com/netscape/kra/KeyRecoveryAuthority.java
index 8ee8cb2d0a725bf116ef51804a5122008edd21d8..cda3ba659b935139f23f5bae2ac6b1a41c060a8f 100644
--- a/base/kra/src/com/netscape/kra/KeyRecoveryAuthority.java
+++ b/base/kra/src/com/netscape/kra/KeyRecoveryAuthority.java
@@ -28,11 +28,6 @@ import java.util.Hashtable;
 import java.util.StringTokenizer;
 import java.util.Vector;
 
-import netscape.security.util.DerOutputStream;
-import netscape.security.x509.CertificateChain;
-import netscape.security.x509.X500Name;
-import netscape.security.x509.X509CertImpl;
-
 import org.mozilla.jss.CryptoManager;
 import org.mozilla.jss.NoSuchTokenException;
 import org.mozilla.jss.crypto.CryptoToken;
@@ -73,6 +68,11 @@ import com.netscape.cmscore.dbs.KeyRepository;
 import com.netscape.cmscore.dbs.ReplicaIDRepository;
 import com.netscape.cmscore.request.RequestSubsystem;
 
+import netscape.security.util.DerOutputStream;
+import netscape.security.x509.CertificateChain;
+import netscape.security.x509.X500Name;
+import netscape.security.x509.X509CertImpl;
+
 /**
  * A class represents an key recovery authority (KRA). A KRA
  * is responsible to maintain key pairs that have been
@@ -841,7 +841,7 @@ public class KeyRecoveryAuthority implements IAuthority, IKeyService, IKeyRecove
     /**
      * async key recovery initiation
      */
-    public String initAsyncKeyRecovery(BigInteger kid, X509CertImpl cert, String agent)
+    public String initAsyncKeyRecovery(BigInteger kid, X509CertImpl cert, String agent, String realm)
             throws EBaseException {
 
         String auditPublicKey = auditPublicKey(cert);
@@ -861,6 +861,7 @@ public class KeyRecoveryAuthority implements IAuthority, IKeyService, IKeyRecove
             // first one in the "approvingAgents" list is the initiating agent
             r.setExtData(IRequest.ATTR_APPROVE_AGENTS, agent);
             r.setRequestStatus(RequestStatus.PENDING);
+            r.setRealm(realm);
             queue.updateRequest(r);
             auditRecoveryID = r.getRequestId().toString();
 
diff --git a/base/server/cms/src/com/netscape/cms/servlet/key/KeyRequestDAO.java b/base/server/cms/src/com/netscape/cms/servlet/key/KeyRequestDAO.java
index 00e313a80da008ed84f5990cb29680192c3c6cba..8238c10f13a5a4eaceeb10d97f520c1cd1727e88 100644
--- a/base/server/cms/src/com/netscape/cms/servlet/key/KeyRequestDAO.java
+++ b/base/server/cms/src/com/netscape/cms/servlet/key/KeyRequestDAO.java
@@ -321,8 +321,9 @@ public class KeyRequestDAO extends CMSRequestDAO {
             throw new KeyNotFoundException(keyId, "key not found to recover", e);
         }
 
+        String realm = rec.getRealm();
         try {
-            authz.checkRealm(rec.getRealm(), authToken, rec.getOwnerName(), "certServer.kra.key", "recover");
+            authz.checkRealm(realm, authToken, rec.getOwnerName(), "certServer.kra.key", "recover");
         } catch (EAuthzUnknownRealm e) {
             throw new UnauthorizedException("Invalid realm", e);
         } catch (EBaseException e) {
@@ -333,8 +334,8 @@ public class KeyRequestDAO extends CMSRequestDAO {
         byte[] certData = Utils.base64decode(b64Certificate);
         String requestId = null;
         try {
-            requestId = service.initAsyncKeyRecovery(new BigInteger(keyId.toString()), new X509CertImpl(certData), requestor);
-            // TODO - update request with realm
+            requestId = service.initAsyncKeyRecovery(new BigInteger(keyId.toString()),
+                    new X509CertImpl(certData), requestor, realm);
         } catch (EBaseException | CertificateException e) {
             e.printStackTrace();
             throw new PKIException(e.toString(), e);
diff --git a/base/server/cms/src/com/netscape/cms/servlet/key/RecoverBySerial.java b/base/server/cms/src/com/netscape/cms/servlet/key/RecoverBySerial.java
index 7b961c0b2c8329eba9ae386cd2ef79b7bb16036d..baf1f287d41e7d6550ac174f70636370c4b4352f 100644
--- a/base/server/cms/src/com/netscape/cms/servlet/key/RecoverBySerial.java
+++ b/base/server/cms/src/com/netscape/cms/servlet/key/RecoverBySerial.java
@@ -29,16 +29,19 @@ import javax.servlet.ServletOutputStream;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-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.EAuthzAccessDenied;
+import com.netscape.certsrv.authorization.EAuthzException;
 import com.netscape.certsrv.base.EBaseException;
 import com.netscape.certsrv.base.IArgBlock;
 import com.netscape.certsrv.base.SessionContext;
 import com.netscape.certsrv.common.ICMSRequest;
+import com.netscape.certsrv.dbs.EDBRecordNotFoundException;
+import com.netscape.certsrv.dbs.keydb.IKeyRecord;
+import com.netscape.certsrv.dbs.keydb.IKeyRepository;
+import com.netscape.certsrv.dbs.keydb.KeyId;
 import com.netscape.certsrv.kra.IKeyRecoveryAuthority;
 import com.netscape.certsrv.logging.ILogger;
 import com.netscape.certsrv.security.Credential;
@@ -49,6 +52,8 @@ import com.netscape.cms.servlet.common.CMSTemplateParams;
 import com.netscape.cms.servlet.common.ECMSGWException;
 import com.netscape.cmsutil.util.Cert;
 
+import netscape.security.x509.X509CertImpl;
+
 /**
  * A class representing a recoverBySerial servlet.
  *
@@ -83,6 +88,7 @@ public class RecoverBySerial extends CMSServlet {
     private final static String PORT = "port";
 
     private com.netscape.certsrv.kra.IKeyService mService = null;
+    private IKeyRepository repo;
     private String mFormPath = null;
 
     /**
@@ -99,6 +105,7 @@ public class RecoverBySerial extends CMSServlet {
         super.init(sc);
         mFormPath = "/" + mAuthority.getId() + "/" + TPL_FILE;
         mService = (com.netscape.certsrv.kra.IKeyService) mAuthority;
+        repo = ((IKeyRecoveryAuthority) mAuthority).getKeyRepository();
 
         mTemplates.remove(ICMSRequest.SUCCESS);
         if (mOutputTemplatePath != null)
@@ -181,6 +188,27 @@ public class RecoverBySerial extends CMSServlet {
         try {
             String initAsyncRecovery = req.getParameter("initAsyncRecovery");
 
+            // First confirm that the requester has access to the authz realm (if present)
+            KeyId keyId = new KeyId(req.getParameter(IN_SERIALNO));
+            IKeyRecord rec = null;
+            try {
+                rec = repo.readKeyRecord(keyId.toBigInteger());
+            } catch (EDBRecordNotFoundException e) {
+                header.addStringValue(OUT_ERROR, "serialNumber not found");
+                return;
+            }
+
+            String realm = rec.getRealm();
+            try {
+                mAuthz.checkRealm(realm, authToken, rec.getOwnerName(),
+                        mAuthzResourceName, "recover");
+            } catch (EAuthzException e) {
+                log(ILogger.LL_FAILURE,
+                        CMS.getLogMessage("ADMIN_SRVLT_AUTH_FAILURE", e.toString()));
+                cmsReq.setStatus(ICMSRequest.UNAUTHORIZED);
+                return;
+            }
+
             // this information is needed within the server for
             // various signed audit log messages to report
             ctx = SessionContext.getContext();
@@ -198,7 +226,7 @@ public class RecoverBySerial extends CMSServlet {
                 process(form, argSet, header,
                         req.getParameter(IN_SERIALNO),
                         req.getParameter(IN_CERT),
-                        req, resp, locale[0]);
+                        req, resp, locale[0], realm);
 
                 int requiredNumber = mService.getNoOfRequiredAgents();
                 header.addIntegerValue("noOfRequiredAgents", requiredNumber);
@@ -217,7 +245,7 @@ public class RecoverBySerial extends CMSServlet {
                         req.getParameter(IN_CERT),
                         req.getParameter(IN_DELIVERY),
                         req.getParameter(IN_NICKNAME),
-                        req, resp, locale[0]);
+                        req, resp, locale[0], realm);
 
                 if (pkcs12 != null) {
                     //resp.setStatus(HttpServletResponse.SC_OK);
@@ -260,7 +288,7 @@ public class RecoverBySerial extends CMSServlet {
     private void process(CMSTemplate form, CMSTemplateParams argSet,
             IArgBlock header, String seq, String cert,
             HttpServletRequest req, HttpServletResponse resp,
-            Locale locale) {
+            Locale locale, String realm) {
 
         // seq is the key id
         if (seq == null) {
@@ -289,7 +317,7 @@ public class RecoverBySerial extends CMSServlet {
         try {
             String reqID = mService.initAsyncKeyRecovery(
                     new BigInteger(seq), x509cert,
-                      (String) sContext.get(SessionContext.USER_ID));
+                      (String) sContext.get(SessionContext.USER_ID), realm);
             header.addStringValue(OUT_SERIALNO, req.getParameter(IN_SERIALNO));
             header.addStringValue(OUT_SERIALNO_IN_HEX,
                     new BigInteger(req.getParameter(IN_SERIALNO)).toString(16));
@@ -320,7 +348,7 @@ public class RecoverBySerial extends CMSServlet {
             String password, String passwordAgain,
             String cert, String delivery, String nickname,
             HttpServletRequest req, HttpServletResponse resp,
-            Locale locale) {
+            Locale locale, String realm) {
         if (seq == null) {
             header.addStringValue(OUT_ERROR, "sequence number not found");
             return null;
-- 
2.4.3

