From 53d47235cd82bc82ed03743a8900a09a1b35f9c7 Mon Sep 17 00:00:00 2001
From: Endi Sukma Dewata <edewata@redhat.com>
Date: Thu, 25 Oct 2012 11:52:15 -0500
Subject: [PATCH] Enabled authentication for key services.

The web.xml in KRA has been modified to enable the authentication
for key and key request services. Some tools have been added to
access the services via command-line.

Ticket #376
---
 .../com/netscape/certsrv/cert/CertRequestInfo.java |  75 +++++++++++++
 .../netscape/certsrv/cert/CertRequestInfos.java    | 121 +++++++++++++++++++--
 .../src/com/netscape/certsrv/key/KeyClient.java    |  75 +++++++++++++
 .../src/com/netscape/certsrv/key/KeyDataInfo.java  |  43 ++++++++
 .../src/com/netscape/certsrv/key/KeyDataInfos.java |  15 ++-
 .../com/netscape/certsrv/key/KeyRequestInfo.java   |  69 ++++++++++++
 .../com/netscape/certsrv/key/KeyRequestInfos.java  | 120 ++++++++++++++++++--
 .../netscape/certsrv/key/KeyRequestResource.java   |  14 +--
 .../src/com/netscape/certsrv/key/KeyResource.java  |   8 +-
 .../netscape/certsrv/request/CMSRequestInfo.java   |  36 ++++++
 .../netscape/certsrv/request/CMSRequestInfos.java  |  26 ++++-
 .../netscape/cms/servlet/cert/CertRequestDAO.java  |  29 ++---
 .../netscape/cms/servlet/key/KeyRequestDAO.java    |  17 +--
 .../com/netscape/cms/servlet/key/KeyService.java   |  19 +++-
 .../cms/servlet/request/CMSRequestDAO.java         |  19 ++--
 .../cms/servlet/request/KeyRequestService.java     |  15 ++-
 .../src/com/netscape/cmstools/cli/MainCLI.java     |   2 +
 .../src/com/netscape/cmstools/key/KeyCLI.java      | 111 +++++++++++++++++++
 .../{user/UserFindCLI.java => key/KeyFindCLI.java} |  59 +++++-----
 .../netscape/cmstools/key/KeyRequestFindCLI.java   | 120 ++++++++++++++++++++
 .../com/netscape/cmstools/user/UserFindCLI.java    |   2 +-
 base/kra/shared/webapps/kra/WEB-INF/web.xml        |   2 -
 22 files changed, 868 insertions(+), 129 deletions(-)
 create mode 100644 base/common/src/com/netscape/certsrv/key/KeyClient.java
 create mode 100644 base/java-tools/src/com/netscape/cmstools/key/KeyCLI.java
 copy base/java-tools/src/com/netscape/cmstools/{user/UserFindCLI.java => key/KeyFindCLI.java} (50%)
 create mode 100644 base/java-tools/src/com/netscape/cmstools/key/KeyRequestFindCLI.java

diff --git a/base/common/src/com/netscape/certsrv/cert/CertRequestInfo.java b/base/common/src/com/netscape/certsrv/cert/CertRequestInfo.java
index d11e945437e902ca7c5b13760fb091d990f6ece2..0d887a871e69c440c6fb5dc928f6f3588f8457b2 100644
--- a/base/common/src/com/netscape/certsrv/cert/CertRequestInfo.java
+++ b/base/common/src/com/netscape/certsrv/cert/CertRequestInfo.java
@@ -18,6 +18,12 @@
 
 package com.netscape.certsrv.cert;
 
+import java.io.StringReader;
+import java.io.StringWriter;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlElement;
@@ -25,6 +31,7 @@ import javax.xml.bind.annotation.XmlRootElement;
 
 import com.netscape.certsrv.dbs.certdb.CertId;
 import com.netscape.certsrv.request.CMSRequestInfo;
+import com.netscape.certsrv.request.RequestStatus;
 
 @XmlRootElement(name = "CertRequestInfo")
 @XmlAccessorType(XmlAccessType.FIELD)
@@ -82,4 +89,72 @@ public class CertRequestInfo extends CMSRequestInfo {
         return new CertId(id);
     }
 
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((certRequestType == null) ? 0 : certRequestType.hashCode());
+        result = prime * result + ((certURL == null) ? 0 : certURL.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        CertRequestInfo other = (CertRequestInfo) obj;
+        if (certRequestType == null) {
+            if (other.certRequestType != null)
+                return false;
+        } else if (!certRequestType.equals(other.certRequestType))
+            return false;
+        if (certURL == null) {
+            if (other.certURL != null)
+                return false;
+        } else if (!certURL.equals(other.certURL))
+            return false;
+        return true;
+    }
+
+    public String toString() {
+        try {
+            StringWriter sw = new StringWriter();
+            Marshaller marshaller = JAXBContext.newInstance(CertRequestInfo.class).createMarshaller();
+            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
+            marshaller.marshal(this, sw);
+            return sw.toString();
+
+        } catch (Exception e) {
+            return super.toString();
+        }
+    }
+
+    public static CertRequestInfo valueOf(String string) throws Exception {
+        try {
+            Unmarshaller unmarshaller = JAXBContext.newInstance(CertRequestInfo.class).createUnmarshaller();
+            return (CertRequestInfo)unmarshaller.unmarshal(new StringReader(string));
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    public static void main(String args[]) throws Exception {
+
+        CertRequestInfo before = new CertRequestInfo();
+        before.setRequestType("enrollment");
+        before.setRequestStatus(RequestStatus.COMPLETE);
+        before.setCertRequestType("pkcs10");
+
+        String string = before.toString();
+        System.out.println(string);
+
+        CertRequestInfo after = CertRequestInfo.valueOf(string);
+        System.out.println(after);
+
+        System.out.println(before.equals(after));
+    }
 }
diff --git a/base/common/src/com/netscape/certsrv/cert/CertRequestInfos.java b/base/common/src/com/netscape/certsrv/cert/CertRequestInfos.java
index 028bff58338db97497c104aeac9043d0030b21b7..a6a520c2390b081928bd9c05a8432088dcfeb759 100644
--- a/base/common/src/com/netscape/certsrv/cert/CertRequestInfos.java
+++ b/base/common/src/com/netscape/certsrv/cert/CertRequestInfos.java
@@ -17,24 +17,38 @@
 // --- END COPYRIGHT BLOCK ---
 package com.netscape.certsrv.cert;
 
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlElementRef;
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlTransient;
 
 import com.netscape.certsrv.base.Link;
+import com.netscape.certsrv.request.RequestStatus;
 
 @XmlRootElement(name = "CertRequestInfos")
+@XmlAccessorType(XmlAccessType.FIELD)
 public class CertRequestInfos {
-    protected Collection<CertRequestInfo> requests;
-    protected List<Link> links;
+
+    @XmlElementRef
+    protected Collection<CertRequestInfo> requests = new ArrayList<CertRequestInfo>();
+
+    @XmlElement(name = "Links")
+    protected List<Link> links = new ArrayList<Link>();
 
     /**
      * @return the requests
      */
-    @XmlElementRef
     public Collection<CertRequestInfo> getRequests() {
         return requests;
     }
@@ -43,13 +57,21 @@ public class CertRequestInfos {
      * @param requests the requests to set
      */
     public void setRequests(Collection<CertRequestInfo> requests) {
-        this.requests = requests;
+        this.requests.clear();
+        if (requests == null) return;
+        this.requests.addAll(requests);
+    }
+
+    /**
+     * @param requests the request to add
+     */
+    public void addRequest(CertRequestInfo request) {
+        requests.add(request);
     }
 
     /**
      * @return the links
      */
-    @XmlElementRef
     public List<Link> getLinks() {
         return links;
     }
@@ -58,14 +80,20 @@ public class CertRequestInfos {
      * @param links the links to set
      */
     public void setLinks(List<Link> links) {
-        this.links = links;
+        this.links.clear();
+        if (links == null) return;
+        this.links.addAll(links);
+    }
+
+    /**
+     * @param links the link to add
+     */
+    public void addLink(Link link) {
+        links.add(link);
     }
 
     @XmlTransient
     public String getNext() {
-        if (links == null) {
-            return null;
-        }
         for (Link link : links) {
             if ("next".equals(link.getRelationship())) {
                 return link.getHref();
@@ -76,9 +104,6 @@ public class CertRequestInfos {
 
     @XmlTransient
     public String getPrevious() {
-        if (links == null) {
-            return null;
-        }
         for (Link link : links) {
             if ("previous".equals(link.getRelationship())) {
                 return link.getHref();
@@ -86,4 +111,76 @@ public class CertRequestInfos {
         }
         return null;
     }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((links == null) ? 0 : links.hashCode());
+        result = prime * result + ((requests == null) ? 0 : requests.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        CertRequestInfos other = (CertRequestInfos) obj;
+        if (links == null) {
+            if (other.links != null)
+                return false;
+        } else if (!links.equals(other.links))
+            return false;
+        if (requests == null) {
+            if (other.requests != null)
+                return false;
+        } else if (!requests.equals(other.requests))
+            return false;
+        return true;
+    }
+
+    public String toString() {
+        try {
+            StringWriter sw = new StringWriter();
+            Marshaller marshaller = JAXBContext.newInstance(CertRequestInfos.class).createMarshaller();
+            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
+            marshaller.marshal(this, sw);
+            return sw.toString();
+
+        } catch (Exception e) {
+            return super.toString();
+        }
+    }
+
+    public static CertRequestInfos valueOf(String string) throws Exception {
+        try {
+            Unmarshaller unmarshaller = JAXBContext.newInstance(CertRequestInfos.class).createUnmarshaller();
+            return (CertRequestInfos)unmarshaller.unmarshal(new StringReader(string));
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    public static void main(String args[]) throws Exception {
+
+        CertRequestInfos before = new CertRequestInfos();
+
+        CertRequestInfo request = new CertRequestInfo();
+        request.setRequestType("enrollment");
+        request.setRequestStatus(RequestStatus.COMPLETE);
+        request.setCertRequestType("pkcs10");
+        before.addRequest(request);
+
+        String string = before.toString();
+        System.out.println(string);
+
+        CertRequestInfos after = CertRequestInfos.valueOf(string);
+        System.out.println(after);
+
+        System.out.println(request.equals(after));
+    }
 }
diff --git a/base/common/src/com/netscape/certsrv/key/KeyClient.java b/base/common/src/com/netscape/certsrv/key/KeyClient.java
new file mode 100644
index 0000000000000000000000000000000000000000..ce2946c1e0e83854cbddaeed9218e79c73e36df9
--- /dev/null
+++ b/base/common/src/com/netscape/certsrv/key/KeyClient.java
@@ -0,0 +1,75 @@
+//--- 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.certsrv.key;
+
+import java.net.URISyntaxException;
+
+import com.netscape.certsrv.client.ClientConfig;
+import com.netscape.certsrv.client.PKIClient;
+import com.netscape.certsrv.client.PKIConnection;
+import com.netscape.certsrv.request.RequestId;
+
+/**
+ * @author Endi S. Dewata
+ */
+public class KeyClient extends PKIClient {
+
+    public KeyResource keyClient;
+    public KeyRequestResource keyRequestClient;
+
+    public KeyClient(PKIConnection connection) throws URISyntaxException {
+        super(connection);
+        init();
+    }
+
+    public KeyClient(ClientConfig config) throws URISyntaxException {
+        super(config);
+        init();
+    }
+
+    public void init() throws URISyntaxException {
+        keyClient = createProxy(KeyResource.class);
+        keyRequestClient = createProxy(KeyRequestResource.class);
+    }
+
+    public KeyDataInfos findKeys(String clientID, String status, Integer maxSize, Integer maxTime) {
+        return keyClient.listKeys(clientID, status, maxSize, maxTime);
+    }
+
+    public KeyData retrieveKey(KeyRecoveryRequest data) {
+        return keyClient.retrieveKey(data);
+    }
+
+    public KeyRequestInfos findKeyRequests(
+            String requestState,
+            String requestType,
+            String clientID,
+            RequestId start,
+            Integer pageSize,
+            Integer maxResults,
+            Integer maxTime) {
+        return keyRequestClient.listRequests(
+                requestState,
+                requestType,
+                clientID,
+                start,
+                pageSize,
+                maxResults,
+                maxTime);
+    }
+}
diff --git a/base/common/src/com/netscape/certsrv/key/KeyDataInfo.java b/base/common/src/com/netscape/certsrv/key/KeyDataInfo.java
index 3af348ef3b1d268896c8a0a563dae231b4f570e0..09d22871807bf3bf76ead7b5c5944eac6cec8531 100644
--- a/base/common/src/com/netscape/certsrv/key/KeyDataInfo.java
+++ b/base/common/src/com/netscape/certsrv/key/KeyDataInfo.java
@@ -42,6 +42,18 @@ public class KeyDataInfo {
     @XmlElement
     protected String clientID;
 
+    @XmlElement
+    protected String status;
+
+    @XmlElement
+    protected String algorithm;
+
+    @XmlElement
+    protected Integer size;
+
+    @XmlElement
+    protected String ownerName;
+
     public KeyDataInfo() {
         // required for JAXB (defaults)
     }
@@ -82,4 +94,35 @@ public class KeyDataInfo {
         this.clientID = clientID;
     }
 
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    public String getAlgorithm() {
+        return algorithm;
+    }
+
+    public void setAlgorithm(String algorithm) {
+        this.algorithm = algorithm;
+    }
+
+    public Integer getSize() {
+        return size;
+    }
+
+    public void setSize(Integer size) {
+        this.size = size;
+    }
+
+    public String getOwnerName() {
+        return ownerName;
+    }
+
+    public void setOwnerName(String ownerName) {
+        this.ownerName = ownerName;
+    }
 }
diff --git a/base/common/src/com/netscape/certsrv/key/KeyDataInfos.java b/base/common/src/com/netscape/certsrv/key/KeyDataInfos.java
index 4e82f27b51559e532f6938b614df30c6f033b3c3..d9fc885b45be345fc9edf1071facb9aeb09d5a72 100644
--- a/base/common/src/com/netscape/certsrv/key/KeyDataInfos.java
+++ b/base/common/src/com/netscape/certsrv/key/KeyDataInfos.java
@@ -17,6 +17,7 @@
 // --- END COPYRIGHT BLOCK ---
 package com.netscape.certsrv.key;
 
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 
@@ -29,8 +30,8 @@ import com.netscape.certsrv.base.Link;
 @XmlRootElement(name = "KeyDataInfos")
 public class KeyDataInfos {
 
-    protected Collection<KeyDataInfo> keyInfos;
-    protected List<Link> links;
+    protected Collection<KeyDataInfo> keyInfos = new ArrayList<KeyDataInfo>();
+    protected List<Link> links = new ArrayList<Link>();
 
     /**
      * @return the keyInfos
@@ -39,12 +40,21 @@ public class KeyDataInfos {
     public Collection<KeyDataInfo> getKeyInfos() {
         return keyInfos;
     }
+
     /**
      * @param keyInfos the keyInfos to set
      */
     public void setKeyInfos(Collection<KeyDataInfo> keyInfos) {
         this.keyInfos = keyInfos;
     }
+
+    /**
+     * @param keyInfo the keyInfo to add
+     */
+    public void addKeyInfo(KeyDataInfo keyInfo) {
+        keyInfos.add(keyInfo);
+    }
+
     /**
      * @return the links
      */
@@ -52,6 +62,7 @@ public class KeyDataInfos {
     public List<Link> getLinks() {
         return links;
     }
+
     /**
      * @param links the links to set
      */
diff --git a/base/common/src/com/netscape/certsrv/key/KeyRequestInfo.java b/base/common/src/com/netscape/certsrv/key/KeyRequestInfo.java
index f18e60e641fabf9930b391ab9a2c80298fa6c48c..d9e5fbf1c09cbc4f6f66e80b6877a384371ffe6c 100644
--- a/base/common/src/com/netscape/certsrv/key/KeyRequestInfo.java
+++ b/base/common/src/com/netscape/certsrv/key/KeyRequestInfo.java
@@ -18,6 +18,12 @@
 
 package com.netscape.certsrv.key;
 
+import java.io.StringReader;
+import java.io.StringWriter;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlElement;
@@ -25,6 +31,7 @@ import javax.xml.bind.annotation.XmlRootElement;
 
 import com.netscape.certsrv.dbs.keydb.KeyId;
 import com.netscape.certsrv.request.CMSRequestInfo;
+import com.netscape.certsrv.request.RequestStatus;
 
 @XmlRootElement(name = "KeyRequestInfo")
 @XmlAccessorType(XmlAccessType.FIELD)
@@ -58,4 +65,66 @@ public class KeyRequestInfo extends CMSRequestInfo {
     public void setKeyURL(String keyURL) {
         this.keyURL = keyURL;
     }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = super.hashCode();
+        result = prime * result + ((keyURL == null) ? 0 : keyURL.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (!super.equals(obj))
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        KeyRequestInfo other = (KeyRequestInfo) obj;
+        if (keyURL == null) {
+            if (other.keyURL != null)
+                return false;
+        } else if (!keyURL.equals(other.keyURL))
+            return false;
+        return true;
+    }
+
+    public String toString() {
+        try {
+            StringWriter sw = new StringWriter();
+            Marshaller marshaller = JAXBContext.newInstance(KeyRequestInfo.class).createMarshaller();
+            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
+            marshaller.marshal(this, sw);
+            return sw.toString();
+
+        } catch (Exception e) {
+            return super.toString();
+        }
+    }
+
+    public static KeyRequestInfo valueOf(String string) throws Exception {
+        try {
+            Unmarshaller unmarshaller = JAXBContext.newInstance(KeyRequestInfo.class).createUnmarshaller();
+            return (KeyRequestInfo)unmarshaller.unmarshal(new StringReader(string));
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    public static void main(String args[]) throws Exception {
+
+        KeyRequestInfo before = new KeyRequestInfo();
+        before.setRequestType("securityDataEnrollment");
+        before.setRequestStatus(RequestStatus.COMPLETE);
+
+        String string = before.toString();
+        System.out.println(string);
+
+        KeyRequestInfo after = KeyRequestInfo.valueOf(string);
+        System.out.println(after);
+
+        System.out.println(before.equals(after));
+    }
 }
diff --git a/base/common/src/com/netscape/certsrv/key/KeyRequestInfos.java b/base/common/src/com/netscape/certsrv/key/KeyRequestInfos.java
index 1fbd363d36d2b5bedd50e6caf5194e62478fd377..90756f8d3ab5bacf8bd4cd0e90edcf506c916718 100644
--- a/base/common/src/com/netscape/certsrv/key/KeyRequestInfos.java
+++ b/base/common/src/com/netscape/certsrv/key/KeyRequestInfos.java
@@ -17,24 +17,38 @@
 // --- END COPYRIGHT BLOCK ---
 package com.netscape.certsrv.key;
 
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlElementRef;
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlTransient;
 
 import com.netscape.certsrv.base.Link;
+import com.netscape.certsrv.request.RequestStatus;
 
 @XmlRootElement(name = "KeyRequestInfos")
+@XmlAccessorType(XmlAccessType.FIELD)
 public class KeyRequestInfos {
-    protected Collection<KeyRequestInfo> requests;
-    protected List<Link> links;
+
+    @XmlElementRef
+    protected Collection<KeyRequestInfo> requests = new ArrayList<KeyRequestInfo>();
+
+    @XmlElement(name = "Link")
+    protected List<Link> links = new ArrayList<Link>();
 
     /**
      * @return the requests
      */
-    @XmlElementRef
     public Collection<KeyRequestInfo> getRequests() {
         return requests;
     }
@@ -43,13 +57,21 @@ public class KeyRequestInfos {
      * @param requests the requests to set
      */
     public void setRequests(Collection<KeyRequestInfo> requests) {
-        this.requests = requests;
+        this.requests.clear();
+        if (requests == null) return;
+        this.requests.addAll(requests);
+    }
+
+    /**
+     * @param request the request to add
+     */
+    public void addRequest(KeyRequestInfo request) {
+        requests.add(request);
     }
 
     /**
      * @return the links
      */
-    @XmlElementRef
     public List<Link> getLinks() {
         return links;
     }
@@ -58,14 +80,20 @@ public class KeyRequestInfos {
      * @param links the links to set
      */
     public void setLinks(List<Link> links) {
-        this.links = links;
+        this.links.clear();
+        if (links == null) return;
+        this.links.addAll(links);
+    }
+
+    /**
+     * @param links the link to add
+     */
+    public void addLink(Link link) {
+        this.links.add(link);
     }
 
     @XmlTransient
     public String getNext() {
-        if (links == null) {
-            return null;
-        }
         for (Link link : links) {
             if ("next".equals(link.getRelationship())) {
                 return link.getHref();
@@ -76,9 +104,6 @@ public class KeyRequestInfos {
 
     @XmlTransient
     public String getPrevious() {
-        if (links == null) {
-            return null;
-        }
         for (Link link : links) {
             if ("previous".equals(link.getRelationship())) {
                 return link.getHref();
@@ -86,4 +111,75 @@ public class KeyRequestInfos {
         }
         return null;
     }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((links == null) ? 0 : links.hashCode());
+        result = prime * result + ((requests == null) ? 0 : requests.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        KeyRequestInfos other = (KeyRequestInfos) obj;
+        if (links == null) {
+            if (other.links != null)
+                return false;
+        } else if (!links.equals(other.links))
+            return false;
+        if (requests == null) {
+            if (other.requests != null)
+                return false;
+        } else if (!requests.equals(other.requests))
+            return false;
+        return true;
+    }
+
+    public String toString() {
+        try {
+            StringWriter sw = new StringWriter();
+            Marshaller marshaller = JAXBContext.newInstance(KeyRequestInfos.class).createMarshaller();
+            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
+            marshaller.marshal(this, sw);
+            return sw.toString();
+
+        } catch (Exception e) {
+            return super.toString();
+        }
+    }
+
+    public static KeyRequestInfos valueOf(String string) throws Exception {
+        try {
+            Unmarshaller unmarshaller = JAXBContext.newInstance(KeyRequestInfos.class).createUnmarshaller();
+            return (KeyRequestInfos)unmarshaller.unmarshal(new StringReader(string));
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    public static void main(String args[]) throws Exception {
+
+        KeyRequestInfos before = new KeyRequestInfos();
+
+        KeyRequestInfo request = new KeyRequestInfo();
+        request.setRequestType("securityDataEnrollment");
+        request.setRequestStatus(RequestStatus.COMPLETE);
+        before.addRequest(request);
+
+        String string = before.toString();
+        System.out.println(string);
+
+        KeyRequestInfos after = KeyRequestInfos.valueOf(string);
+        System.out.println(after);
+
+        System.out.println(before.equals(after));
+    }
 }
diff --git a/base/common/src/com/netscape/certsrv/key/KeyRequestResource.java b/base/common/src/com/netscape/certsrv/key/KeyRequestResource.java
index 7fecd06106a92aaad2239a2198b3f1d137eb4df0..356fd1569c391b840ff2998a3009964a03367951 100644
--- a/base/common/src/com/netscape/certsrv/key/KeyRequestResource.java
+++ b/base/common/src/com/netscape/certsrv/key/KeyRequestResource.java
@@ -1,7 +1,6 @@
 package com.netscape.certsrv.key;
 
 import javax.ws.rs.Consumes;
-import javax.ws.rs.DefaultValue;
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
 import javax.ws.rs.Path;
@@ -20,11 +19,6 @@ public interface KeyRequestResource {
     public final String PASS_PHRASE_TYPE = "passPhrase";
     public final String ASYMMETRIC_KEY_TYPE = "asymmetricKey";
 
-    public static final int DEFAULT_START = 0;
-    public static final int DEFAULT_PAGESIZE = 20;
-    public static final int DEFAULT_MAXRESULTS = 100;
-    public static final int DEFAULT_MAXTIME = 10;
-
     /**
      * Used to generate list of key requests based on the search parameters
      */
@@ -33,10 +27,10 @@ public interface KeyRequestResource {
     public KeyRequestInfos listRequests(@QueryParam("requestState") String requestState,
                                             @QueryParam("requestType") String requestType,
                                             @QueryParam("clientID") String clientID,
-                                            @DefaultValue(""+DEFAULT_START) @QueryParam("start") RequestId start,
-                                            @DefaultValue(""+DEFAULT_PAGESIZE) @QueryParam("pageSize") int pageSize,
-                                            @DefaultValue(""+DEFAULT_MAXRESULTS) @QueryParam("maxResults") int maxResults,
-                                            @DefaultValue(""+DEFAULT_MAXTIME) @QueryParam("maxTime") int maxTime);
+                                            @QueryParam("start") RequestId start,
+                                            @QueryParam("pageSize") Integer pageSize,
+                                            @QueryParam("maxResults") Integer maxResults,
+                                            @QueryParam("maxTime") Integer maxTime);
 
 
     /**
diff --git a/base/common/src/com/netscape/certsrv/key/KeyResource.java b/base/common/src/com/netscape/certsrv/key/KeyResource.java
index a499ca11fdcd43177bc7e858787ac2fbf4c1966a..50fe82cc313585cbf5c033bd00aff22451779a28 100644
--- a/base/common/src/com/netscape/certsrv/key/KeyResource.java
+++ b/base/common/src/com/netscape/certsrv/key/KeyResource.java
@@ -1,7 +1,6 @@
 package com.netscape.certsrv.key;
 
 import javax.ws.rs.Consumes;
-import javax.ws.rs.DefaultValue;
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
 import javax.ws.rs.Path;
@@ -14,15 +13,12 @@ import javax.ws.rs.core.MultivaluedMap;
 @Path("agent/keys")
 public interface KeyResource {
 
-    public static final int DEFAULT_MAXTIME = 10;
-    public static final int DEFAULT_MAXRESULTS = 100;
-
     @GET
     @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
     public KeyDataInfos listKeys(@QueryParam("clientID") String clientID,
                                  @QueryParam("status") String status,
-                                 @DefaultValue(""+DEFAULT_MAXRESULTS) @QueryParam("maxResults") int maxResults,
-                                 @DefaultValue(""+DEFAULT_MAXTIME) @QueryParam("maxTime") int maxTime);
+                                 @QueryParam("maxResults") Integer maxResults,
+                                 @QueryParam("maxTime") Integer maxTime);
 
 
     /**
diff --git a/base/common/src/com/netscape/certsrv/request/CMSRequestInfo.java b/base/common/src/com/netscape/certsrv/request/CMSRequestInfo.java
index 0be24fbb49df800c6718e764baf9bd4f34cd0d78..f7b34f0a2f25ff2665aa86bc569f71f9ce46b90b 100644
--- a/base/common/src/com/netscape/certsrv/request/CMSRequestInfo.java
+++ b/base/common/src/com/netscape/certsrv/request/CMSRequestInfo.java
@@ -85,4 +85,40 @@ public  class CMSRequestInfo {
         this.requestURL = requestURL;
     }
 
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((requestStatus == null) ? 0 : requestStatus.hashCode());
+        result = prime * result + ((requestType == null) ? 0 : requestType.hashCode());
+        result = prime * result + ((requestURL == null) ? 0 : requestURL.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        CMSRequestInfo other = (CMSRequestInfo) obj;
+        if (requestStatus == null) {
+            if (other.requestStatus != null)
+                return false;
+        } else if (!requestStatus.equals(other.requestStatus))
+            return false;
+        if (requestType == null) {
+            if (other.requestType != null)
+                return false;
+        } else if (!requestType.equals(other.requestType))
+            return false;
+        if (requestURL == null) {
+            if (other.requestURL != null)
+                return false;
+        } else if (!requestURL.equals(other.requestURL))
+            return false;
+        return true;
+    }
 }
diff --git a/base/common/src/com/netscape/certsrv/request/CMSRequestInfos.java b/base/common/src/com/netscape/certsrv/request/CMSRequestInfos.java
index cb07caf71218b6d5e52e9267e38e526eb865ff6c..7e9445dbc69b212cabe1ec36a05eecea0432da6d 100644
--- a/base/common/src/com/netscape/certsrv/request/CMSRequestInfos.java
+++ b/base/common/src/com/netscape/certsrv/request/CMSRequestInfos.java
@@ -17,6 +17,7 @@
 //--- END COPYRIGHT BLOCK ---
 package com.netscape.certsrv.request;
 
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 
@@ -25,8 +26,8 @@ import com.netscape.certsrv.base.Link;
 //Convenience class to simply hold a Collection of CMSRequests and a List of Links.
 public class CMSRequestInfos {
 
-    protected Collection<CMSRequestInfo> requests;
-    protected List<Link> links;
+    protected Collection<CMSRequestInfo> requests = new ArrayList<CMSRequestInfo>();
+    protected List<Link> links = new ArrayList<Link>();
 
     /**
      * @return the requests
@@ -39,7 +40,16 @@ public class CMSRequestInfos {
      * @param requests the requests to set
      */
     public void setRequests(Collection<CMSRequestInfo> requests) {
-        this.requests = requests;
+        this.requests.clear();
+        if (requests == null) return;
+        this.requests.addAll(requests);
+    }
+
+    /**
+     * @param requests the requests to add
+     */
+    public void addRequest(CMSRequestInfo request) {
+        requests.add(request);
     }
 
     /**
@@ -53,7 +63,15 @@ public class CMSRequestInfos {
      * @param links the links to set
      */
     public void setLinks(List<Link> links) {
-        this.links = links;
+        this.links.clear();
+        if (links == null) return;
+        this.links.addAll(links);
     }
 
+    /**
+     * @param links the link to add
+     */
+    public void addLink(Link link) {
+        links.add(link);
+    }
 }
diff --git a/base/common/src/com/netscape/cms/servlet/cert/CertRequestDAO.java b/base/common/src/com/netscape/cms/servlet/cert/CertRequestDAO.java
index bcb19a70b6d7fb15f118d179041e20af899a50d1..4d0fc38b22011e2dec8cce4fac262d7eacc9e0da 100644
--- a/base/common/src/com/netscape/cms/servlet/cert/CertRequestDAO.java
+++ b/base/common/src/com/netscape/cms/servlet/cert/CertRequestDAO.java
@@ -17,7 +17,6 @@
 // --- END COPYRIGHT BLOCK ---
 package com.netscape.cms.servlet.cert;
 
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
@@ -92,29 +91,21 @@ public class CertRequestDAO extends CMSRequestDAO {
     public CertRequestInfos listRequests(String filter, RequestId start, int pageSize, int maxResults, int maxTime,
             UriInfo uriInfo) throws EBaseException {
 
+        CertRequestInfos ret = new CertRequestInfos();
+
         CMSRequestInfos cmsInfos = listCMSRequests(filter, start, pageSize, maxResults, maxTime, uriInfo);
 
-        CertRequestInfos ret = new CertRequestInfos();
-
-        if (cmsInfos == null) {
-            ret.setRequests(null);
-            ret.setLinks(null);
-            return ret;
-        }
-
-        List<CertRequestInfo> list = new ArrayList<CertRequestInfo>();
-        ;
         Collection<? extends CMSRequestInfo> cmsList = cmsInfos.getRequests();
 
         // We absolutely know 100% that this list is a list
         // of CertRequestInfo objects. This is because the method
         // createCMSRequestInfo. Is the only one adding to it
 
-        list = (List<CertRequestInfo>) cmsList;
-
-        ret.setLinks(cmsInfos.getLinks());
+        List<CertRequestInfo> list = (List<CertRequestInfo>) cmsList;
         ret.setRequests(list);
 
+        ret.setLinks(cmsInfos.getLinks());
+
         return ret;
     }
 
@@ -176,6 +167,9 @@ public class CertRequestDAO extends CMSRequestDAO {
      */
     public CertRequestInfos submitRequest(CertEnrollmentRequest data, HttpServletRequest request, UriInfo uriInfo,
             Locale locale) throws EBaseException {
+
+        CertRequestInfos ret = new CertRequestInfos();
+
         HashMap<String, Object> results = null;
         if (data.getIsRenewal()) {
             RenewalProcessor processor = new RenewalProcessor("caProfileSubmit", locale);
@@ -185,16 +179,13 @@ public class CertRequestDAO extends CMSRequestDAO {
             results = processor.processEnrollment(data, request);
         }
 
-        CertRequestInfos ret = new CertRequestInfos();
-        ArrayList<CertRequestInfo> infos = new ArrayList<CertRequestInfo>();
         IRequest reqs[] = (IRequest[]) results.get(Processor.ARG_REQUESTS);
         for (IRequest req : reqs) {
             CertRequestInfo info = CertRequestInfoFactory.create(req, uriInfo);
-            infos.add(info);
+            ret.addRequest(info);
         }
+
         // TODO - what happens if the errorCode is internal error ?
-        ret.setRequests(infos);
-        ret.setLinks(null);
 
         return ret;
     }
diff --git a/base/common/src/com/netscape/cms/servlet/key/KeyRequestDAO.java b/base/common/src/com/netscape/cms/servlet/key/KeyRequestDAO.java
index e64bcb2dcae9b69da58c89174ccddc1629f1a985..bef0455a91b00b5a059bfc06e196c2152aad6828 100644
--- a/base/common/src/com/netscape/cms/servlet/key/KeyRequestDAO.java
+++ b/base/common/src/com/netscape/cms/servlet/key/KeyRequestDAO.java
@@ -17,7 +17,6 @@
 // --- END COPYRIGHT BLOCK ---
 package com.netscape.cms.servlet.key;
 
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Enumeration;
 import java.util.Hashtable;
@@ -85,30 +84,22 @@ public class KeyRequestDAO extends CMSRequestDAO {
     public KeyRequestInfos listRequests(String filter, RequestId start, int pageSize, int maxResults, int maxTime,
             UriInfo uriInfo) throws EBaseException {
 
-        CMSRequestInfos cmsInfos = listCMSRequests(filter, start, pageSize, maxResults, maxTime, uriInfo);
         KeyRequestInfos ret = new KeyRequestInfos();
 
-        if (cmsInfos == null) {
-            ret.setRequests(null);
-            ret.setLinks(null);
-            return ret;
-        }
+        CMSRequestInfos cmsInfos = listCMSRequests(filter, start, pageSize, maxResults, maxTime, uriInfo);
 
-        List<KeyRequestInfo> list = new ArrayList<KeyRequestInfo>();
-        ;
         Collection<? extends CMSRequestInfo> cmsList = cmsInfos.getRequests();
 
         // We absolutely know 100% that this list is a list
         // of KeyRequestInfo objects. This is because the method
         // createCMSRequestInfo. Is the only one adding to it
 
-        list = (List<KeyRequestInfo>) cmsList;
-
-        ret.setLinks(cmsInfos.getLinks());
+        List<KeyRequestInfo> list = (List<KeyRequestInfo>) cmsList;
         ret.setRequests(list);
 
-        return ret;
+        ret.setLinks(cmsInfos.getLinks());
 
+        return ret;
     }
 
     /**
diff --git a/base/common/src/com/netscape/cms/servlet/key/KeyService.java b/base/common/src/com/netscape/cms/servlet/key/KeyService.java
index 4db2fed0a4e35a5985cd9d22fef30c398e7a782d..fe82d5fcd74700ec339a786421c0f8fefd6427ab 100644
--- a/base/common/src/com/netscape/cms/servlet/key/KeyService.java
+++ b/base/common/src/com/netscape/cms/servlet/key/KeyService.java
@@ -20,10 +20,8 @@ package com.netscape.cms.servlet.key;
 
 
 import java.math.BigInteger;
-import java.util.ArrayList;
 import java.util.Enumeration;
 import java.util.Hashtable;
-import java.util.List;
 
 import javax.ws.rs.Path;
 import javax.ws.rs.WebApplicationException;
@@ -56,6 +54,9 @@ import com.netscape.cmsutil.ldap.LDAPUtil;
  */
 public class KeyService extends PKIService implements KeyResource{
 
+    public static final int DEFAULT_MAXRESULTS = 100;
+    public static final int DEFAULT_MAXTIME = 10;
+
     private IKeyRepository repo;
     private IKeyRecoveryAuthority kra;
     private IRequestQueue queue;
@@ -245,16 +246,18 @@ public class KeyService extends PKIService implements KeyResource{
     /**
      * Used to generate list of key infos based on the search parameters
      */
-    public KeyDataInfos listKeys(String clientID, String status, int maxResults, int maxTime) {
+    public KeyDataInfos listKeys(String clientID, String status, Integer maxResults, Integer maxTime) {
         // auth and authz
 
         // get ldap filter
         String filter = createSearchFilter(status, clientID);
         CMS.debug("listKeys: filter is " + filter);
 
+        maxResults = maxResults == null ? DEFAULT_MAXRESULTS : maxResults;
+        maxTime = maxTime == null ? DEFAULT_MAXTIME : maxTime;
+
         KeyDataInfos infos = new KeyDataInfos();
         try {
-            List <KeyDataInfo> list = new ArrayList<KeyDataInfo>();
             Enumeration<IKeyRecord> e = null;
 
             e = repo.searchKeys(filter, maxResults, maxTime);
@@ -265,11 +268,10 @@ public class KeyService extends PKIService implements KeyResource{
             while (e.hasMoreElements()) {
                 IKeyRecord rec = e.nextElement();
                 if (rec != null) {
-                    list.add(createKeyDataInfo(rec));
+                    infos.addKeyInfo(createKeyDataInfo(rec));
                 }
             }
 
-            infos.setKeyInfos(list);
         } catch (EBaseException e) {
             e.printStackTrace();
             throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
@@ -280,6 +282,11 @@ public class KeyService extends PKIService implements KeyResource{
 
     public KeyDataInfo createKeyDataInfo(IKeyRecord rec) throws EBaseException {
         KeyDataInfo ret = new KeyDataInfo();
+        ret.setClientID(rec.getClientId());
+        ret.setStatus(rec.getKeyStatus());
+        ret.setAlgorithm(rec.getAlgorithm());
+        ret.setSize(rec.getKeySize());
+        ret.setOwnerName(rec.getOwnerName());
 
         Path keyPath = KeyResource.class.getAnnotation(Path.class);
         BigInteger serial = rec.getSerialNumber();
diff --git a/base/common/src/com/netscape/cms/servlet/request/CMSRequestDAO.java b/base/common/src/com/netscape/cms/servlet/request/CMSRequestDAO.java
index f7c9f7aae5ab7593c57bbeea6b70031ebc6558b8..e54f8a4c6843151ccb66f24f65fde499fe43700f 100644
--- a/base/common/src/com/netscape/cms/servlet/request/CMSRequestDAO.java
+++ b/base/common/src/com/netscape/cms/servlet/request/CMSRequestDAO.java
@@ -18,8 +18,6 @@
 package com.netscape.cms.servlet.request;
 
 import java.net.URI;
-import java.util.ArrayList;
-import java.util.List;
 
 import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.UriBuilder;
@@ -84,8 +82,8 @@ public abstract class CMSRequestDAO {
      */
     public CMSRequestInfos listCMSRequests(String filter, RequestId start, int pageSize, int maxResults, int maxTime,
             UriInfo uriInfo) throws EBaseException {
-        List<CMSRequestInfo> list = new ArrayList<CMSRequestInfo>();
-        List<Link> links = new ArrayList<Link>();
+
+        CMSRequestInfos ret = new CMSRequestInfos();
         int totalSize = 0;
         int current = 0;
 
@@ -100,7 +98,7 @@ public abstract class CMSRequestDAO {
 
             for (int i = 0; i < numRecords; i++) {
                 IRequest request = vlvlist.getElementAt(i);
-                list.add(createCMSRequestInfo(request, uriInfo));
+                ret.addRequest(createCMSRequestInfo(request, uriInfo));
             }
         } else {
             // The non-vlv requests are indexed, but are not paginated.
@@ -109,13 +107,13 @@ public abstract class CMSRequestDAO {
             IRequestList requests = queue.listRequestsByFilter(filter, maxResults, maxTime);
 
             if (requests == null) {
-                return null;
+                return ret;
             }
             while (requests.hasMoreElements()) {
                 RequestId rid = requests.nextElement();
                 IRequest request = queue.findRequest(rid);
                 if (request != null) {
-                    list.add(createCMSRequestInfo(request, uriInfo));
+                    ret.addRequest(createCMSRequestInfo(request, uriInfo));
                 }
             }
         }
@@ -137,7 +135,7 @@ public abstract class CMSRequestDAO {
             int next = current + pageSize + 1;
             URI nextUri = builder.clone().build(next, pageSize);
             Link nextLink = new Link("next", nextUri.toString(), "application/xml");
-            links.add(nextLink);
+            ret.addLink(nextLink);
         }
 
         // previous link
@@ -145,12 +143,9 @@ public abstract class CMSRequestDAO {
             int previous = current - pageSize;
             URI previousUri = builder.clone().build(previous, pageSize);
             Link previousLink = new Link("previous", previousUri.toString(), "application/xml");
-            links.add(previousLink);
+            ret.addLink(previousLink);
         }
 
-        CMSRequestInfos ret = new CMSRequestInfos();
-        ret.setRequests(list);
-        ret.setLinks(links);
         return ret;
     }
 
diff --git a/base/common/src/com/netscape/cms/servlet/request/KeyRequestService.java b/base/common/src/com/netscape/cms/servlet/request/KeyRequestService.java
index 775c0ed28aad51c7266cc4ddbf8cba67c56a67ef..12f3bb7eefc5ab42cb98063f443dd12b4ff764c6 100644
--- a/base/common/src/com/netscape/cms/servlet/request/KeyRequestService.java
+++ b/base/common/src/com/netscape/cms/servlet/request/KeyRequestService.java
@@ -42,6 +42,11 @@ import com.netscape.cmsutil.ldap.LDAPUtil;
  */
 public class KeyRequestService extends PKIService implements KeyRequestResource {
 
+    public static final int DEFAULT_START = 0;
+    public static final int DEFAULT_PAGESIZE = 20;
+    public static final int DEFAULT_MAXRESULTS = 100;
+    public static final int DEFAULT_MAXTIME = 10;
+
     /**
      * Used to retrieve key request info for a specific request
      */
@@ -169,17 +174,17 @@ public class KeyRequestService extends PKIService implements KeyRequestResource
      * Used to generate list of key requests based on the search parameters
      */
     public KeyRequestInfos listRequests(String requestState, String requestType, String clientID,
-            RequestId start, int pageSize, int maxResults, int maxTime) {
+            RequestId start, Integer pageSize, Integer maxResults, Integer maxTime) {
         // auth and authz
 
         // get ldap filter
         String filter = createSearchFilter(requestState, requestType, clientID);
         CMS.debug("listRequests: filter is " + filter);
 
-        // get start marker
-        if (start == null) {
-            start = new RequestId(KeyRequestResource.DEFAULT_START);
-        }
+        start = start == null ? new RequestId(KeyRequestService.DEFAULT_START) : start;
+        pageSize = pageSize == null ? DEFAULT_PAGESIZE : pageSize;
+        maxResults = maxResults == null ? DEFAULT_MAXRESULTS : maxResults;
+        maxTime = maxTime == null ? DEFAULT_MAXTIME : maxTime;
 
         KeyRequestDAO reqDAO = new KeyRequestDAO();
         KeyRequestInfos requests;
diff --git a/base/java-tools/src/com/netscape/cmstools/cli/MainCLI.java b/base/java-tools/src/com/netscape/cmstools/cli/MainCLI.java
index d7cb293a787e11b73cc32eab8215bd0615285c54..2e661fcc6c152d9cb88c14b161b2bed0f8172223 100644
--- a/base/java-tools/src/com/netscape/cmstools/cli/MainCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/cli/MainCLI.java
@@ -35,6 +35,7 @@ import com.netscape.certsrv.client.ClientConfig;
 import com.netscape.certsrv.client.PKIConnection;
 import com.netscape.cmstools.cert.CertCLI;
 import com.netscape.cmstools.group.GroupCLI;
+import com.netscape.cmstools.key.KeyCLI;
 import com.netscape.cmstools.system.SecurityDomainCLI;
 import com.netscape.cmstools.user.UserCLI;
 
@@ -53,6 +54,7 @@ public class MainCLI extends CLI {
 
         addModule(new CertCLI(this));
         addModule(new GroupCLI(this));
+        addModule(new KeyCLI(this));
         addModule(new SecurityDomainCLI(this));
         addModule(new UserCLI(this));
     }
diff --git a/base/java-tools/src/com/netscape/cmstools/key/KeyCLI.java b/base/java-tools/src/com/netscape/cmstools/key/KeyCLI.java
new file mode 100644
index 0000000000000000000000000000000000000000..f3922d5da1266f82c5f26f6f3204d53b1f2c3f36
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/key/KeyCLI.java
@@ -0,0 +1,111 @@
+// --- 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.cmstools.key;
+
+import java.util.Arrays;
+
+import org.apache.commons.lang.StringUtils;
+
+import com.netscape.certsrv.key.KeyClient;
+import com.netscape.certsrv.key.KeyDataInfo;
+import com.netscape.certsrv.key.KeyRequestInfo;
+import com.netscape.cmstools.cli.CLI;
+import com.netscape.cmstools.cli.MainCLI;
+
+/**
+ * @author Endi S. Dewata
+ */
+public class KeyCLI extends CLI {
+
+    public MainCLI parent;
+    public KeyClient keyClient;
+
+    public KeyCLI(MainCLI parent) {
+        super("key", "Key management commands");
+        this.parent = parent;
+
+        addModule(new KeyFindCLI(this));
+        addModule(new KeyRequestFindCLI(this));
+    }
+
+    public void printHelp() {
+
+        System.out.println("Commands:");
+
+        int leftPadding = 1;
+        int rightPadding = 25;
+
+        for (CLI module : modules.values()) {
+            String label = name + "-" + module.getName();
+
+            int padding = rightPadding - leftPadding - label.length();
+            if (padding < 1)
+                padding = 1;
+
+            System.out.print(StringUtils.repeat(" ", leftPadding));
+            System.out.print(label);
+            System.out.print(StringUtils.repeat(" ", padding));
+            System.out.println(module.getDescription());
+        }
+    }
+
+    public void execute(String[] args) throws Exception {
+
+        keyClient = new KeyClient(parent.connection);
+
+        if (args.length == 0) {
+            printHelp();
+            System.exit(1);
+        }
+
+        String command = args[0];
+        String[] commandArgs = Arrays.copyOfRange(args, 1, args.length);
+
+        if (command == null) {
+            printHelp();
+            System.exit(1);
+        }
+
+        CLI module = getModule(command);
+        if (module != null) {
+            module.execute(commandArgs);
+
+        } else {
+            System.err.println("Error: Invalid command \"" + command + "\"");
+            printHelp();
+            System.exit(1);
+        }
+    }
+
+    public static void printKeyInfo(KeyDataInfo info) {
+        System.out.println("  Key ID: "+info.getKeyId().toHexString());
+        if (info.getClientID() != null) System.out.println("  Client ID: "+info.getClientID());
+        if (info.getStatus() != null) System.out.println("  Status: "+info.getStatus());
+        if (info.getAlgorithm() != null) System.out.println("  Algorithm: "+info.getAlgorithm());
+        if (info.getSize() != null) System.out.println("  Size: "+info.getSize());
+        if (info.getOwnerName() != null) System.out.println("  Owner: "+info.getOwnerName());
+    }
+
+    public static void printKeyRequestInfo(KeyRequestInfo info) {
+        System.out.println("  Request ID: "+info.getRequestId().toHexString());
+        if (info.getKeyId() != null) System.out.println("  Key ID: "+info.getKeyId().toHexString());
+        if (info.getRequestType() != null) System.out.println("  Type: "+info.getRequestType());
+        if (info.getRequestStatus() != null) System.out.println("  Status: "+info.getRequestStatus());
+    }
+}
diff --git a/base/java-tools/src/com/netscape/cmstools/user/UserFindCLI.java b/base/java-tools/src/com/netscape/cmstools/key/KeyFindCLI.java
similarity index 50%
copy from base/java-tools/src/com/netscape/cmstools/user/UserFindCLI.java
copy to base/java-tools/src/com/netscape/cmstools/key/KeyFindCLI.java
index a5b96d1c3cd997db735a1923016cb707d2c72571..014a9b60e3067cf32eb89793554accb8ca590166 100644
--- a/base/java-tools/src/com/netscape/cmstools/user/UserFindCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/key/KeyFindCLI.java
@@ -16,42 +16,51 @@
 // All rights reserved.
 // --- END COPYRIGHT BLOCK ---
 
-package com.netscape.cmstools.user;
+package com.netscape.cmstools.key;
 
 import java.util.Collection;
 
 import org.apache.commons.cli.CommandLine;
 import org.apache.commons.cli.Option;
+import org.apache.commons.cli.ParseException;
 
-import com.netscape.certsrv.user.UserCollection;
-import com.netscape.certsrv.user.UserData;
+import com.netscape.certsrv.key.KeyDataInfo;
+import com.netscape.certsrv.key.KeyDataInfos;
 import com.netscape.cmstools.cli.CLI;
 import com.netscape.cmstools.cli.MainCLI;
 
 /**
  * @author Endi S. Dewata
  */
-public class UserFindCLI extends CLI {
+public class KeyFindCLI extends CLI {
 
-    public UserCLI parent;
+    public KeyCLI parent;
 
-    public UserFindCLI(UserCLI parent) {
-        super("find", "Find users");
+    public KeyFindCLI(KeyCLI parent) {
+        super("find", "Find keys");
         this.parent = parent;
     }
 
     public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " [FILTER] [OPTIONS...]", options);
+        formatter.printHelp(parent.name + "-" + name + " [OPTIONS...]", options);
     }
 
-    public void execute(String[] args) throws Exception {
+    public void execute(String[] args) {
 
-        Option option = new Option(null, "start", true, "Page start");
-        option.setArgName("start");
+        Option option = new Option(null, "client", true, "Client ID");
+        option.setArgName("client ID");
         options.addOption(option);
 
-        option = new Option(null, "size", true, "Page size");
-        option.setArgName("size");
+        option = new Option(null, "status", true, "Status");
+        option.setArgName("status");
+        options.addOption(option);
+
+        option = new Option(null, "maxResults", true, "Maximum results");
+        option.setArgName("max results");
+        options.addOption(option);
+
+        option = new Option(null, "maxTime", true, "Maximum time");
+        option.setArgName("max time");
         options.addOption(option);
 
         CommandLine cmd = null;
@@ -59,30 +68,30 @@ public class UserFindCLI extends CLI {
         try {
             cmd = parser.parse(options, args);
 
-        } catch (Exception e) {
+        } catch (ParseException e) {
             System.err.println("Error: " + e.getMessage());
             printHelp();
             System.exit(1);
         }
 
-        String[] cmdArgs = cmd.getArgs();;
-        String filter = cmdArgs.length > 0 ? cmdArgs[0] : null;
+        String clientID = cmd.getOptionValue("client");
+        String status = cmd.getOptionValue("status");
 
-        String s = cmd.getOptionValue("start");
-        Integer start = s == null ? null : Integer.valueOf(s);
+        String s = cmd.getOptionValue("maxResults");
+        Integer maxResults = s == null ? null : Integer.valueOf(s);
 
-        s = cmd.getOptionValue("size");
-        Integer size = s == null ? null : Integer.valueOf(s);
+        s = cmd.getOptionValue("maxTime");
+        Integer maxTime = s == null ? null : Integer.valueOf(s);
 
-        UserCollection response = parent.client.findUsers(filter, start, size);
+        KeyDataInfos keys = parent.keyClient.findKeys(clientID, status, maxResults, maxTime);
 
-        Collection<UserData> entries = response.getUsers();
+        Collection<KeyDataInfo> entries = keys.getKeyInfos();
 
-        MainCLI.printMessage(entries.size() + " user(s) matched");
+        MainCLI.printMessage(entries.size() + " key(s) matched");
 
         boolean first = true;
 
-        for (UserData userData : entries) {
+        for (KeyDataInfo info : entries) {
 
             if (first) {
                 first = false;
@@ -90,7 +99,7 @@ public class UserFindCLI extends CLI {
                 System.out.println();
             }
 
-            UserCLI.printUser(userData);
+            KeyCLI.printKeyInfo(info);
         }
 
         MainCLI.printMessage("Number of entries returned " + entries.size());
diff --git a/base/java-tools/src/com/netscape/cmstools/key/KeyRequestFindCLI.java b/base/java-tools/src/com/netscape/cmstools/key/KeyRequestFindCLI.java
new file mode 100644
index 0000000000000000000000000000000000000000..83ce4231837f205375c2da5ebfce82876e811a70
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/key/KeyRequestFindCLI.java
@@ -0,0 +1,120 @@
+// --- 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.cmstools.key;
+
+import java.util.Collection;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.ParseException;
+
+import com.netscape.certsrv.key.KeyRequestInfo;
+import com.netscape.certsrv.key.KeyRequestInfos;
+import com.netscape.certsrv.request.RequestId;
+import com.netscape.cmstools.cli.CLI;
+import com.netscape.cmstools.cli.MainCLI;
+
+/**
+ * @author Endi S. Dewata
+ */
+public class KeyRequestFindCLI extends CLI {
+
+    public KeyCLI parent;
+
+    public KeyRequestFindCLI(KeyCLI parent) {
+        super("request-find", "Find key requests");
+        this.parent = parent;
+    }
+
+    public void printHelp() {
+        formatter.printHelp(parent.name + "-" + name + " [OPTIONS...]", options);
+    }
+
+    public void execute(String[] args) {
+
+        Option option = new Option(null, "status", true, "Request status");
+        option.setArgName("status");
+        options.addOption(option);
+
+        option = new Option(null, "type", true, "Request type");
+        option.setArgName("type");
+        options.addOption(option);
+
+        option = new Option(null, "client", true, "Client ID");
+        option.setArgName("client ID");
+        options.addOption(option);
+
+        option = new Option(null, "maxResults", true, "Maximum results");
+        option.setArgName("max results");
+        options.addOption(option);
+
+        option = new Option(null, "maxTime", true, "Maximum time");
+        option.setArgName("max time");
+        options.addOption(option);
+
+        CommandLine cmd = null;
+
+        try {
+            cmd = parser.parse(options, args);
+
+        } catch (ParseException e) {
+            System.err.println("Error: " + e.getMessage());
+            printHelp();
+            System.exit(1);
+        }
+
+        String status = cmd.getOptionValue("status");
+        String type = cmd.getOptionValue("type");
+        String clientID = cmd.getOptionValue("client");
+
+        String s = cmd.getOptionValue("start");
+        RequestId start = s == null ? null : new RequestId(s);
+
+        s = cmd.getOptionValue("pageSize");
+        Integer pageSize = s == null ? null : Integer.valueOf(s);
+
+        s = cmd.getOptionValue("maxResults");
+        Integer maxResults = s == null ? null : Integer.valueOf(s);
+
+        s = cmd.getOptionValue("maxTime");
+        Integer maxTime = s == null ? null : Integer.valueOf(s);
+
+        KeyRequestInfos keys = parent.keyClient.findKeyRequests(
+                status, type, clientID, start, pageSize, maxResults, maxTime);
+
+        Collection<KeyRequestInfo> entries = keys.getRequests();
+
+        MainCLI.printMessage(entries.size() + " key request(s) matched");
+
+        boolean first = true;
+
+        for (KeyRequestInfo info : entries) {
+
+            if (first) {
+                first = false;
+            } else {
+                System.out.println();
+            }
+
+            KeyCLI.printKeyRequestInfo(info);
+        }
+
+        MainCLI.printMessage("Number of entries returned " + entries.size());
+    }
+}
diff --git a/base/java-tools/src/com/netscape/cmstools/user/UserFindCLI.java b/base/java-tools/src/com/netscape/cmstools/user/UserFindCLI.java
index a5b96d1c3cd997db735a1923016cb707d2c72571..187d4596d91421f1f14e2ca3d772f73e8ef35ceb 100644
--- a/base/java-tools/src/com/netscape/cmstools/user/UserFindCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/user/UserFindCLI.java
@@ -65,7 +65,7 @@ public class UserFindCLI extends CLI {
             System.exit(1);
         }
 
-        String[] cmdArgs = cmd.getArgs();;
+        String[] cmdArgs = cmd.getArgs();
         String filter = cmdArgs.length > 0 ? cmdArgs[0] : null;
 
         String s = cmd.getOptionValue("start");
diff --git a/base/kra/shared/webapps/kra/WEB-INF/web.xml b/base/kra/shared/webapps/kra/WEB-INF/web.xml
index ce90b62e62477e62fa14f9cd244835ef0e51a188..ca7d6ea4d767035be13e733e1736c36505d70cf7 100644
--- a/base/kra/shared/webapps/kra/WEB-INF/web.xml
+++ b/base/kra/shared/webapps/kra/WEB-INF/web.xml
@@ -980,7 +980,6 @@
         </user-data-constraint>
     </security-constraint>
 
-    <!--
     <security-constraint>
         <web-resource-collection>
             <web-resource-name>Agent Services</web-resource-name>
@@ -993,7 +992,6 @@
             <transport-guarantee>CONFIDENTIAL</transport-guarantee>
         </user-data-constraint>
     </security-constraint>
-    -->
 
     <login-config>
         <realm-name>Key Recovery Authority</realm-name>
-- 
1.7.11.4

