From 9bbefa1888ea5cdaeaeb48102ce91c7db495b179 Mon Sep 17 00:00:00 2001
From: Jack Magne <jmagne@dhcp-32-224.sjc.redhat.com>
Date: Sun, 29 Apr 2012 19:44:56 -0700
Subject: [PATCH] Provide CA EE Restful interface and test client.

Tickets #144 and #145
Providing the following:

1. Simple EE restful interface for certificates, printing, listing and searching.
2. Simple EE restful interface for certificate enrollment requests.
3. Simple EE restful interface for profiles and profile properties.
4. Simple Test client to exercise the functionality.
5. Created restful client base class inherited by CARestClient and DRMRestClient.
6. Provide simple restful implementations of new interfaces added.

ToDO: Need some more refactoring to base classes for some of the new classes which are similar to classes
in the DRM restful area.
ToDO: Actual certificate enrollment code that will be refactored from existing ProfileSubmitServlet.
---
 .classpath                                         |    2 +
 .../cms/servlet/test/CAErrorInterceptor.java       |   44 +
 .../netscape/cms/servlet/test/CARestClient.java    |  116 +++
 .../src/com/netscape/cms/servlet/test/CATest.java  |  456 ++++++++++
 .../netscape/cms/servlet/test/CMSRestClient.java   |  174 ++++
 base/common/src/CMakeLists.txt                     |   31 +
 .../com/netscape/certsrv/dbs/certdb/CertId.java    |  134 +++
 .../netscape/certsrv/dbs/certdb/CertIdAdapter.java |   37 +
 .../cms/servlet/cert/CertNotFoundException.java    |   47 +
 .../netscape/cms/servlet/cert/CertResource.java    |   40 +
 .../cms/servlet/cert/CertResourceService.java      |  105 +++
 .../netscape/cms/servlet/cert/CertsResource.java   |   33 +
 .../cms/servlet/cert/CertsResourceService.java     |  111 +++
 .../netscape/cms/servlet/cert/model/CertDAO.java   |  250 ++++++
 .../cms/servlet/cert/model/CertDataInfo.java       |   68 ++
 .../cms/servlet/cert/model/CertDataInfos.java      |   89 ++
 .../cms/servlet/cert/model/CertSearchData.java     |  882 ++++++++++++++++++++
 .../cms/servlet/cert/model/CertificateData.java    |   77 ++
 .../servlet/profile/ProfileNotFoundException.java  |   46 +
 .../cms/servlet/profile/ProfileResource.java       |   39 +
 .../servlet/profile/ProfileResourceService.java    |   81 ++
 .../cms/servlet/profile/ProfilesResource.java      |   17 +
 .../servlet/profile/ProfilesResourceService.java   |   39 +
 .../cms/servlet/profile/model/ProfileDAO.java      |  213 +++++
 .../cms/servlet/profile/model/ProfileData.java     |  148 ++++
 .../cms/servlet/profile/model/ProfileDataInfo.java |   72 ++
 .../servlet/profile/model/ProfileDataInfos.java    |   87 ++
 .../cms/servlet/profile/model/ProfileInput.java    |   72 ++
 .../cms/servlet/request/CertRequestResource.java   |   53 ++
 .../request/CertRequestResourceService.java        |  112 +++
 .../cms/servlet/request/CertRequestsResource.java  |   33 +
 .../request/CertRequestsResourceService.java       |   91 ++
 .../cms/servlet/request/model/CertRequestDAO.java  |  231 +++++
 .../cms/servlet/request/model/CertRequestInfo.java |  115 +++
 .../servlet/request/model/CertRequestInfos.java    |   89 ++
 .../request/model/CertRetrievalRequestData.java    |   78 ++
 .../request/model/EnrollmentRequestData.java       |  203 +++++
 .../request/model/ProfileRetrievalRequestData.java |   67 ++
 .../netscape/cms/servlet/test/DRMRestClient.java   |  169 +----
 39 files changed, 4584 insertions(+), 167 deletions(-)
 create mode 100644 base/ca/functional/src/com/netscape/cms/servlet/test/CAErrorInterceptor.java
 create mode 100644 base/ca/functional/src/com/netscape/cms/servlet/test/CARestClient.java
 create mode 100644 base/ca/functional/src/com/netscape/cms/servlet/test/CATest.java
 create mode 100644 base/common/functional/src/com/netscape/cms/servlet/test/CMSRestClient.java
 create mode 100644 base/common/src/com/netscape/certsrv/dbs/certdb/CertId.java
 create mode 100644 base/common/src/com/netscape/certsrv/dbs/certdb/CertIdAdapter.java
 create mode 100644 base/common/src/com/netscape/cms/servlet/cert/CertNotFoundException.java
 create mode 100644 base/common/src/com/netscape/cms/servlet/cert/CertResource.java
 create mode 100644 base/common/src/com/netscape/cms/servlet/cert/CertResourceService.java
 create mode 100644 base/common/src/com/netscape/cms/servlet/cert/CertsResource.java
 create mode 100644 base/common/src/com/netscape/cms/servlet/cert/CertsResourceService.java
 create mode 100644 base/common/src/com/netscape/cms/servlet/cert/model/CertDAO.java
 create mode 100644 base/common/src/com/netscape/cms/servlet/cert/model/CertDataInfo.java
 create mode 100644 base/common/src/com/netscape/cms/servlet/cert/model/CertDataInfos.java
 create mode 100644 base/common/src/com/netscape/cms/servlet/cert/model/CertSearchData.java
 create mode 100644 base/common/src/com/netscape/cms/servlet/profile/ProfileNotFoundException.java
 create mode 100644 base/common/src/com/netscape/cms/servlet/profile/ProfileResource.java
 create mode 100644 base/common/src/com/netscape/cms/servlet/profile/ProfileResourceService.java
 create mode 100644 base/common/src/com/netscape/cms/servlet/profile/ProfilesResource.java
 create mode 100644 base/common/src/com/netscape/cms/servlet/profile/ProfilesResourceService.java
 create mode 100644 base/common/src/com/netscape/cms/servlet/profile/model/ProfileDAO.java
 create mode 100644 base/common/src/com/netscape/cms/servlet/profile/model/ProfileData.java
 create mode 100644 base/common/src/com/netscape/cms/servlet/profile/model/ProfileDataInfo.java
 create mode 100644 base/common/src/com/netscape/cms/servlet/profile/model/ProfileDataInfos.java
 create mode 100644 base/common/src/com/netscape/cms/servlet/profile/model/ProfileInput.java
 create mode 100644 base/common/src/com/netscape/cms/servlet/request/CertRequestResource.java
 create mode 100644 base/common/src/com/netscape/cms/servlet/request/CertRequestResourceService.java
 create mode 100644 base/common/src/com/netscape/cms/servlet/request/CertRequestsResource.java
 create mode 100644 base/common/src/com/netscape/cms/servlet/request/CertRequestsResourceService.java
 create mode 100644 base/common/src/com/netscape/cms/servlet/request/model/CertRequestDAO.java
 create mode 100644 base/common/src/com/netscape/cms/servlet/request/model/CertRequestInfo.java
 create mode 100644 base/common/src/com/netscape/cms/servlet/request/model/CertRequestInfos.java
 create mode 100644 base/common/src/com/netscape/cms/servlet/request/model/CertRetrievalRequestData.java
 create mode 100644 base/common/src/com/netscape/cms/servlet/request/model/EnrollmentRequestData.java
 create mode 100644 base/common/src/com/netscape/cms/servlet/request/model/ProfileRetrievalRequestData.java

diff --git a/.classpath b/.classpath
index 3f38dd9..29ac716 100644
--- a/.classpath
+++ b/.classpath
@@ -14,6 +14,8 @@
 	<classpathentry excluding="**/CMakeLists.txt" kind="src" path="base/util/src"/>
 	<classpathentry excluding="**/CMakeLists.txt" kind="src" path="base/silent/src"/>
 	<classpathentry kind="src" path="base/kra/functional/src"/>
+	<classpathentry kind="src" path="base/ca/functional/src"/>
+	<classpathentry kind="src" path="base/common/functional/src"/>
 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
 	<classpathentry kind="lib" path="/usr/share/java/apache-commons-cli.jar"/>
 	<classpathentry kind="lib" path="/usr/share/java/apache-commons-logging.jar"/>
diff --git a/base/ca/functional/src/com/netscape/cms/servlet/test/CAErrorInterceptor.java b/base/ca/functional/src/com/netscape/cms/servlet/test/CAErrorInterceptor.java
new file mode 100644
index 0000000..d7e3034
--- /dev/null
+++ b/base/ca/functional/src/com/netscape/cms/servlet/test/CAErrorInterceptor.java
@@ -0,0 +1,44 @@
+package com.netscape.cms.servlet.test;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+
+import org.jboss.resteasy.client.ClientResponse;
+import org.jboss.resteasy.client.core.ClientErrorInterceptor;
+
+import com.netscape.cms.servlet.base.CMSException;
+
+public class CAErrorInterceptor implements ClientErrorInterceptor  {
+
+    public void handle(ClientResponse<?> response) {
+
+        // handle HTTP code 4xx and 5xx
+        int code = response.getResponseStatus().getStatusCode();
+        if (code < 400) return;
+
+        MultivaluedMap<String, String> headers = response.getHeaders();
+        String contentType = headers.getFirst("Content-Type");
+
+        // handle XML content only
+        if (!contentType.startsWith(MediaType.TEXT_XML)) return;
+
+        CMSException exception;
+
+        try {
+            // Requires RESTEasy 2.3.2
+            // https://issues.jboss.org/browse/RESTEASY-652
+            CMSException.Data data = response.getEntity(CMSException.Data.class);
+
+            Class<?> clazz = Class.forName(data.className);
+            exception = (CMSException) clazz.getConstructor(CMSException.Data.class).newInstance(data);
+
+        } catch (Exception e) {
+            e.printStackTrace();
+            return;
+        }
+
+        throw exception;
+    }
+
+}
+
diff --git a/base/ca/functional/src/com/netscape/cms/servlet/test/CARestClient.java b/base/ca/functional/src/com/netscape/cms/servlet/test/CARestClient.java
new file mode 100644
index 0000000..98f9443
--- /dev/null
+++ b/base/ca/functional/src/com/netscape/cms/servlet/test/CARestClient.java
@@ -0,0 +1,116 @@
+package com.netscape.cms.servlet.test;
+
+import java.net.URISyntaxException;
+import java.util.Collection;
+import org.jboss.resteasy.client.ProxyFactory;
+import com.netscape.certsrv.dbs.certdb.CertId;
+import com.netscape.certsrv.request.RequestId;
+import com.netscape.cms.servlet.cert.CertResource;
+import com.netscape.cms.servlet.cert.CertsResource;
+import com.netscape.cms.servlet.cert.model.CertDataInfos;
+import com.netscape.cms.servlet.cert.model.CertSearchData;
+import com.netscape.cms.servlet.cert.model.CertificateData;
+import com.netscape.cms.servlet.profile.ProfileResource;
+import com.netscape.cms.servlet.profile.ProfilesResource;
+import com.netscape.cms.servlet.profile.model.ProfileData;
+import com.netscape.cms.servlet.profile.model.ProfileDataInfos;
+import com.netscape.cms.servlet.request.CertRequestResource;
+import com.netscape.cms.servlet.request.CertRequestsResource;
+import com.netscape.cms.servlet.request.model.CertRequestInfo;
+import com.netscape.cms.servlet.request.model.CertRequestInfos;
+import com.netscape.cms.servlet.request.model.CertRetrievalRequestData;
+import com.netscape.cms.servlet.request.model.EnrollmentRequestData;
+import com.netscape.cms.servlet.request.model.ProfileRetrievalRequestData;
+
+
+public class CARestClient extends CMSRestClient {
+
+    private CertResource certClient;
+    private CertsResource certsClient;
+    private CertRequestsResource certRequestsClient;
+    private CertRequestResource certRequestClient;
+    private ProfilesResource profilesClient;
+    private ProfileResource profileClient;
+
+    public CARestClient(String baseUri, String clientCertNick) throws URISyntaxException {
+        
+        super(baseUri,clientCertNick);
+
+        providerFactory.addClientErrorInterceptor(new CAErrorInterceptor());
+
+        certRequestsClient = ProxyFactory.create(CertRequestsResource.class, uri, executor, providerFactory);
+        certRequestClient = ProxyFactory.create(CertRequestResource.class, uri, executor, providerFactory);
+
+        certsClient = ProxyFactory.create(CertsResource.class, uri, executor, providerFactory);
+        certClient = ProxyFactory.create(CertResource.class, uri, executor, providerFactory);
+        profilesClient = ProxyFactory.create(ProfilesResource.class, uri, executor, providerFactory);
+        profileClient = ProxyFactory.create(ProfileResource.class, uri, executor, providerFactory);
+    }
+
+    public Collection<CertRequestInfo> listRequests(String requestState, String requestType) {
+
+        CertRequestInfos infos = null;
+        Collection<CertRequestInfo> list = null;
+        infos = certRequestsClient.listRequests(
+                requestState, requestType, new RequestId(0), 100, 100, 10);
+        list = infos.getRequests();
+
+        return list;
+    }
+
+    public CertDataInfos listCerts(String status) {
+        return certsClient.listCerts(status, 100, 10);
+    }
+
+    public CertDataInfos searchCerts(CertSearchData data) {
+        return certsClient.searchCerts(data);
+    }
+    
+    public ProfileDataInfos listProfiles() {
+        return profilesClient.listProfiles();
+    }
+    
+    public ProfileData getProfile(String id) {
+        
+        if (id == null ) {
+            return null;
+        }
+        
+        ProfileRetrievalRequestData data = null;
+        data = new ProfileRetrievalRequestData();
+        data.setProfileId(id);
+        
+        return profileClient.retrieveProfile(data);
+    }
+
+    public CertificateData getCertData(CertId id) {
+
+        if (id == null) {
+            return null;
+        }
+
+        CertRetrievalRequestData data = null;
+        data = new CertRetrievalRequestData();
+        data.setCertId(id);
+
+        return certClient.retrieveCert(data);
+
+    }
+
+    public CertRequestInfo enrollCertificate(EnrollmentRequestData data) {
+
+        if (data == null) {
+            return null;
+        }
+        return certRequestClient.enrollCert(data);
+    }
+
+    public CertRequestInfo getRequest(RequestId id) {
+
+        if (id == null) {
+            return null;
+        }
+        return certRequestClient.getRequestInfo(id);
+    }
+    
+}
diff --git a/base/ca/functional/src/com/netscape/cms/servlet/test/CATest.java b/base/ca/functional/src/com/netscape/cms/servlet/test/CATest.java
new file mode 100644
index 0000000..d955c66
--- /dev/null
+++ b/base/ca/functional/src/com/netscape/cms/servlet/test/CATest.java
@@ -0,0 +1,456 @@
+package com.netscape.cms.servlet.test;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.apache.commons.cli.PosixParser;
+import org.mozilla.jss.CryptoManager;
+import org.mozilla.jss.crypto.AlreadyInitializedException;
+import org.mozilla.jss.crypto.CryptoToken;
+import org.mozilla.jss.util.Password;
+
+import com.netscape.certsrv.dbs.certdb.CertId;
+import com.netscape.certsrv.request.RequestId;
+import com.netscape.cms.servlet.cert.CertNotFoundException;
+import com.netscape.cms.servlet.cert.model.CertDataInfo;
+import com.netscape.cms.servlet.cert.model.CertDataInfos;
+import com.netscape.cms.servlet.cert.model.CertSearchData;
+import com.netscape.cms.servlet.cert.model.CertificateData;
+import com.netscape.cms.servlet.profile.model.ProfileData;
+import com.netscape.cms.servlet.profile.model.ProfileDataInfo;
+import com.netscape.cms.servlet.profile.model.ProfileDataInfos;
+import com.netscape.cms.servlet.profile.model.ProfileInput;
+import com.netscape.cms.servlet.request.RequestNotFoundException;
+import com.netscape.cms.servlet.request.model.CertRequestInfo;
+import com.netscape.cms.servlet.request.model.EnrollmentRequestData;
+
+public class CATest {
+    
+    private static String clientCertNickname;
+    
+    public static void main(String args[]) {
+        String host = null;
+        String port = null;
+        String token_pwd = null;
+        String db_dir = "./";
+        String protocol = "http";
+
+        // parse command line arguments
+        Options options = new Options();
+        options.addOption("h", true, "Hostname of the CA");
+        options.addOption("p", true, "Port of the CA");
+        options.addOption("s", true, "Attempt Optional Secure SSL connection");
+        options.addOption("w", true, "Token password");
+        options.addOption("d", true, "Directory for tokendb");
+        options.addOption("c", true, "Optional SSL Client cert Nickname");
+
+        try {
+            CommandLineParser parser = new PosixParser();
+            CommandLine cmd = parser.parse(options, args);
+
+            if (cmd.hasOption("h")) {
+                host = cmd.getOptionValue("h");
+            } else {
+                System.err.println("Error: no hostname provided.");
+                usage(options);
+            }
+
+            if (cmd.hasOption("p")) {
+                port = cmd.getOptionValue("p");
+            } else {
+                System.err.println("Error: no port provided");
+                usage(options);
+            }
+
+            if (cmd.hasOption("w")) {
+                token_pwd = cmd.getOptionValue("w");
+            } else {
+                log("Notice: no token password provided");
+            }
+
+            if (cmd.hasOption("d")) {
+                db_dir = cmd.getOptionValue("d");
+            }
+
+            if (cmd.hasOption("s")) {
+                if (cmd.getOptionValue("s") != null && cmd.getOptionValue("s").equals("true")) {
+                    protocol = "https";
+                }
+            }
+
+            if (cmd.hasOption("c")) {
+                String nick = cmd.getOptionValue("c");
+
+                if (nick != null && protocol.equals("https")) {
+                    clientCertNickname = nick;
+                }
+            }
+
+        } catch (ParseException e) {
+            System.err.println("Error in parsing command line options: " + e.getMessage());
+            usage(options);
+        }
+
+        CryptoManager manager = null;
+        CryptoToken token = null;
+
+        // Initialize token
+        try {
+            CryptoManager.initialize(db_dir);
+        } catch (AlreadyInitializedException e) {
+            // it is ok if it is already initialized
+        } catch (Exception e) {
+            log("INITIALIZATION ERROR: " + e.toString());
+            System.exit(1);
+        }
+
+        // log into token
+        try {
+            manager = CryptoManager.getInstance();
+            token = manager.getInternalKeyStorageToken();
+            Password password = new Password(token_pwd.toCharArray());
+            try {
+                token.login(password);
+            } catch (Exception e) {
+                log("login Exception: " + e.toString());
+                if (!token.isLoggedIn()) {
+                    token.initPassword(password, password);
+                }
+            }
+        } catch (Exception e) {
+            log("Exception in logging into token:" + e.toString());
+        }
+
+        String baseUri = protocol + "://" + host + ":" + port + "/ca/pki";
+        CARestClient client;
+        try {
+            client = new CARestClient(baseUri, clientCertNickname);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return;
+        }
+
+        Collection<CertRequestInfo> list = null;
+        try {
+            list = client.listRequests("complete", null);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        printRequests(list);
+
+        //Get a CertInfo
+        int certIdToPrint = 15;
+        CertId id = new CertId(certIdToPrint);
+        CertificateData certData = null;
+        try {
+            certData = client.getCertData(id);
+        } catch (CertNotFoundException e) {
+            e.printStackTrace();
+            log("Cert: " + certIdToPrint + " not found. \n" + e.toString());
+        }
+
+        printCertificate(certData);
+
+        //Try an invalid Cert to print out
+        //Get a CertInfo
+        int certIdBadToPrint = 9999999;
+        CertId certIdBad = new CertId(certIdBadToPrint);
+        CertificateData certDataBad = null;
+        try {
+            certDataBad = client.getCertData(certIdBad);
+        } catch (CertNotFoundException e) {
+            e.printStackTrace();
+            log("Cert: " + certIdBadToPrint + " not found. \n" + e.toString());
+        }
+
+        printCertificate(certDataBad);
+
+        //Get a CertInfoList
+
+        CertDataInfos infos = null;
+        try {
+            infos = client.listCerts("VALID");
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        printCertInfos(infos, "no search filter:");
+
+        //Initiate a Certificate Enrollment
+
+        EnrollmentRequestData data = new EnrollmentRequestData();
+        data.setProfileId("caUserCert");
+        data.setRenewal("false");
+
+        //Simulate a "caUserCert" Profile enrollment
+
+        ProfileInput certReq = data.addInput("Key Generation");
+        certReq.setInputAttr("cert_request_type", "crmf");
+        certReq.setInputAttr(
+                "cert_request",
+                "MIIBozCCAZ8wggEFAgQBMQp8MIHHgAECpQ4wDDEKMAgGA1UEAxMBeKaBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA2NgaPHp0jiohcP4M+ufrJOZEqH8GV+liu5JLbT8nWpkfhC+8EUBqT6g+n3qroSxIcNVGNdcsBEqs1utvpItzyslAbpdyat3WwQep1dWMzo6RHrPDuIoxNA0Yka1n3qEX4U//08cLQtUv2bYglYgN/hOCNQemLV6vZWAv0n7zelkCAwEAAakQMA4GA1UdDwEB/wQEAwIF4DAzMBUGCSsGAQUFBwUBAQwIcmVnVG9rZW4wGgYJKwYBBQUHBQECDA1hdXRoZW50aWNhdG9yoYGTMA0GCSqGSIb3DQEBBQUAA4GBAJ1VOQcaSEhdHa94s8kifVbSZ2WZeYE5//qxL6wVlEst20vq4ybj13CetnbN3+WT49Zkwp7Fg+6lALKgSk47suTg3EbbQDm+8yOrC0nc/q4PTRoHl0alMmUxIhirYc1t3xoCMqJewmjX1bNP8lpVIZAYFZo4eZCpZaiSkM5BeHhz");
+
+        ProfileInput subjectName = data.addInput("Subject Name");
+        subjectName.setInputAttr("sn_uid", "jmagne");
+        subjectName.setInputAttr("sn_e", "jmagne@redhat.com");
+        subjectName.setInputAttr("sn_c", "US");
+        subjectName.setInputAttr("sn_ou", "Development");
+        subjectName.setInputAttr("sn_ou1", "IPA");
+        subjectName.setInputAttr("sn_ou2", "Dogtag");
+        subjectName.setInputAttr("sn_ou3", "CA");
+        subjectName.setInputAttr("sn_cn", "Common");
+        subjectName.setInputAttr("sn_o", "RedHat");
+
+        ProfileInput submitter = data.addInput("Requestor Information");
+        submitter.setInputAttr("requestor_name", "admin");
+        submitter.setInputAttr("requestor_email", "admin@redhat.com");
+        submitter.setInputAttr("requestor_phone", "650-555-5555");
+
+        CertRequestInfo reqInfo = null;
+
+        try {
+            reqInfo = client.enrollCertificate(data);
+        } catch (Exception e) {
+            e.printStackTrace();
+            log(e.toString());
+        }
+
+        printRequestInfo(reqInfo);
+
+        //Perform a sample certificate search with advanced search terms
+
+        CertSearchData searchData = new CertSearchData();
+        searchData.setSerialNumberRangeInUse(true);
+        searchData.setSerialFrom("9999");
+        searchData.setSerialTo("99990");
+
+        infos = client.searchCerts(searchData);
+
+        printCertInfos(infos, searchData.buildFilter());
+
+        // Try to get a non existing request
+
+        RequestId idBad = new RequestId("999999");
+
+        CertRequestInfo infoBad = null;
+
+        try {
+            infoBad = client.getRequest(idBad);
+        } catch (RequestNotFoundException e) {
+            e.printStackTrace();
+            log("Exception getting request #: " + idBad.toString() + "\n" + e.toString());
+        }
+
+        printRequestInfo(infoBad);
+
+        //Perform another sample certificate search with advanced search terms
+
+        searchData = new CertSearchData();
+        searchData.setSubjectInUse(true);
+        searchData.setEmail("jmagne@redhat.com");
+
+        infos = client.searchCerts(searchData);
+
+        printCertInfos(infos, searchData.buildFilter());
+        
+        //Get a list of Profiles
+        
+        
+        
+       ProfileDataInfos pInfos = client.listProfiles();
+       
+       printProfileInfos(pInfos);
+       
+       
+       // Get a specific profile
+       String pId = "caUserCert";
+       ProfileData pData = client.getProfile(pId);
+       
+       printProfileData(pData);
+        
+    }
+
+    private static void printProfileInfos(ProfileDataInfos pInfos) {
+        
+        if (pInfos == null) {
+            log("No ProfileInfos found. \n");
+            return;
+        }
+        
+        Collection<ProfileDataInfo> listProfiles = pInfos.getProfileInfos();
+        Iterator<ProfileDataInfo> iter = null;
+        
+        if (listProfiles != null) {
+            iter = listProfiles.iterator();
+        }
+        
+        log("\nProfiles found. \n");
+        
+        while (iter != null && iter.hasNext()) {
+            ProfileDataInfo info = iter.next();
+            
+            if (info != null) {
+                printProfileDataInfo(info);
+            }
+        }
+    }
+    
+    private static void printProfileDataInfo(ProfileDataInfo info) {
+        if (info == null) {
+            log("No Profile Data Information. \n");
+        }
+        
+        log(" \n Profile Information: \n");
+        log("ProfileURL: " + info.getProfileURL());
+        log("ProfileID: " + info.getProfileId());
+    }
+
+    private static void printProfileData(ProfileData info) {
+        if (info == null) {
+            log("\n No ProfileInformation. \n");
+        }
+        
+        log("Profile Information: \n");
+        log("ProfileID: " + info.getId());
+       log("Name: " + info.getName());
+        log("Description: " + info.getDescription());
+        log("EnabledBy: " + info.getEnabledBy());
+        log("IsEnabled: " + info.getIsEnabled());
+        log("IsVisible: " + info.getIsVisible() + "\n\n");
+        
+        log("Profile Input Information: \n");
+        
+        List<ProfileInput> inputs = info.getProfileInputsList();
+        
+        if (inputs != null) {
+            Iterator<ProfileInput> it= inputs.iterator();
+
+            ProfileInput curInput = null;
+            while(it.hasNext()) {
+                curInput = it.next();
+                
+                if (curInput != null) {
+                    
+                    log("Input Name: " + curInput.getInputId());
+                    
+                    Map<String,String> attrs = curInput.getAttributes();
+                    
+                    if (!attrs.isEmpty()) {
+                        for (String key : attrs.keySet()) {
+                            String value = attrs.get(key);
+                            
+                            log("Input Attribute Name: " + key + "\n");
+                            log("Input Attribute Value: " + value + "\n");
+                        }
+                    }
+                    
+                }
+            }
+            
+        }
+        
+    }
+    
+
+    private static void printCertInfos(CertDataInfos infos, String filter) {
+
+        if (infos == null) {
+            log("No CertInfos found. \n");
+            return;
+        }
+
+        Collection<CertDataInfo> listCerts = infos.getCertInfos();
+        Iterator<CertDataInfo> iter = null;
+
+        if (listCerts != null) {
+            iter = listCerts.iterator();
+        }
+
+        log("\nCertificates found with search filter: " + filter + "\n");
+
+        while (iter != null && iter.hasNext()) {
+            CertDataInfo info = iter.next();
+            if (info != null) {
+                printCertInfo(info);
+            }
+        }
+    }
+
+    private static void printCertInfo(CertDataInfo info) {
+
+        if (info == null) {
+            log("No CertInfo: ");
+            return;
+        }
+        log("CertId: " + info.getCertId().toString());
+        log("CertUrl: " + info.getCertURL());
+
+    }
+
+    private static void printCertificate(CertificateData info) {
+
+        if (info == null) {
+            log("No CertificateData: ");
+            return;
+        }
+
+        log("CertificateInfo: " + "\n");
+        log("-----------------");
+
+        log("CertSerialNo:  \n" + info.getSerialNo() + "\n");
+        log("CertSubject:  \n" + info.getSubjectName() + "\n");
+        log("CertIssuer: \n" + info.getIssuerName() + "\n");
+        log("NotBefore:  \n" + info.getNotBefore() + "\n");
+        log("NotAfter: \n" + info.getNotAfter() + "\n");
+        log("CertBase64: \n" + info.getB64() + "\n");
+        log("CertPKCS7Chain: \n" + info.getPkcs7CertChain() + "\n");
+        log("CertPrettyPrint: \n" + info.getPrettyPrint());
+
+    }
+
+    private static void printRequests(Collection<CertRequestInfo> list) {
+        if (list == null) {
+            log("No requests found");
+            return;
+        }
+
+        Iterator<CertRequestInfo> iter = list.iterator();
+
+        while (iter != null && iter.hasNext()) {
+            CertRequestInfo info = iter.next();
+            printRequestInfo(info);
+        }
+    }
+
+    private static void printRequestInfo(CertRequestInfo info) {
+        if (info == null) {
+            log("No RequestInfo: ");
+            return;
+        }
+
+        log("CertRequestURL: " + info.getRequestURL());
+        log("RequestType: " + info.getCertRequestType());
+        log("Status:        " + info.getRequestStatus());
+        log("Type:          " + info.getRequestType());
+    }
+
+    private static void log(String string) {
+        // TODO Auto-generated method stub
+        System.out.println(string);
+    }
+
+    private static void usage(Options options) {
+        HelpFormatter formatter = new HelpFormatter();
+        formatter.printHelp("CARestClient Test:", options);
+        System.exit(1);
+    }
+
+}
diff --git a/base/common/functional/src/com/netscape/cms/servlet/test/CMSRestClient.java b/base/common/functional/src/com/netscape/cms/servlet/test/CMSRestClient.java
new file mode 100644
index 0000000..2909582
--- /dev/null
+++ b/base/common/functional/src/com/netscape/cms/servlet/test/CMSRestClient.java
@@ -0,0 +1,174 @@
+package com.netscape.cms.servlet.test;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.UnknownHostException;
+import java.util.Enumeration;
+
+import org.apache.commons.httpclient.ConnectTimeoutException;
+import org.apache.http.client.HttpClient;
+import org.apache.http.conn.scheme.LayeredSchemeSocketFactory;
+import org.apache.http.conn.scheme.Scheme;
+import org.apache.http.conn.scheme.SchemeSocketFactory;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.params.HttpParams;
+import org.jboss.resteasy.client.ClientExecutor;
+import org.jboss.resteasy.client.core.executors.ApacheHttpClient4Executor;
+import org.jboss.resteasy.spi.ResteasyProviderFactory;
+import org.mozilla.jss.ssl.SSLCertificateApprovalCallback;
+import org.mozilla.jss.ssl.SSLSocket;
+
+public abstract class CMSRestClient {
+ // Callback to approve or deny returned SSL server certs
+    // Right now, simply approve the cert.
+    // ToDO: Look into taking this JSS http client code and move it into
+    // its own class to be used by possible future clients.
+
+    public CMSRestClient(String baseUri, String clientCertNick) throws URISyntaxException {
+
+        clientCertNickname = clientCertNick;
+
+        uri = new URI(baseUri);
+
+        String protocol = uri.getScheme();
+        int port = uri.getPort();
+
+        HttpClient httpclient = new DefaultHttpClient();
+        if (protocol != null && protocol.equals("https")) {
+
+            Scheme scheme = new Scheme("https", port, new JSSProtocolSocketFactory());
+            httpclient.getConnectionManager().getSchemeRegistry().register(scheme);
+
+        }
+
+        executor = new ApacheHttpClient4Executor(httpclient);
+        providerFactory = ResteasyProviderFactory.getInstance();
+    }
+
+    private class ServerCertApprovalCB implements SSLCertificateApprovalCallback {
+
+        public boolean approve(org.mozilla.jss.crypto.X509Certificate servercert,
+                SSLCertificateApprovalCallback.ValidityStatus status) {
+
+            //For now lets just accept the server cert. This is a test tool, being
+            // pointed at a well know kra instance.
+
+            if (servercert != null) {
+                System.out.println("Peer SSL Servercert details: " +
+                        "\n     subject: " + servercert.getSubjectDN().toString() +
+                        "\n     issuer:  " + servercert.getIssuerDN().toString() +
+                        "\n     serial:  " + servercert.getSerialNumber().toString()
+                        );
+            }
+
+            SSLCertificateApprovalCallback.ValidityItem item;
+
+            Enumeration<?> errors = status.getReasons();
+            int i = 0;
+            while (errors.hasMoreElements()) {
+                i++;
+                item = (SSLCertificateApprovalCallback.ValidityItem) errors.nextElement();
+                System.out.println("item " + i +
+                        " reason=" + item.getReason() +
+                        " depth=" + item.getDepth());
+
+                int reason = item.getReason();
+
+                if (reason ==
+                        SSLCertificateApprovalCallback.ValidityStatus.UNTRUSTED_ISSUER ||
+                        reason == SSLCertificateApprovalCallback.ValidityStatus.BAD_CERT_DOMAIN) {
+
+                    //Allow these two since we haven't necessarily installed the CA cert for trust
+                    // and we are choosing "localhost" as the host for this client.
+
+                    return true;
+
+                }
+            }
+
+            //For other errors return false
+
+            return false;
+        }
+    }
+
+    private class JSSProtocolSocketFactory implements SchemeSocketFactory, LayeredSchemeSocketFactory {
+
+        @Override
+        public Socket createSocket(HttpParams params)
+                throws IOException {
+
+            return null;
+
+        }
+
+        @Override
+        public Socket connectSocket(Socket sock,
+                InetSocketAddress remoteAddress,
+                InetSocketAddress localAddress,
+                HttpParams params)
+                throws IOException,
+                UnknownHostException,
+                ConnectTimeoutException {
+
+            SSLSocket socket;
+
+            String hostName = null;
+            int port = 0;
+            if (remoteAddress != null) {
+                hostName = remoteAddress.getHostName();
+                port = remoteAddress.getPort();
+
+            }
+
+            int localPort = 0;
+            InetAddress localAddr = null;
+
+            if (localAddress != null) {
+                localPort = localAddress.getPort();
+                localAddr = localAddress.getAddress();
+            }
+
+            if (sock == null) {
+                socket = new SSLSocket(InetAddress.getByName(hostName),
+                        port,
+                        localAddr,
+                        localPort,
+                        new ServerCertApprovalCB(),
+                        null);
+
+            } else {
+                socket = new SSLSocket(sock, hostName, new ServerCertApprovalCB(), null);
+            }
+
+            if (socket != null && clientCertNickname != null) {
+                socket.setClientCertNickname(clientCertNickname);
+            }
+
+            return socket;
+        }
+
+        @Override
+        public boolean isSecure(Socket sock) {
+            //We only use this factory in the case of SSL Connections
+            return true;
+        }
+
+        @Override
+        public Socket createLayeredSocket(Socket arg0, String arg1, int arg2, boolean arg3) throws IOException,
+                UnknownHostException {
+            //This method implementation is required to get SSL working.
+            return null;
+        }
+
+    }
+
+    protected static String clientCertNickname;
+    protected ResteasyProviderFactory providerFactory;
+    protected ClientExecutor executor;
+    protected URI uri;
+}
diff --git a/base/common/src/CMakeLists.txt b/base/common/src/CMakeLists.txt
index 43f3a5a..590acc7 100644
--- a/base/common/src/CMakeLists.txt
+++ b/base/common/src/CMakeLists.txt
@@ -216,6 +216,8 @@ set(pki-certsrv_java_SRCS
     com/netscape/certsrv/dbs/certdb/ICertificateRepository.java
     com/netscape/certsrv/dbs/certdb/IRevocationInfo.java
     com/netscape/certsrv/dbs/certdb/ICertRecord.java
+    com/netscape/certsrv/dbs/certdb/CertId.java
+    com/netscape/certsrv/dbs/certdb/CertIdAdapter.java
     com/netscape/certsrv/dbs/DBResources.java
     com/netscape/certsrv/dbs/IDBSearchResults.java
     com/netscape/certsrv/dbs/IFilterConverter.java
@@ -529,7 +531,16 @@ set(pki-cms_java_SRCS
     com/netscape/cms/servlet/cert/CMCRevReqServlet.java
     com/netscape/cms/servlet/cert/GetBySerial.java
     com/netscape/cms/servlet/cert/DisplayCRL.java
+    com/netscape/cms/servlet/cert/CertNotFoundException.java
+    com/netscape/cms/servlet/cert/CertResource.java
+    com/netscape/cms/servlet/cert/CertResourceService.java
+    com/netscape/cms/servlet/cert/CertsResource.java
+    com/netscape/cms/servlet/cert/CertsResourceService.java
     com/netscape/cms/servlet/cert/model/CertificateData.java
+    com/netscape/cms/servlet/cert/model/CertDAO.java
+    com/netscape/cms/servlet/cert/model/CertDataInfo.java
+    com/netscape/cms/servlet/cert/model/CertDataInfos.java
+    com/netscape/cms/servlet/cert/model/CertSearchData.java
     com/netscape/cms/servlet/admin/OCSPAdminServlet.java
     com/netscape/cms/servlet/admin/CMSAdminServlet.java
     com/netscape/cms/servlet/admin/JobsAdminServlet.java
@@ -669,11 +680,21 @@ set(pki-cms_java_SRCS
     com/netscape/cms/servlet/request/KeyRequestResourceService.java
     com/netscape/cms/servlet/request/KeyRequestsResource.java
     com/netscape/cms/servlet/request/KeyRequestsResourceService.java
+    com/netscape/cms/servlet/request/CertRequestResource.java
+    com/netscape/cms/servlet/request/CertRequestResourceService.java
+    com/netscape/cms/servlet/request/CertRequestsResource.java
+    com/netscape/cms/servlet/request/CertRequestsResourceService.java
     com/netscape/cms/servlet/request/model/ArchivalRequestData.java
     com/netscape/cms/servlet/request/model/KeyRequestDAO.java
     com/netscape/cms/servlet/request/model/KeyRequestInfo.java
     com/netscape/cms/servlet/request/model/KeyRequestInfos.java
     com/netscape/cms/servlet/request/model/RecoveryRequestData.java
+    com/netscape/cms/servlet/request/model/CertRequestDAO.java
+    com/netscape/cms/servlet/request/model/CertRequestInfo.java
+    com/netscape/cms/servlet/request/model/CertRequestInfos.java
+    com/netscape/cms/servlet/request/model/CertRetrievalRequestData.java
+    com/netscape/cms/servlet/request/model/EnrollmentRequestData.java 
+    com/netscape/cms/servlet/request/model/ProfileRetrievalRequestData.java
     com/netscape/cms/servlet/tks/TokenServlet.java
     com/netscape/cms/servlet/connector/CloneServlet.java
     com/netscape/cms/servlet/connector/TokenKeyRecoveryServlet.java
@@ -695,6 +716,16 @@ set(pki-cms_java_SRCS
     com/netscape/cms/servlet/profile/ProfileReviewServlet.java
     com/netscape/cms/servlet/profile/SSLClientCertProvider.java
     com/netscape/cms/servlet/profile/ProfileServlet.java
+    com/netscape/cms/servlet/profile/ProfileNotFoundException.java
+    com/netscape/cms/servlet/profile/ProfileResource.java
+    com/netscape/cms/servlet/profile/ProfileResourceService.java
+    com/netscape/cms/servlet/profile/ProfilesResource.java
+    com/netscape/cms/servlet/profile/ProfilesResourceService.java
+    com/netscape/cms/servlet/profile/model/ProfileDAO.java
+    com/netscape/cms/servlet/profile/model/ProfileData.java
+    com/netscape/cms/servlet/profile/model/ProfileDataInfo.java
+    com/netscape/cms/servlet/profile/model/ProfileDataInfos.java
+    com/netscape/cms/servlet/profile/model/ProfileInput.java
     com/netscape/cms/authentication/AgentCertAuthentication.java
     com/netscape/cms/authentication/PortalEnroll.java
     com/netscape/cms/authentication/UdnPwdDirAuthentication.java
diff --git a/base/common/src/com/netscape/certsrv/dbs/certdb/CertId.java b/base/common/src/com/netscape/certsrv/dbs/certdb/CertId.java
new file mode 100644
index 0000000..b29870b
--- /dev/null
+++ b/base/common/src/com/netscape/certsrv/dbs/certdb/CertId.java
@@ -0,0 +1,134 @@
+// --- 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.certsrv.dbs.certdb;
+
+import java.math.BigInteger;
+
+/**
+ * The CertId class represents the identifier for a particular
+ * cert record. This identifier may be used to retrieve the cert record
+ * from the database.
+ * <p>
+ *
+ * @author Endi S. Dewata
+ * @version $Revision$ $Date$
+ */
+// ToDo: Make a common base class for cert id's and key ids
+public class CertId {
+
+    protected BigInteger value;
+
+    /**
+     * Creates a new CertId from its string representation.
+     * <p>
+     *
+     * @param id
+     *            a string containing the decimal or hex value for the identifier.
+     */
+    public CertId(String id) {
+        if (id != null) {
+            id = id.trim();
+            if (id.startsWith("0x")) { // hex
+                value = new BigInteger(id.substring(2), 16);
+            } else { // decimal
+                value = new BigInteger(id);
+            }
+        }
+    }
+
+    /**
+     * Creates a new CertId from its BigInteger representation.
+     * <p>
+     *
+     * @param id
+     *            a BigInteger containing the identifier.
+     */
+    public CertId(BigInteger id) {
+        value = id;
+    }
+
+    /**
+     * Creates a new CertId from its integer representation.
+     * <p>
+     *
+     * @param id
+     *            an integer containing the identifier.
+     */
+    public CertId(int id) {
+        value = BigInteger.valueOf(id);
+    }
+
+    /**
+     * Converts the CertId into its BigInteger representation.
+     * <p>
+     *
+     * @return
+     *         a BigInteger containing the identifier.
+     */
+    public BigInteger toBigInteger() {
+        return value;
+    }
+
+    /**
+     * Converts the CertId into its string representation. The string
+     * form can be stored in a database (such as the LDAP directory)
+     * <p>
+     *
+     * @return
+     *         a string containing the decimal (base 10) value for the identifier.
+     */
+    public String toString() {
+        return value.toString();
+    }
+
+    /**
+     * Converts the CertId into its hex string representation. The string
+     * form can be stored in a database (such as the LDAP directory)
+     *
+     * @return
+     *         a string containing the hex (hex 16) value for the identifier.
+     */
+    public String toHexString() {
+        return "0x"+value.toString(16);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((value == null) ? 0 : value.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;
+        CertId other = (CertId) obj;
+        if (value == null) {
+            if (other.value != null)
+                return false;
+        } else if (!value.equals(other.value))
+            return false;
+        return true;
+    }
+}
diff --git a/base/common/src/com/netscape/certsrv/dbs/certdb/CertIdAdapter.java b/base/common/src/com/netscape/certsrv/dbs/certdb/CertIdAdapter.java
new file mode 100644
index 0000000..b6d8141
--- /dev/null
+++ b/base/common/src/com/netscape/certsrv/dbs/certdb/CertIdAdapter.java
@@ -0,0 +1,37 @@
+// --- 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.certsrv.dbs.certdb;
+
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+
+/**
+ * The CertIdAdapter class provides custom marshaling for CertId.
+ *
+ * @author Endi S. Dewata
+ * @version $Revision$ $Date$
+ */
+public class CertIdAdapter extends XmlAdapter<String,CertId> {
+
+    public CertId unmarshal(String value) throws Exception {
+        return new CertId(value);
+    }
+
+    public String marshal(CertId value) throws Exception {
+        return value.toString();
+    }
+}
diff --git a/base/common/src/com/netscape/cms/servlet/cert/CertNotFoundException.java b/base/common/src/com/netscape/cms/servlet/cert/CertNotFoundException.java
new file mode 100644
index 0000000..ee5142e
--- /dev/null
+++ b/base/common/src/com/netscape/cms/servlet/cert/CertNotFoundException.java
@@ -0,0 +1,47 @@
+package com.netscape.cms.servlet.cert;
+
+
+import javax.ws.rs.core.Response;
+
+import com.netscape.certsrv.dbs.certdb.CertId;
+import com.netscape.cms.servlet.base.CMSException;
+
+public class CertNotFoundException extends CMSException {
+
+    private static final long serialVersionUID = -4784839378360933483L;
+
+    public CertId certId;
+
+    public CertNotFoundException(CertId certId) {
+        this(certId, "Certificate ID "+certId.toHexString()+" not found");
+    }
+
+    public CertNotFoundException(CertId certId, String message) {
+        super(Response.Status.NOT_FOUND, message);
+        this.certId = certId;
+    }
+
+    public CertNotFoundException(CertId certId, String message, Throwable cause) {
+        super(Response.Status.NOT_FOUND, message, cause);
+        this.certId = certId;
+    }
+
+    public CertNotFoundException(Data data) {
+        super(data);
+        certId = new CertId(data.getAttribute("certId"));
+    }
+
+    public Data getData() {
+        Data data = super.getData();
+        data.setAttribute("certId", certId.toString());
+        return data;
+    }
+
+    public CertId getCertId() {
+        return certId;
+    }
+
+    public void setRequestId(CertId certId) {
+        this.certId = certId;
+    }
+}
diff --git a/base/common/src/com/netscape/cms/servlet/cert/CertResource.java b/base/common/src/com/netscape/cms/servlet/cert/CertResource.java
new file mode 100644
index 0000000..1c6fe18
--- /dev/null
+++ b/base/common/src/com/netscape/cms/servlet/cert/CertResource.java
@@ -0,0 +1,40 @@
+package com.netscape.cms.servlet.cert;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+
+import com.netscape.certsrv.dbs.certdb.CertId;
+import com.netscape.cms.servlet.cert.model.CertificateData;
+import com.netscape.cms.servlet.request.model.CertRetrievalRequestData;
+
+@Path("/cert")
+public interface CertResource {
+   
+    @GET
+    @Path("{id}")
+    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.TEXT_XML })
+    public CertificateData retrieveCert(@PathParam("id") CertId id);
+    /**
+     * Used to retrieve a key
+     * @param data
+     * @return
+     */
+    @POST
+    @Path("retrieve")
+    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.TEXT_XML })
+    @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+    public CertificateData retrieveCert(CertRetrievalRequestData data);
+    
+    // retrieval - used to test integration with a browser
+    @POST
+    @Path("retrieve")
+    @Produces(MediaType.TEXT_XML)
+    @Consumes({ MediaType.APPLICATION_FORM_URLENCODED})
+    public CertificateData retrieveCert(MultivaluedMap<String, String> form);
+}
diff --git a/base/common/src/com/netscape/cms/servlet/cert/CertResourceService.java b/base/common/src/com/netscape/cms/servlet/cert/CertResourceService.java
new file mode 100644
index 0000000..7699ac4
--- /dev/null
+++ b/base/common/src/com/netscape/cms/servlet/cert/CertResourceService.java
@@ -0,0 +1,105 @@
+// --- 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) 2011 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package com.netscape.cms.servlet.cert;
+
+
+import java.security.cert.CertificateEncodingException;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+
+import com.netscape.cms.servlet.base.CMSResourceService;
+import com.netscape.cms.servlet.cert.model.CertDAO;
+import com.netscape.cms.servlet.cert.model.CertificateData;
+import com.netscape.cms.servlet.request.model.CertRetrievalRequestData;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.dbs.certdb.CertId;
+
+/**
+ * @author alee
+ * 
+ */
+public class CertResourceService extends CMSResourceService implements CertResource{
+    
+    private final static String CERT_ID = "certId";
+    private CertId validateRequest(CertRetrievalRequestData data) {
+        
+        CertId id;
+        
+        if (data == null) {
+            throw new WebApplicationException(Response.Status.BAD_REQUEST);   
+        }
+        
+        id = data.getCertId();
+            
+        if (id == null) {
+            throw new WebApplicationException(Response.Status.BAD_REQUEST);
+        }
+        
+        return id;
+    }
+
+    @Override
+    public CertificateData retrieveCert(CertRetrievalRequestData data)  {
+        
+        if (data == null) {
+            throw new WebApplicationException(Response.Status.BAD_REQUEST);   
+        }
+        CertDAO dao = new CertDAO();
+        CertId id = validateRequest(data);
+        
+        CertificateData certData = null;
+        
+        try {
+            certData = dao.getCert(data);
+        } catch (CertificateEncodingException e) {
+            e.printStackTrace();
+            throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR); 
+        } catch (EBaseException e) {
+            e.printStackTrace();
+            throw new CertNotFoundException(id);
+        }
+        
+        return certData;
+    }
+
+    @Override
+    public CertificateData retrieveCert(MultivaluedMap<String, String> form) {
+        // TODO Auto-generated method stub
+        
+        CertId certId = null;
+        if (form.containsKey(CERT_ID)) {
+            certId = new CertId(form.getFirst(CERT_ID));
+        }
+
+        return retrieveCert(certId);
+        
+    }
+
+    @Override
+    public CertificateData retrieveCert(CertId id) {
+        CertRetrievalRequestData data = new CertRetrievalRequestData();
+        
+        data.setCertId(id);
+        
+        return retrieveCert(data);
+    }
+
+}
diff --git a/base/common/src/com/netscape/cms/servlet/cert/CertsResource.java b/base/common/src/com/netscape/cms/servlet/cert/CertsResource.java
new file mode 100644
index 0000000..28fe169
--- /dev/null
+++ b/base/common/src/com/netscape/cms/servlet/cert/CertsResource.java
@@ -0,0 +1,33 @@
+package com.netscape.cms.servlet.cert;
+
+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;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+
+import com.netscape.cms.servlet.cert.model.CertDataInfos;
+import com.netscape.cms.servlet.cert.model.CertSearchData;
+ 
+@Path("/certs")
+public interface CertsResource {
+    public static final int DEFAULT_MAXTIME = 10;
+    public static final int DEFAULT_MAXRESULTS = 100;
+    
+    @GET
+    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.TEXT_XML })
+    public CertDataInfos listCerts(
+                                 @QueryParam("status") String status,
+                                 @DefaultValue(""+DEFAULT_MAXRESULTS) @QueryParam("maxResults") int maxResults,
+                                 @DefaultValue(""+DEFAULT_MAXTIME) @QueryParam("maxTime") int maxTime);
+    
+    @POST
+    @Path("search")
+    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.TEXT_XML })
+    @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+    public CertDataInfos searchCerts(CertSearchData data);
+    
+}
diff --git a/base/common/src/com/netscape/cms/servlet/cert/CertsResourceService.java b/base/common/src/com/netscape/cms/servlet/cert/CertsResourceService.java
new file mode 100644
index 0000000..8340191
--- /dev/null
+++ b/base/common/src/com/netscape/cms/servlet/cert/CertsResourceService.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) 2011 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+/**
+ * 
+ */
+package com.netscape.cms.servlet.cert;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Response;
+ 
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.cms.servlet.base.CMSResourceService;
+import com.netscape.cms.servlet.cert.model.CertDAO;
+import com.netscape.cms.servlet.cert.model.CertDataInfos;
+import com.netscape.cms.servlet.cert.model.CertSearchData;
+import com.netscape.cmsutil.ldap.LDAPUtil;
+
+/**
+ * @author alee
+ * 
+ */
+public class CertsResourceService extends CMSResourceService implements CertsResource {
+    
+    private String createSearchFilter(String status) {
+        String filter = "";
+        int matches = 0;
+        
+        if ((status == null)) {
+            filter = "(serialno=*)";
+            return filter;
+        }
+        
+        if (status != null) {
+            filter += "(certStatus=" + LDAPUtil.escape(status) + ")";
+            matches ++;
+        }
+        
+        
+        if (matches > 1) {
+            filter = "(&" + filter + ")";
+        }
+        
+        return filter;
+    }
+    
+    private String createSearchFilter(CertSearchData data) {
+        
+        if (data == null) {
+            return null;
+        }
+        
+        return data.buildFilter();
+        
+    }
+
+    @Override
+    public CertDataInfos listCerts(String status, int maxResults, int maxTime) {
+        
+        // get ldap filter
+        String filter = createSearchFilter(status);
+        CMS.debug("listKeys: filter is " + filter);
+       
+        CertDAO dao = new CertDAO();
+        CertDataInfos infos;
+        try {
+            infos = dao.listCerts(filter, maxResults, maxTime, uriInfo);
+        } catch (EBaseException e) {
+            e.printStackTrace();
+            throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
+        }
+        return infos;
+    }
+
+    @Override
+    public CertDataInfos searchCerts(CertSearchData data) {
+        // TODO Auto-generated method stub
+        
+        if (data == null) {
+            throw new WebApplicationException(Response.Status.BAD_REQUEST);   
+        }
+        String filter = createSearchFilter(data);
+        CertDAO dao = new CertDAO();
+        CertDataInfos infos;
+        
+        try {
+            infos = dao.listCerts(filter, 0, 0, uriInfo);
+        } catch (EBaseException e) {
+            e.printStackTrace();
+            throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
+        }
+        
+        return infos;
+    }
+
+}
diff --git a/base/common/src/com/netscape/cms/servlet/cert/model/CertDAO.java b/base/common/src/com/netscape/cms/servlet/cert/model/CertDAO.java
new file mode 100644
index 0000000..16a3a51
--- /dev/null
+++ b/base/common/src/com/netscape/cms/servlet/cert/model/CertDAO.java
@@ -0,0 +1,250 @@
+// --- 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) 2011 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cms.servlet.cert.model;
+
+import java.io.ByteArrayOutputStream;
+import java.math.BigInteger;
+import java.security.Principal;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.List;
+
+import javax.ws.rs.Path;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+
+import netscape.security.pkcs.ContentInfo;
+import netscape.security.pkcs.PKCS7;
+import netscape.security.pkcs.SignerInfo;
+import netscape.security.x509.AlgorithmId;
+import netscape.security.x509.X509CertImpl;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.ca.ICertificateAuthority;
+import com.netscape.certsrv.dbs.certdb.CertId;
+import com.netscape.certsrv.dbs.certdb.ICertRecord;
+import com.netscape.certsrv.dbs.certdb.ICertificateRepository;
+import com.netscape.cms.servlet.cert.CertResource;
+import com.netscape.cms.servlet.request.model.CertRetrievalRequestData;
+import com.netscape.cmsutil.util.Utils;
+
+/**
+ * @author alee
+ *
+ */
+public class CertDAO {
+
+    private ICertificateRepository repo;
+    private ICertificateAuthority ca;
+    
+    public CertDAO() {
+        ca = ( ICertificateAuthority ) CMS.getSubsystem( "ca" );
+        repo = ca.getCertificateRepository();
+    }
+    /**
+     * Returns list of certs meeting specified search filter.
+     * Currently, vlv searches are not used for certs.
+     * 
+     * @param filter
+     * @param maxResults
+     * @param maxTime
+     * @param uriInfo
+     * @return
+     * @throws EBaseException
+     */
+    public CertDataInfos listCerts(String filter, int maxResults, int maxTime, UriInfo uriInfo) 
+        throws EBaseException {
+        List <CertDataInfo> list = new ArrayList<CertDataInfo>();
+        Enumeration<ICertRecord> e = null;
+        
+        e = repo.searchCertificates(filter, maxResults, maxTime); 
+        if (e == null) {
+            throw new EBaseException("search results are null");
+        }
+        
+        while (e.hasMoreElements()) {
+            ICertRecord rec = e.nextElement();
+            if (rec != null) {
+                list.add(createCertDataInfo(rec, uriInfo));
+            }
+        }
+        
+        CertDataInfos ret = new CertDataInfos();
+        ret.setCertInfos(list);
+        
+        return ret;
+    }
+    
+    public CertificateData getCert(CertRetrievalRequestData data) throws EBaseException, CertificateEncodingException {
+        
+        CertificateData certData = null; 
+        CertId certId = data.getCertId();
+        
+        //find the cert in question
+        
+        ICertRecord rec = null;
+        BigInteger seq = certId.toBigInteger();
+        
+        rec = (ICertRecord) repo.readCertificateRecord(seq);
+        X509CertImpl x509cert = null;
+        
+        if (rec != null) {
+            x509cert  = rec.getCertificate();
+        }
+
+        if (x509cert != null) {
+           certData = new CertificateData();
+            
+            byte[] ba = null;
+            String encoded64 = null;
+            
+            ba = x509cert.getEncoded();
+
+            encoded64 = Utils.base64encode(ba);
+            
+            String prettyPrint = x509cert.toString();
+
+            certData.setB64(encoded64);
+            certData.setPrettyPrint(prettyPrint);
+            
+            String subjectNameStr = null;
+            Principal subjectName = x509cert.getSubjectDN();
+            
+            if (subjectName != null) {
+                subjectNameStr = subjectName.toString();
+            }
+            
+            certData.setSubjectName(subjectNameStr);
+            
+            //Try to get the chain
+            
+            String p7Str = getCertChainData(x509cert);
+            
+            certData.setPkcs7CertChain(p7Str);
+            
+            BigInteger serial = x509cert.getSerialNumber();
+            
+            String serialStr = null;
+            
+            if (serial != null) {
+                serialStr = serial.toString();
+            }
+            certData.setSerialNo(serialStr);
+            
+            Date notBefore = x509cert.getNotBefore();
+            Date notAfter  = x509cert.getNotAfter();
+            
+            String notBeforeStr = null;
+            String notAfterStr =  null;
+            
+            if (notBefore != null) {
+                notBeforeStr = notBefore.toString();
+            }
+            
+            if (notAfter != null) {
+                notAfterStr = notAfter.toString();
+            }
+            
+            certData.setNotBefore(notBeforeStr);
+            certData.setNotAfter(notAfterStr);
+            
+            String issuerNameStr = null;
+            
+            Principal issuerName = x509cert.getIssuerDN();
+            
+            if (issuerName != null) {
+                issuerNameStr = issuerName.toString();
+            }
+            
+            certData.setIssuerName(issuerNameStr);
+            
+        }
+        
+        return certData;
+    }
+    
+    private CertDataInfo createCertDataInfo(ICertRecord rec, UriInfo uriInfo) throws EBaseException {
+        CertDataInfo ret = new CertDataInfo();
+
+        Path certPath = CertResource.class.getAnnotation(Path.class);
+        BigInteger serial = rec.getSerialNumber();
+
+        UriBuilder certBuilder = uriInfo.getBaseUriBuilder();
+        certBuilder.path(certPath.value() + "/" + serial);
+        ret.setCertURL(certBuilder.build().toString());
+
+        return ret;
+    }
+    
+    private String getCertChainData(X509CertImpl x509cert) {
+        
+        X509Certificate mCACerts[];
+        
+        try {
+            mCACerts = ca.getCACertChain().getChain();
+        } catch (Exception e) {
+            mCACerts = null;
+        }
+        
+        X509CertImpl[] certsInChain = new X509CertImpl[1];
+        ;
+        if (mCACerts != null) {
+            for (int i = 0; i < mCACerts.length; i++) {
+                if (x509cert.equals(mCACerts[i])) {
+                    certsInChain = new
+                            X509CertImpl[mCACerts.length];
+                    break;
+                }
+                certsInChain = new X509CertImpl[mCACerts.length + 1];
+            }
+        }
+
+        certsInChain[0] = x509cert;
+
+        if (mCACerts != null) {
+            for (int i = 0; i < mCACerts.length; i++) {
+                if (!x509cert.equals(mCACerts[i]))
+                    certsInChain[i + 1] = (X509CertImpl) mCACerts[i];
+            }
+        }
+
+        String p7Str;
+
+        try {
+            PKCS7 p7 = new PKCS7(new AlgorithmId[0],
+                    new ContentInfo(new byte[0]),
+                    certsInChain,
+                    new SignerInfo[0]);
+            ByteArrayOutputStream bos = new ByteArrayOutputStream();
+
+            p7.encodeSignedData(bos, false);
+            byte[] p7Bytes = bos.toByteArray();
+
+            p7Str = Utils.base64encode(p7Bytes);
+        } catch (Exception e) {
+            p7Str = null;
+        }
+        
+    
+    return p7Str;
+    }
+}
diff --git a/base/common/src/com/netscape/cms/servlet/cert/model/CertDataInfo.java b/base/common/src/com/netscape/cms/servlet/cert/model/CertDataInfo.java
new file mode 100644
index 0000000..3b1d724
--- /dev/null
+++ b/base/common/src/com/netscape/cms/servlet/cert/model/CertDataInfo.java
@@ -0,0 +1,68 @@
+// --- 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) 2011 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+/**
+ * 
+ */
+package com.netscape.cms.servlet.cert.model;
+
+ 
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlAccessorType;
+
+import com.netscape.certsrv.dbs.certdb.CertId;
+
+/**
+ * @author alee
+ *
+ */
+@XmlRootElement(name="CertDataInfo")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class CertDataInfo {
+    
+    @XmlElement
+    protected String certURL;
+    
+    public CertDataInfo() {
+        // required for JAXB (defaults)
+    }
+
+    /**
+     * @return the CertURL
+     */
+    public String getCertURL() {
+        return certURL;
+    }
+
+    /**
+     * @param CertURL the certURL to set
+     */
+    public void setCertURL(String certURL) {
+        this.certURL = certURL;
+    }
+
+    /**
+     * @return the Cert ID in the CertURL
+     */
+    public CertId getCertId() {
+        String id = certURL.substring(certURL.lastIndexOf("/") + 1);
+        return new CertId(id);
+    }
+   
+}
diff --git a/base/common/src/com/netscape/cms/servlet/cert/model/CertDataInfos.java b/base/common/src/com/netscape/cms/servlet/cert/model/CertDataInfos.java
new file mode 100644
index 0000000..b24b551
--- /dev/null
+++ b/base/common/src/com/netscape/cms/servlet/cert/model/CertDataInfos.java
@@ -0,0 +1,89 @@
+
+//--- 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.cms.servlet.cert.model;
+
+import java.util.Collection;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlElementRef;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlTransient;
+
+import com.netscape.cms.servlet.base.model.Link;
+
+@XmlRootElement(name = "CertDataInfos")
+public class CertDataInfos {
+ 
+ protected Collection<CertDataInfo> certInfos;
+ protected List<Link> links;
+ 
+ /**
+  * @return the CertInfos
+  */
+ @XmlElementRef
+ public Collection<CertDataInfo> getCertInfos() {
+     return certInfos;
+ }
+ /**
+  * @param certInfos the CertInfos to set
+  */
+ public void setCertInfos(Collection<CertDataInfo> certInfos) {
+     this.certInfos = certInfos;
+ }
+ /**
+  * @return the links
+  */
+ @XmlElementRef
+ public List<Link> getLinks() {
+     return links;
+ }
+ /**
+  * @param links the links to set
+  */
+ public void setLinks(List<Link> links) {
+     this.links = links;
+ }
+ 
+ @XmlTransient
+ public String getNext() {
+     if (links == null) {
+         return null;
+     }
+     for (Link link : links) {
+         if ("next".equals(link.getRelationship())) {
+             return link.getHref();
+         }
+     }
+     return null;
+ }
+
+ @XmlTransient
+ public String getPrevious() {
+     if (links == null) {
+         return null;
+     }
+     for (Link link : links) {
+         if ("previous".equals(link.getRelationship())) {
+             return link.getHref();
+         }
+     }
+     return null;
+ }
+}
+
diff --git a/base/common/src/com/netscape/cms/servlet/cert/model/CertSearchData.java b/base/common/src/com/netscape/cms/servlet/cert/model/CertSearchData.java
new file mode 100644
index 0000000..c6af462
--- /dev/null
+++ b/base/common/src/com/netscape/cms/servlet/cert/model/CertSearchData.java
@@ -0,0 +1,882 @@
+//--- 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) 2011 Red Hat, Inc.
+//All rights reserved.
+//--- END COPYRIGHT BLOCK ---
+
+// ToDo: This class is brute force. Come up with a way to divide these search filter entities into
+// smaller classes
+package com.netscape.cms.servlet.cert.model;
+
+import java.util.Calendar;
+import java.util.StringTokenizer;
+
+import javax.ws.rs.core.MultivaluedMap;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * @author jmagne
+ * 
+ */
+@XmlRootElement(name = "CertSearchData")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class CertSearchData {
+    //Serial Number
+    @XmlElement
+    protected boolean serialNumberRangeInUse;
+
+    @XmlElement
+    protected String serialTo;
+
+    @XmlElement
+    protected String serialFrom;
+
+    //Subject Name
+    @XmlElement
+    protected boolean subjectInUse;
+
+    @XmlElement
+    protected String eMail;
+
+    @XmlElement
+    protected String commonName;
+
+    @XmlElement
+    protected String userID;
+
+    @XmlElement
+    protected String orgUnit;
+
+    @XmlElement
+    protected String org;
+
+    @XmlElement
+    protected String locality;
+
+    @XmlElement
+    protected String state;
+
+    @XmlElement
+    protected String country;
+
+    @XmlElement
+    protected boolean matchExactly;
+
+    //Revoked By
+
+    @XmlElement
+    protected String revokedBy;
+
+    //Revoked On
+
+    @XmlElement
+    protected String revokedOnFrom;
+
+    @XmlElement
+    protected String revokedOnTo;
+
+    //Revocation Reason
+
+    @XmlElement
+    protected String revocationReason;
+
+    //Issued By
+
+    @XmlElement
+    protected String issuedBy;
+
+    //Issued On
+
+    @XmlElement
+    protected String issuedOnFrom;
+
+    @XmlElement
+    protected String issuedOnTo;
+
+    //Valid Not Before
+
+    @XmlElement
+    protected String validNotBeforeFrom;
+
+    @XmlElement
+    protected String validNotBeforeTo;
+
+    //Valid Not After
+
+    @XmlElement
+    protected String validNotAfterFrom;
+
+    @XmlElement
+    protected String validNotAfterTo;
+
+    //Validity Length
+
+    @XmlElement
+    protected String validityOperation;
+
+    @XmlElement
+    protected String validityCount;
+
+    @XmlElement
+    protected String validityUnit;
+
+    // Cert Type
+
+    @XmlElement
+    protected String certTypeSubEmailCA;
+
+    @XmlElement
+    protected String certTypeSubSSLCA;
+
+    @XmlElement
+    protected String certTypeSecureEmail;
+
+    @XmlElement
+    protected String certTypeSSLClient;
+
+    @XmlElement
+    protected String certTypeSSLServer;
+
+    //Revoked By
+    @XmlElement
+    protected boolean revokedByInUse;
+
+    //Revoked On
+    @XmlElement
+    protected boolean revokedOnInUse;
+
+    @XmlElement
+    protected boolean revocationReasonInUse;
+
+    @XmlElement
+    protected boolean issuedByInUse;
+
+    @XmlElement
+    protected boolean issuedOnInUse;
+
+    @XmlElement
+    protected boolean validNotBeforeInUse;
+
+    @XmlElement
+    protected boolean validNotAfterInUse;
+
+    @XmlElement
+    protected boolean validityLengthInUse;
+
+    @XmlElement
+    protected boolean certTypeInUse;
+
+    //Boolean values 
+    public boolean getSerialNumberRangeInUse() {
+        return serialNumberRangeInUse;
+    }
+
+    public void setSerialNumberRangeInUse(boolean serialNumberRangeInUse) {
+        this.serialNumberRangeInUse = serialNumberRangeInUse;
+    }
+
+    public boolean getSubjectInUse() {
+        return subjectInUse;
+    }
+
+    public void setSubjectInUse(boolean subjectInUse) {
+        this.subjectInUse = subjectInUse;
+    }
+
+    public boolean getRevokedByInUse() {
+        return revokedByInUse;
+    }
+
+    public void setRevokedByInUse(boolean revokedByInUse) {
+        this.revokedByInUse = revokedByInUse;
+    }
+
+    public boolean getRevokedOnInUse() {
+        return revokedOnInUse;
+    }
+
+    public void setRevokedOnInUse(boolean revokedOnInUse) {
+        this.revokedOnInUse = revokedOnInUse;
+    }
+
+    public void setRevocationReasonInUse(boolean revocationReasonInUse) {
+        this.revocationReasonInUse = revocationReasonInUse;
+    }
+
+    public boolean getRevocationReasonInUse() {
+        return revocationReasonInUse;
+    }
+
+    public void setIssuedByInUse(boolean issuedByInUse) {
+        this.issuedByInUse = issuedByInUse;
+    }
+
+    public boolean getIssuedByInUse() {
+        return issuedByInUse;
+    }
+
+    public void setIssuedOnInUse(boolean issuedOnInUse) {
+        this.issuedOnInUse = issuedOnInUse;
+    }
+
+    public boolean getIssuedOnInUse() {
+        return issuedOnInUse;
+    }
+
+    public void setValidNotBeforeInUse(boolean validNotBeforeInUse) {
+        this.validNotBeforeInUse = validNotBeforeInUse;
+    }
+
+    public boolean getValidNotBeforeInUse() {
+        return validNotBeforeInUse;
+    }
+
+    public void setValidNotAfterInUse(boolean validNotAfterInUse) {
+        this.validNotAfterInUse = validNotAfterInUse;
+    }
+
+    public boolean getValidNotAfterInUse() {
+        return validNotAfterInUse;
+    }
+
+    public void setValidityLengthInUse(boolean validityLengthInUse) {
+        this.validityLengthInUse = validityLengthInUse;
+    }
+
+    public boolean getValidityLengthInUse() {
+        return validityLengthInUse;
+    }
+
+    public void setCertTypeInUse(boolean certTypeInUse) {
+        this.certTypeInUse = certTypeInUse;
+    }
+
+    public boolean getCertTypeInUse() {
+        return certTypeInUse;
+    }
+
+    //Actual Values
+
+    public String getSerialTo() {
+        return serialTo;
+    }
+
+    public void setSerialTo(String serialTo) {
+        this.serialTo = serialTo;
+    }
+
+    public String getSerialFrom() {
+        return serialFrom;
+    }
+
+    public void setSerialFrom(String serialFrom) {
+        this.serialFrom = serialFrom;
+    }
+
+    //Subject Name
+
+    public String getEmail() {
+        return eMail;
+    }
+
+    public void setEmail(String email) {
+        this.eMail = email;
+    }
+
+    public String getCommonName() {
+        return commonName;
+    }
+
+    public void setCommonName(String commonName) {
+        this.commonName = commonName;
+    }
+
+    public String getUserID() {
+        return userID;
+    }
+
+    public void setUserID(String userID) {
+        this.userID = userID;
+    }
+
+    public String getOrgUnit() {
+        return orgUnit;
+    }
+
+    public void setOrgUnit(String orgUnit) {
+        this.orgUnit = orgUnit;
+    }
+
+    public String getOrg() {
+        return org;
+    }
+
+    public void setOrg(String org) {
+        this.org = org;
+    }
+
+    public String getLocality() {
+        return locality;
+    }
+
+    public void setLocality(String locality) {
+        this.locality = locality;
+    }
+
+    public String getState() {
+        return state;
+    }
+
+    public void setState(String state) {
+        this.state = state;
+    }
+
+    public String getCountry() {
+        return country;
+    }
+
+    public void setCountry(String country) {
+        this.country = country;
+    }
+
+    public boolean getMatchExactly() {
+        return matchExactly;
+    }
+
+    public void setMatchExactly(boolean matchExactly) {
+        this.matchExactly = matchExactly;
+    }
+
+    //Revoked On
+
+    public String getRevokedOnTo() {
+        return revokedOnTo;
+    }
+
+    public void setRevokedOnTo(String revokedOnTo) {
+        this.revokedOnTo = revokedOnTo;
+    }
+
+    public String getRevokedOnFrom() {
+        return revokedOnFrom;
+    }
+
+    public void setRevokedOnFrom(String revokedOnFrom) {
+        this.revokedOnFrom = revokedOnFrom;
+    }
+
+    //Revoked By
+
+    public String getRevokedBy() {
+        return revokedBy;
+    }
+
+    public void setRevokedBy(String revokedBy) {
+        this.revokedBy = revokedBy;
+    }
+
+    //Revocation Reason
+
+    public String getRevocationReason() {
+        return revocationReason;
+    }
+
+    public void setRevocationReason(String revocationReason) {
+        this.revocationReason = revocationReason;
+    }
+
+    //Issued By
+
+    public String getIssuedBy() {
+        return issuedBy;
+    }
+
+    public void setIssuedBy(String issuedBy) {
+        this.issuedBy = issuedBy;
+    }
+
+    //Issued On
+
+    public String getIssuedOnFrom() {
+        return issuedOnFrom;
+    }
+
+    public void setIssuedOnFrom(String issuedOnFrom) {
+        this.issuedOnFrom = issuedOnFrom;
+    }
+
+    public String getIssuedOnTo() {
+        return getIssuedOnTo();
+    }
+
+    //Valid Not After
+
+    public String getValidNotAfterFrom() {
+        return validNotAfterFrom;
+    }
+
+    public void setValidNotAfterFrom(String validNotAfterFrom) {
+        this.validNotAfterFrom = validNotAfterFrom;
+    }
+
+    public String getValidNotAfterTo() {
+        return validNotAfterTo;
+    }
+
+    public void setValidNotAfterTo(String validNotAfterTo) {
+        this.validNotAfterTo = validNotAfterTo;
+    }
+
+    //Valid Not Before
+
+    public String getValidNotBeforeFrom() {
+        return validNotBeforeFrom;
+    }
+
+    public void setValidNotBeforeFrom(String validNotBeforeFrom) {
+        this.validNotBeforeFrom = validNotBeforeFrom;
+    }
+
+    public String getValidNotBeforeTo() {
+        return validNotBeforeTo;
+    }
+
+    public void setValidNotBeforeTo(String validNotBeforeTo) {
+        this.validNotBeforeTo = validNotBeforeTo;
+    }
+
+    //Validity Length
+
+    public String getValidityOperation() {
+        return validityOperation;
+    }
+
+    public void setValidityOperation(String validityOperation) {
+        this.validityOperation = validityOperation;
+    }
+
+    public String getValidityUnit() {
+        return validityUnit;
+    }
+
+    public void setValidityUnit(String validityUnit) {
+        this.validityUnit = validityUnit;
+    }
+
+    public String getValidityCount() {
+        return validityCount;
+    }
+
+    public void setValidityCount(String validityCount) {
+        this.validityCount = validityCount;
+    }
+
+    //Cert Type
+
+    String getCertTypeSubEmailCA() {
+        return certTypeSubEmailCA;
+    }
+
+    void setCertTypeSubEmailCA(String certTypeSubEmailCA) {
+        this.certTypeSubEmailCA = certTypeSubEmailCA;
+    }
+
+    public String getCertTypeSubSSLCA() {
+        return certTypeSubSSLCA;
+    }
+
+    public void setCertTypeSubSSLCA(String certTypeSubSSLCA) {
+        this.certTypeSubSSLCA = certTypeSubSSLCA;
+    }
+
+    public String getCertTypeSecureEmail() {
+        return certTypeSecureEmail;
+    }
+
+    public String getCertTypeSSLClient() {
+        return certTypeSSLClient;
+    }
+
+    public void setCertTypeSSLClient(String SSLClient) {
+        this.certTypeSSLClient = SSLClient;
+    }
+
+    public String getCertTypeSSLServer() {
+        return certTypeSSLServer;
+    }
+
+    public void setCertTypeSSLServer(String SSLServer) {
+        this.certTypeSSLServer = SSLServer;
+    }
+
+    public CertSearchData() {
+        // required for JAXB (defaults)
+    }
+
+    public void buildFromServletRequest(HttpServletRequest req) {
+        //Set values from the servlet request
+        if (req == null) {
+            return;
+        }
+    }
+
+    public CertSearchData(MultivaluedMap<String, String> form) {
+    }
+
+    public String buildFilter() {
+        StringBuffer filter = new StringBuffer();
+        buildSerialNumberRangeFilter(filter);
+        buildSubjectFilter(filter);
+        buildRevokedByFilter(filter);
+        buildRevokedOnFilter(filter);
+        buildRevocationReasonFilter(filter);
+        buildIssuedByFilter(filter);
+        buildIssuedOnFilter(filter);
+        buildValidNotBeforeFilter(filter);
+        buildValidNotAfterFilter(filter);
+        buildValidityLengthFilter(filter);
+        buildCertTypeFilter(filter);
+
+        searchFilter = filter.toString();
+
+        if (searchFilter != null && !searchFilter.equals("")) {
+            searchFilter = "(&" + searchFilter + ")";
+        }
+
+        return searchFilter;
+    }
+
+    private void buildSerialNumberRangeFilter(StringBuffer filter) {
+
+        if (!this.getSerialNumberRangeInUse()) {
+            return;
+        }
+        boolean changed = false;
+        String serialFrom = this.getSerialFrom();
+        if (serialFrom != null && !serialFrom.equals("")) {
+            filter.append("(certRecordId>=" + serialFrom + ")");
+            changed = true;
+        }
+        String serialTo = this.getSerialTo();
+        if (serialTo != null && !serialTo.equals("")) {
+            filter.append("(certRecordId<=" + serialTo + ")");
+            changed = true;
+        }
+        if (!changed) {
+            filter.append("(certRecordId=*)");
+        }
+
+    }
+
+    private void buildSubjectFilter(StringBuffer filter) {
+        if (!this.getSubjectInUse()) {
+            return;
+        }
+        StringBuffer lf = new StringBuffer();
+
+        String matchStr = null;
+        boolean match = this.getMatchExactly();
+
+        matchStr = new Boolean(match).toString();
+
+        buildAVAFilter(this.getEmail(), "E", lf, matchStr);
+        buildAVAFilter(this.getCommonName(), "CN", lf, matchStr);
+        buildAVAFilter(this.getUserID(), "UID", lf, matchStr);
+        buildAVAFilter(this.getOrgUnit(), "OU", lf, matchStr);
+        buildAVAFilter(this.getOrg(), "O", lf, matchStr);
+        buildAVAFilter(this.getLocality(), "L", lf, matchStr);
+        buildAVAFilter(this.getState(), "ST", lf, matchStr);
+        buildAVAFilter(this.getCountry(), "C", lf, matchStr);
+
+        if (lf.length() == 0) {
+            filter.append("(x509cert.subject=*)");
+            return;
+        }
+        if (matchStr.equals("exact")) {
+            filter.append("(&");
+            filter.append(lf);
+            filter.append(")");
+        } else {
+            filter.append("(|");
+            filter.append(lf);
+            filter.append(")");
+        }
+    }
+
+    private void buildRevokedByFilter(StringBuffer filter) {
+        if (!this.getRevokedByInUse()) {
+            return;
+        }
+
+        String revokedBy = this.getRevokedBy();
+        if (revokedBy == null || revokedBy.equals("")) {
+            filter.append("(certRevokedBy=*)");
+        } else {
+            filter.append("(certRevokedBy=");
+            filter.append(revokedBy);
+            filter.append(")");
+        }
+    }
+
+    private void buildDateFilter(String prefix,
+            String outStr, long adjustment,
+            StringBuffer filter) {
+        long epoch = 0;
+        try {
+            epoch = Long.parseLong(prefix);
+        } catch (NumberFormatException e) {
+            // exception safely ignored
+        }
+        Calendar from = Calendar.getInstance();
+        from.setTimeInMillis(epoch);
+        filter.append("(");
+        filter.append(outStr);
+        filter.append(Long.toString(from.getTimeInMillis() + adjustment));
+        filter.append(")");
+    }
+
+    private void buildRevokedOnFilter(StringBuffer filter) {
+        if (!this.getRevokedOnInUse()) {
+            return;
+        }
+        buildDateFilter(this.getRevokedOnFrom(), "certRevokedOn>=", 0, filter);
+        buildDateFilter(this.getRevokedOnTo(), "certRevokedOn<=", 86399999, filter);
+    }
+
+    private void buildRevocationReasonFilter(StringBuffer filter) {
+        if (!this.getRevocationReasonInUse()) {
+            return;
+        }
+        String reasons = this.getRevocationReason();
+        if (reasons == null) {
+            return;
+        }
+        String queryCertFilter = null;
+        StringTokenizer st = new StringTokenizer(reasons, ",");
+        if (st.hasMoreTokens()) {
+            filter.append("(|");
+            while (st.hasMoreTokens()) {
+                String token = st.nextToken();
+                if (queryCertFilter == null) {
+                    queryCertFilter = "";
+                }
+                filter.append("(x509cert.certRevoInfo=");
+                filter.append(token);
+                filter.append(")");
+            }
+            filter.append(")");
+        }
+    }
+
+    private void buildIssuedByFilter(StringBuffer filter) {
+        if (!this.getIssuedByInUse()) {
+            return;
+        }
+        String issuedBy = this.getIssuedBy();
+        ;
+        if (issuedBy == null || issuedBy.equals("")) {
+            filter.append("(certIssuedBy=*)");
+        } else {
+            filter.append("(certIssuedBy=");
+            filter.append(issuedBy);
+            filter.append(")");
+        }
+    }
+
+    private void buildIssuedOnFilter(StringBuffer filter) {
+        if (!this.getIssuedOnInUse()) {
+            return;
+        }
+        buildDateFilter(this.getIssuedOnFrom(), "certCreateTime>=", 0, filter);
+        buildDateFilter(this.getIssuedOnTo(), "certCreateTime<=", 86399999, filter);
+    }
+
+    private void buildValidNotBeforeFilter(StringBuffer filter) {
+        if (!this.getValidNotBeforeInUse()) {
+            return;
+        }
+        buildDateFilter(this.validNotBeforeFrom, "x509cert.notBefore>=", 0, filter);
+        buildDateFilter(this.validNotBeforeTo, "x509cert.notBefore<=", 86399999, filter);
+
+    }
+
+    private void buildValidNotAfterFilter(StringBuffer filter) {
+        if (!this.getValidNotAfterInUse()) {
+            return;
+        }
+        buildDateFilter(this.getValidNotAfterFrom(), "x509cert.notAfter>=", 0, filter);
+        buildDateFilter(this.getValidNotAfterTo(), "x509cert.notAfter<=", 86399999, filter);
+
+    }
+
+    private void buildValidityLengthFilter(StringBuffer filter) {
+        if (!this.getValidityLengthInUse()) {
+            return;
+        }
+        String op = this.getValidityOperation();
+        long count = 0;
+        try {
+            count = Long.parseLong(this.getValidityCount());
+        } catch (NumberFormatException e) {
+            // safely ignore
+        }
+        long unit = 0;
+        try {
+            unit = Long.parseLong(this.getValidityUnit());
+        } catch (NumberFormatException e) {
+            // safely ignore
+        }
+        filter.append("(");
+        filter.append("x509cert.duration");
+        filter.append(op);
+        filter.append(count * unit);
+        filter.append(")");
+    }
+
+    private void buildCertTypeFilter(StringBuffer filter) {
+        if (!this.getCertTypeInUse()) {
+            return;
+        }
+        if (isOn(this.getCertTypeSSLClient())) {
+            filter.append("(x509cert.nsExtension.SSLClient=on)");
+        } else if (isOff(this.getCertTypeSSLClient())) {
+            filter.append("(x509cert.nsExtension.SSLClient=off)");
+        }
+        if (isOn(this.getCertTypeSSLServer())) {
+            filter.append("(x509cert.nsExtension.SSLServer=on)");
+        } else if (isOff(this.getCertTypeSSLServer())) {
+            filter.append("(x509cert.nsExtension.SSLServer=off)");
+        }
+        if (isOn(this.getCertTypeSecureEmail())) {
+            filter.append("(x509cert.nsExtension.SecureEmail=on)");
+        } else if (isOff(this.getCertTypeSecureEmail())) {
+            filter.append("(x509cert.nsExtension.SecureEmail=off)");
+        }
+        if (isOn(this.getCertTypeSubSSLCA())) {
+            filter.append("(x509cert.nsExtension.SubordinateSSLCA=on)");
+        } else if (isOff(this.getCertTypeSubSSLCA())) {
+            filter.append("(x509cert.nsExtension.SubordinateSSLCA=off)");
+        }
+        if (isOn(this.getCertTypeSubEmailCA())) {
+            filter.append("(x509cert.nsExtension.SubordinateEmailCA=on)");
+        } else if (isOff(this.getCertTypeSubEmailCA())) {
+            filter.append("(x509cert.nsExtension.SubordinateEmailCA=off)");
+        }
+    }
+
+    private boolean isOn(String value) {
+        String inUse = value;
+        if (inUse == null) {
+            return false;
+        }
+        if (inUse.equals("on")) {
+            return true;
+        }
+        return false;
+    }
+
+    private boolean isOff(String value) {
+        String inUse = value;
+        if (inUse == null) {
+            return false;
+        }
+        if (inUse.equals("off")) {
+            return true;
+        }
+        return false;
+    }
+
+    private void buildAVAFilter(String param,
+            String avaName, StringBuffer lf, String match) {
+        if (param != null && !param.equals("")) {
+            if (match != null && match.equals("exact")) {
+                lf.append("(|");
+                lf.append("(x509cert.subject=*");
+                lf.append(avaName);
+                lf.append("=");
+                lf.append(escapeValueRfc1779(param, true));
+                lf.append(",*)");
+                lf.append("(x509cert.subject=*");
+                lf.append(avaName);
+                lf.append("=");
+                lf.append(escapeValueRfc1779(param, true));
+                lf.append(")");
+                lf.append(")");
+            } else {
+                lf.append("(x509cert.subject=*");
+                lf.append(avaName);
+                lf.append("=");
+                lf.append("*");
+                lf.append(escapeValueRfc1779(param, true));
+                lf.append("*)");
+            }
+        }
+    }
+
+    // ToDo: Where to put this so everyone can use it?
+    protected StringBuffer escapeValueRfc1779(String v, boolean doubleEscape) {
+        StringBuffer result = new StringBuffer();
+
+        // Do we need to escape any characters
+        for (int i = 0; i < v.length(); i++) {
+            int c = v.charAt(i);
+            if (c == ',' || c == '=' || c == '+' || c == '<' ||
+                    c == '>' || c == '#' || c == ';' || c == '\r' ||
+                    c == '\n' || c == '\\' || c == '"') {
+                if ((c == 0x5c) && ((i + 1) < v.length())) {
+                    int nextC = v.charAt(i + 1);
+                    if ((c == 0x5c) && (nextC == ',' || nextC == '=' || nextC == '+' ||
+                            nextC == '<' || nextC == '>' || nextC == '#' ||
+                            nextC == ';' || nextC == '\r' || nextC == '\n' ||
+                            nextC == '\\' || nextC == '"')) {
+                        if (doubleEscape)
+                            result.append('\\');
+                    } else {
+                        result.append('\\');
+                        if (doubleEscape)
+                            result.append('\\');
+                    }
+                } else {
+                    result.append('\\');
+                    if (doubleEscape)
+                        result.append('\\');
+                }
+            }
+            if (c == '\r') {
+                result.append("0D");
+            } else if (c == '\n') {
+                result.append("0A");
+            } else {
+                result.append((char) c);
+            }
+        }
+        return result;
+    }
+
+    private String searchFilter = null;
+    
+    
+    public String getSearchFilter() {
+        return searchFilter;
+    }
+    
+    public void setSearchFilter(String searchFilter) {
+        this.searchFilter = searchFilter;
+    }
+}
diff --git a/base/common/src/com/netscape/cms/servlet/cert/model/CertificateData.java b/base/common/src/com/netscape/cms/servlet/cert/model/CertificateData.java
index 30623ce..6816245 100644
--- a/base/common/src/com/netscape/cms/servlet/cert/model/CertificateData.java
+++ b/base/common/src/com/netscape/cms/servlet/cert/model/CertificateData.java
@@ -31,6 +31,27 @@ import javax.xml.bind.annotation.XmlElement;
 public class CertificateData {
     @XmlElement
     private String b64;
+    
+    @XmlElement
+    private String prettyPrint;
+    
+    @XmlElement
+    private String subjectName;
+    
+    @XmlElement
+    private String pkcs7CertChain;
+
+    @XmlElement
+    private String serialNo;
+    
+    @XmlElement
+    private String notBefore;
+    
+    @XmlElement
+    private String notAfter;
+    
+    @XmlElement
+    private String issuerName;
 
     public CertificateData() {
         // required for jaxb
@@ -50,4 +71,60 @@ public class CertificateData {
         this.b64 = b64;
     }
 
+    public String getPrettyPrint() {
+        return prettyPrint;
+    }
+    
+    public void setPrettyPrint(String prettyPrint) {
+        this.prettyPrint = prettyPrint;
+    }
+    
+    public void setPkcs7CertChain(String chain) {
+        this.pkcs7CertChain = chain;
+    }
+    
+    public String getPkcs7CertChain() {
+        return pkcs7CertChain;
+    }
+    
+    public String getSubjectName() {
+        return subjectName;
+    }
+    
+    public void setSubjectName(String subjectName) {
+        this.subjectName = subjectName;
+    }
+    
+    public String getSerialNo() {
+        return serialNo;
+    }
+    
+    public void setSerialNo(String serialNo) {
+        this.serialNo = serialNo;
+    }
+    
+    public String getNotBefore() {
+        return notBefore;
+    }
+    
+    public void setNotBefore(String notBefore) {
+        this.notBefore = notBefore;
+    }
+    
+    public String getNotAfter() {
+        return notAfter;
+    }
+    
+    public void setNotAfter(String notAfter) {
+        this.notAfter = notAfter;
+    }
+    
+    public String getIssuerName() {
+        return issuerName;
+    }
+    
+    public void setIssuerName(String issuerName) {
+        this.issuerName = issuerName;
+    }
+    
 }
diff --git a/base/common/src/com/netscape/cms/servlet/profile/ProfileNotFoundException.java b/base/common/src/com/netscape/cms/servlet/profile/ProfileNotFoundException.java
new file mode 100644
index 0000000..594d2da
--- /dev/null
+++ b/base/common/src/com/netscape/cms/servlet/profile/ProfileNotFoundException.java
@@ -0,0 +1,46 @@
+package com.netscape.cms.servlet.profile;
+
+
+import javax.ws.rs.core.Response;
+
+import com.netscape.cms.servlet.base.CMSException;
+
+public class ProfileNotFoundException extends CMSException {
+
+    private static final long serialVersionUID = -4784839378360933483L;
+
+    public String profileId;
+
+    public ProfileNotFoundException(String profileId) {
+        this(profileId, "Profile ID "+profileId+" not found");
+    }
+
+    public ProfileNotFoundException(String profileId, String message) {
+        super(Response.Status.NOT_FOUND, message);
+        this.profileId = profileId;
+    }
+
+    public ProfileNotFoundException(String profileId, String message, Throwable cause) {
+        super(Response.Status.NOT_FOUND, message, cause);
+        this.profileId = profileId;
+    }
+
+    public ProfileNotFoundException(Data data) {
+        super(data);
+        profileId = data.getAttribute("profileId");
+    }
+
+    public Data getData() {
+        Data data = super.getData();
+        data.setAttribute("profileId", profileId);
+        return data;
+    }
+
+    public String  getProfileId() {
+        return profileId;
+    }
+
+    public void setRequestId(String profileId) {
+        this.profileId = profileId;
+    }
+}
diff --git a/base/common/src/com/netscape/cms/servlet/profile/ProfileResource.java b/base/common/src/com/netscape/cms/servlet/profile/ProfileResource.java
new file mode 100644
index 0000000..f347546
--- /dev/null
+++ b/base/common/src/com/netscape/cms/servlet/profile/ProfileResource.java
@@ -0,0 +1,39 @@
+package com.netscape.cms.servlet.profile;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+
+import com.netscape.cms.servlet.profile.model.ProfileData;
+import com.netscape.cms.servlet.request.model.ProfileRetrievalRequestData;
+
+@Path("/profile")
+public interface ProfileResource {
+   
+    @GET
+    @Path("{id}")
+    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.TEXT_XML })
+    public ProfileData retrieveProfile(@PathParam("id") String id);
+    /**
+     * Used to retrieve a key
+     * @param data
+     * @return
+     */
+    @POST
+    @Path("retrieve")
+    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.TEXT_XML })
+    @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+    public ProfileData retrieveProfile(ProfileRetrievalRequestData request);
+    
+    // retrieval - used to test integration with a browser
+    @POST
+    @Path("retrieve")
+    @Produces(MediaType.TEXT_XML)
+    @Consumes({ MediaType.APPLICATION_FORM_URLENCODED})
+    public ProfileData retrievProfile(MultivaluedMap<String, String> form);
+}
\ No newline at end of file
diff --git a/base/common/src/com/netscape/cms/servlet/profile/ProfileResourceService.java b/base/common/src/com/netscape/cms/servlet/profile/ProfileResourceService.java
new file mode 100644
index 0000000..b049e06
--- /dev/null
+++ b/base/common/src/com/netscape/cms/servlet/profile/ProfileResourceService.java
@@ -0,0 +1,81 @@
+//--- 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) 2011 Red Hat, Inc.
+//All rights reserved.
+//--- END COPYRIGHT BLOCK ---
+
+package com.netscape.cms.servlet.profile;
+
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+
+import com.netscape.cms.servlet.base.CMSResourceService;
+import com.netscape.cms.servlet.profile.model.ProfileDAO;
+import com.netscape.cms.servlet.profile.model.ProfileData;
+import com.netscape.cms.servlet.request.model.ProfileRetrievalRequestData;
+
+/**
+ * @author alee
+ * 
+ */
+public class ProfileResourceService extends CMSResourceService implements ProfileResource {
+
+    private final static String PROFILE_ID = "profileId";
+
+    @Override
+    public ProfileData retrieveProfile(String id) {
+        // TODO Auto-generated method stub
+        
+        ProfileData data = null;
+        ProfileDAO  dao = new ProfileDAO();
+        
+        try {
+            data = dao.getProfile(id);
+        } catch (ProfileNotFoundException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+        
+        return data;
+    }
+
+    @Override
+    public ProfileData retrievProfile(MultivaluedMap<String, String> form) {
+        // TODO Auto-generated method stub
+        String profileId =  null;
+        
+        if (form.containsKey(PROFILE_ID)) {
+            profileId = form.getFirst(PROFILE_ID);
+        }
+        
+        return retrieveProfile(profileId);
+    }
+
+    @Override
+    public ProfileData retrieveProfile(ProfileRetrievalRequestData request) {
+        // TODO Auto-generated method stub
+        
+        if (request == null) {
+            throw new WebApplicationException(Response.Status.BAD_REQUEST);
+        }
+        
+        String id = request.getProfileId();
+        
+        return retrieveProfile(id);
+    }
+
+}
diff --git a/base/common/src/com/netscape/cms/servlet/profile/ProfilesResource.java b/base/common/src/com/netscape/cms/servlet/profile/ProfilesResource.java
new file mode 100644
index 0000000..1d5e39d
--- /dev/null
+++ b/base/common/src/com/netscape/cms/servlet/profile/ProfilesResource.java
@@ -0,0 +1,17 @@
+package com.netscape.cms.servlet.profile;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+import com.netscape.cms.servlet.profile.model.ProfileDataInfos;
+ 
+@Path("/profiles")
+public interface ProfilesResource {
+    
+    @GET
+    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.TEXT_XML })
+    public ProfileDataInfos listProfiles();
+    
+}
diff --git a/base/common/src/com/netscape/cms/servlet/profile/ProfilesResourceService.java b/base/common/src/com/netscape/cms/servlet/profile/ProfilesResourceService.java
new file mode 100644
index 0000000..7c0eaa1
--- /dev/null
+++ b/base/common/src/com/netscape/cms/servlet/profile/ProfilesResourceService.java
@@ -0,0 +1,39 @@
+// --- 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) 2011 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+/**
+ * 
+ */
+package com.netscape.cms.servlet.profile;
+
+ 
+import com.netscape.cms.servlet.base.CMSResourceService;
+import com.netscape.cms.servlet.profile.model.ProfileDAO;
+import com.netscape.cms.servlet.profile.model.ProfileDataInfos;
+
+/**
+ * @author alee
+ * 
+ */
+public class ProfilesResourceService extends CMSResourceService implements ProfilesResource {
+    
+    public ProfileDataInfos listProfiles()
+    {
+        ProfileDAO dao = new ProfileDAO();
+        return dao.listProfiles(uriInfo);
+    }
+}
diff --git a/base/common/src/com/netscape/cms/servlet/profile/model/ProfileDAO.java b/base/common/src/com/netscape/cms/servlet/profile/model/ProfileDAO.java
new file mode 100644
index 0000000..980303f
--- /dev/null
+++ b/base/common/src/com/netscape/cms/servlet/profile/model/ProfileDAO.java
@@ -0,0 +1,213 @@
+// --- 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) 2011 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cms.servlet.profile.model;
+
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Locale;
+
+import javax.ws.rs.Path;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.profile.EProfileException;
+import com.netscape.certsrv.profile.IProfile;
+import com.netscape.certsrv.profile.IProfileInput;
+import com.netscape.certsrv.profile.IProfileSubsystem;
+import com.netscape.cms.servlet.profile.ProfileNotFoundException;
+import com.netscape.cms.servlet.profile.ProfileResource;
+
+/**
+ * @author alee
+ *
+ */
+public class ProfileDAO {
+    
+    private IProfileSubsystem ps;
+    
+    public ProfileDAO() {
+        ps = (IProfileSubsystem) CMS.getSubsystem(IProfileSubsystem.ID);
+    }
+    /**
+     * Returns list of profiles 
+     */
+    
+    public ProfileDataInfos listProfiles(UriInfo uriInfo)
+    {
+        
+        List <ProfileDataInfo> list = new ArrayList<ProfileDataInfo>();
+        ProfileDataInfos infos = new ProfileDataInfos();
+        
+        if (ps == null) {
+            return null;
+        }
+        
+        Enumeration<String> profileIds = ps.getProfileIds();
+
+        if (profileIds != null) {
+            while (profileIds.hasMoreElements()) {
+                String id = profileIds.nextElement();
+                ProfileDataInfo info = null;
+                try {
+                    info = createProfileDataInfo(id,uriInfo);
+                } catch (EBaseException e) {
+                    continue;
+                }
+                
+                if (info != null) {
+                   list.add(info); 
+                }
+            }
+        }
+        
+        infos.setProfileInfos(list);
+
+        
+        return infos;
+    }
+    
+    public ProfileData getProfile(String profileId)  throws ProfileNotFoundException {
+        ProfileData data = null;
+        
+        if (ps == null) {
+            return null;
+        }
+        
+        Enumeration<String> profileIds = ps.getProfileIds();
+
+        IProfile profile = null;
+        if (profileIds != null) {
+            while (profileIds.hasMoreElements()) {
+                String id = profileIds.nextElement();
+                
+                if (id.equals(profileId)) {
+                    
+                    try {
+                        profile = ps.getProfile(profileId);
+                    } catch (EProfileException e) {
+                        e.printStackTrace();
+                        throw new ProfileNotFoundException(profileId);
+                    } 
+                    break;
+                }
+            }
+        }
+        
+        if (profile == null) {
+            throw new ProfileNotFoundException(profileId);
+        }
+        
+        try {
+            data = createProfileData(profileId);
+        } catch (EBaseException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+            throw new ProfileNotFoundException(profileId);
+        }
+        
+        return data;
+    }
+    
+    public ProfileData createProfileData(String profileId) throws EBaseException {
+        
+        IProfile profile;
+        
+        try {
+            profile = ps.getProfile(profileId);
+        } catch (EProfileException e) {
+            e.printStackTrace();
+            throw new ProfileNotFoundException(profileId);
+        } 
+        
+        ProfileData data = new ProfileData();
+        
+        Locale locale = Locale.getDefault();
+        String name = profile.getName(locale);
+        String desc = profile.getDescription(locale);
+        
+        data.setName(name);
+        data.setDescription(desc);
+        data.setIsEnabled(ps.isProfileEnable(profileId));
+        data.setIsVisible(profile.isVisible());
+        data.setEnabledBy(ps.getProfileEnableBy(profileId));
+        data.setId(profileId);
+        
+        Enumeration<String> inputIds = profile.getProfileInputIds();
+
+        String inputName = null;
+        
+        if (inputIds != null) {
+            while (inputIds.hasMoreElements()) {
+                String inputId = (String) inputIds.nextElement();
+                IProfileInput profileInput = profile.getProfileInput(inputId);
+                
+                if (profileInput == null) {
+                    continue;
+                }
+                inputName = profileInput.getName(locale);
+                
+                Enumeration<String> inputNames = profileInput.getValueNames();
+                
+                ProfileInput input = data.addProfileInput(inputName);
+
+                String curInputName = null;
+                while (inputNames.hasMoreElements()) {
+                    curInputName = (String) inputNames.nextElement();
+                    
+                    if (curInputName != null && !curInputName.equals("")) {
+                        input.setInputAttr(curInputName, "");
+                    }
+                    
+                }
+            }
+        }
+        
+        return data;
+        
+    }
+    public ProfileDataInfo createProfileDataInfo(String profileId, UriInfo uriInfo) throws EBaseException {
+        
+        if ( profileId == null) {
+            throw new EBaseException("Error creating ProfileDataInfo.");
+        }
+        ProfileDataInfo ret = null;
+
+        IProfile profile = null;
+
+        profile = ps.getProfile(profileId);
+        if (profile == null) {
+            return null;
+        }
+
+        ret = new ProfileDataInfo();
+        
+        ret.setProfileId(profileId);
+        
+        Path profilePath = ProfileResource.class.getAnnotation(Path.class);
+
+        UriBuilder profileBuilder = uriInfo.getBaseUriBuilder();
+        profileBuilder.path(profilePath.value() + "/" + profileId);
+        ret.setProfileURL(profileBuilder.build().toString());
+
+        return ret;
+    }
+    
+}
\ No newline at end of file
diff --git a/base/common/src/com/netscape/cms/servlet/profile/model/ProfileData.java b/base/common/src/com/netscape/cms/servlet/profile/model/ProfileData.java
new file mode 100644
index 0000000..91a0a5c
--- /dev/null
+++ b/base/common/src/com/netscape/cms/servlet/profile/model/ProfileData.java
@@ -0,0 +1,148 @@
+// --- 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) 2011 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+/**
+ * 
+ */
+package com.netscape.cms.servlet.profile.model;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+
+/**
+ * @author jmagne
+ *
+ */
+
+
+@XmlRootElement(name="ProfileData")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class ProfileData {
+    
+    @XmlElement
+    protected String id;
+    @XmlElement
+    protected String name;
+    
+    @XmlElement
+    protected String description;
+    
+    @XmlElement
+    protected boolean isEnabled;
+    
+    @XmlElement
+    protected boolean isVisible;
+    
+    @XmlElement
+    protected String enabledBy;
+    
+    @XmlElement(name="Input")
+    protected List<ProfileInput> inputs = new ArrayList<ProfileInput>();
+    
+    public void setName(String name) {
+        this.name = name;
+    }
+    
+    public String getName() {
+        return name;
+    }
+    
+    public void setDescription(String description) {
+        this.description = description;
+    }
+    
+    public String getDescription() {
+        return description;
+    }
+    
+    public void setIsEnabled(boolean isEnabled) {
+        this.isEnabled = isEnabled;
+    }
+    
+    public boolean getIsEnabled() {
+        return isEnabled;
+    }
+    
+    public void setIsVisible(boolean isVisible) {
+        this.isVisible = isVisible;
+    }
+    
+    public boolean getIsVisible() {
+        return isVisible;
+    }
+    
+    public void setEnabledBy(String enabledBy) {
+        this.enabledBy = enabledBy;
+    }
+    
+    public String getEnabledBy() {
+        return enabledBy;
+    }
+    
+    public void setId(String id) {
+        this.id = id;
+    }
+    
+    public String getId() {
+        return id;
+    }
+    
+    public ProfileInput addProfileInput(String name) {
+        
+        ProfileInput oldInput = getProfileInput(name);
+        
+        if (oldInput != null)
+            return oldInput;
+        
+        ProfileInput newInput = new ProfileInput();
+        newInput.setInputId(name);
+        
+        
+        inputs.add(newInput);
+        
+        return newInput;
+    }
+    
+    public ProfileInput getProfileInput(String name) {
+        
+        ProfileInput input = null;
+        
+        Iterator<ProfileInput> it= inputs.iterator();
+
+        ProfileInput curInput = null;
+        while(it.hasNext()) {
+            curInput = it.next();
+            
+            if (curInput != null && curInput.getInputId().equals(name))
+                break;
+        }
+        
+        return input;
+    }
+    
+    public List<ProfileInput> getProfileInputsList() {
+        return inputs;
+    }
+    
+}
\ No newline at end of file
diff --git a/base/common/src/com/netscape/cms/servlet/profile/model/ProfileDataInfo.java b/base/common/src/com/netscape/cms/servlet/profile/model/ProfileDataInfo.java
new file mode 100644
index 0000000..63f005b
--- /dev/null
+++ b/base/common/src/com/netscape/cms/servlet/profile/model/ProfileDataInfo.java
@@ -0,0 +1,72 @@
+package com.netscape.cms.servlet.profile.model;
+
+//--- 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) 2011 Red Hat, Inc.
+//All rights reserved.
+//--- END COPYRIGHT BLOCK ---
+/**
+ * 
+ */
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlAccessorType;
+
+/**
+ * @author alee
+ * 
+ */
+@XmlRootElement(name = "ProfileDataInfo")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class ProfileDataInfo {
+
+    @XmlElement
+    protected String profileURL;
+
+    @XmlElement
+    protected String profileId;
+
+    public ProfileDataInfo() {
+        // required for JAXB (defaults)
+    }
+
+    /**
+     * @return the profileURL
+     */
+    public String getProfileURL() {
+        return profileURL;
+    }
+
+    /**
+     * @param keyURL the profileURL to set
+     */
+    public void setProfileURL(String profileURL) {
+        this.profileURL = profileURL;
+    }
+
+    public void setProfileId(String profileId) {
+        this.profileId = profileId;
+    }
+
+    /**
+     * @return the profile ID in the profileURL
+     */
+    public String getProfileId() {
+        return profileId;
+    }
+
+}
diff --git a/base/common/src/com/netscape/cms/servlet/profile/model/ProfileDataInfos.java b/base/common/src/com/netscape/cms/servlet/profile/model/ProfileDataInfos.java
new file mode 100644
index 0000000..c31738c
--- /dev/null
+++ b/base/common/src/com/netscape/cms/servlet/profile/model/ProfileDataInfos.java
@@ -0,0 +1,87 @@
+//--- 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.cms.servlet.profile.model;
+
+import java.util.Collection;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlElementRef;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlTransient;
+
+import com.netscape.cms.servlet.base.model.Link;
+
+@XmlRootElement(name = "ProfileDataInfos")
+public class ProfileDataInfos {
+ 
+ protected Collection<ProfileDataInfo> profileInfos;
+ protected List<Link> links;
+ 
+ /**
+  * @return the ProfileInfos
+  */
+ @XmlElementRef
+ public Collection<ProfileDataInfo> getProfileInfos() {
+     return profileInfos;
+ }
+ /**
+  * @param ProfileInfos theProfileInfos to set
+  */
+ public void setProfileInfos(Collection<ProfileDataInfo> profileInfos) {
+     this.profileInfos = profileInfos;
+ }
+ /**
+  * @return the links
+  */
+ @XmlElementRef
+ public List<Link> getLinks() {
+     return links;
+ }
+ /**
+  * @param links the links to set
+  */
+ public void setLinks(List<Link> links) {
+     this.links = links;
+ }
+ 
+ @XmlTransient
+ public String getNext() {
+     if (links == null) {
+         return null;
+     }
+     for (Link link : links) {
+         if ("next".equals(link.getRelationship())) {
+             return link.getHref();
+         }
+     }
+     return null;
+ }
+
+ @XmlTransient
+ public String getPrevious() {
+     if (links == null) {
+         return null;
+     }
+     for (Link link : links) {
+         if ("previous".equals(link.getRelationship())) {
+             return link.getHref();
+         }
+     }
+     return null;
+ }
+}
diff --git a/base/common/src/com/netscape/cms/servlet/profile/model/ProfileInput.java b/base/common/src/com/netscape/cms/servlet/profile/model/ProfileInput.java
new file mode 100644
index 0000000..470b7dc
--- /dev/null
+++ b/base/common/src/com/netscape/cms/servlet/profile/model/ProfileInput.java
@@ -0,0 +1,72 @@
+package com.netscape.cms.servlet.profile.model;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlValue;
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+
+public class ProfileInput {
+
+    @XmlElement
+    public String getInputId() {
+        return inputId;
+    }
+
+    private String inputId;
+    @XmlJavaTypeAdapter(InputAttrsAdapter.class)
+    public Map<String, String> InputAttrs = new LinkedHashMap<String, String>();
+
+    public void setInputAttr(String name, String value) {
+        InputAttrs.put(name, value);
+    }
+
+    public void setInputId(String inputId) {
+        this.inputId = inputId;
+    }
+
+    public static class InputAttrsAdapter extends XmlAdapter<InputAttrList, Map<String, String>> {
+
+        public InputAttrList marshal(Map<String, String> map) {
+            InputAttrList list = new InputAttrList();
+            for (Map.Entry<String, String> entry : map.entrySet()) {
+                Attribute attribute = new Attribute();
+                attribute.name = entry.getKey();
+                attribute.value = entry.getValue();
+                list.attributes.add(attribute);
+            }
+            return list;
+        }
+
+        public Map<String, String> unmarshal(InputAttrList list) {
+            Map<String, String> map = new LinkedHashMap<String, String>();
+            for (Attribute attribute : list.attributes) {
+                map.put(attribute.name, attribute.value);
+            }
+            return map;
+        }
+    }
+
+    public static class InputAttrList {
+        @XmlElement(name = "InputAttr")
+        public List<Attribute> attributes = new ArrayList<Attribute>();
+    }
+
+    public static class Attribute {
+
+        @XmlAttribute
+        public String name;
+
+        @XmlValue
+        public String value;
+    }
+    
+    public Map<String,String> getAttributes() {
+        return InputAttrs;
+    }
+}
diff --git a/base/common/src/com/netscape/cms/servlet/request/CertRequestResource.java b/base/common/src/com/netscape/cms/servlet/request/CertRequestResource.java
new file mode 100644
index 0000000..3c676c2
--- /dev/null
+++ b/base/common/src/com/netscape/cms/servlet/request/CertRequestResource.java
@@ -0,0 +1,53 @@
+package com.netscape.cms.servlet.request;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+
+import com.netscape.certsrv.request.RequestId;
+import com.netscape.cms.servlet.request.model.CertRequestInfo;
+import com.netscape.cms.servlet.request.model.EnrollmentRequestData;
+
+@Path("/certrequest")
+public interface CertRequestResource {
+
+    /**
+     * Used to retrieve cert request info for a specific request
+     */
+    @GET
+    @Path("{id}")
+    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.TEXT_XML })
+    public CertRequestInfo getRequestInfo(@PathParam("id") RequestId id);
+
+    // Enrollment - used to test integration with a browser
+    @POST
+    @Path("enroll")
+    @Produces({ MediaType.TEXT_XML })
+    @Consumes({ MediaType.APPLICATION_FORM_URLENCODED})
+    public CertRequestInfo enrollCert(MultivaluedMap<String, String> form);
+
+    @POST
+    @Path("enroll")
+    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.TEXT_XML })
+    @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+    public CertRequestInfo enrollCert(EnrollmentRequestData data);
+
+
+    @POST
+    @Path("approve/{id}")
+    public void approveRequest(@PathParam("id") RequestId id);
+
+    @POST
+    @Path("reject/{id}")
+    public void rejectRequest(@PathParam("id") RequestId id);
+
+    @POST
+    @Path("cancel/{id}")
+    public void cancelRequest(@PathParam("id") RequestId id);
+
+}
diff --git a/base/common/src/com/netscape/cms/servlet/request/CertRequestResourceService.java b/base/common/src/com/netscape/cms/servlet/request/CertRequestResourceService.java
new file mode 100644
index 0000000..37cc17d
--- /dev/null
+++ b/base/common/src/com/netscape/cms/servlet/request/CertRequestResourceService.java
@@ -0,0 +1,112 @@
+// --- 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) 2011 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package com.netscape.cms.servlet.request;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.request.RequestId;
+import com.netscape.cms.servlet.base.CMSException;
+import com.netscape.cms.servlet.base.CMSResourceService;
+import com.netscape.cms.servlet.request.model.CertRequestDAO;
+import com.netscape.cms.servlet.request.model.CertRequestInfo;
+import com.netscape.cms.servlet.request.model.EnrollmentRequestData;
+
+
+/**
+ * @author alee
+ *
+ */
+public class CertRequestResourceService extends CMSResourceService implements CertRequestResource {
+
+    /**
+     * Used to retrieve key request info for a specific request
+     */
+    public CertRequestInfo getRequestInfo(RequestId id) {
+        // auth and authz
+        CertRequestInfo info;
+        
+        CertRequestDAO dao = new CertRequestDAO();
+        try {
+            info = dao.getRequest(id, uriInfo);
+        } catch (EBaseException e) {
+            // log error
+            e.printStackTrace();
+            throw new CMSException(e.getMessage(), e);
+        }
+        
+        if (info == null) {
+            // request does not exist
+            throw new RequestNotFoundException(id);
+        }
+        
+        return info;
+    }
+
+    // Enrollment - used to test integration with a browser
+    public CertRequestInfo enrollCert(MultivaluedMap<String, String> form) {
+        EnrollmentRequestData data = new EnrollmentRequestData(form);
+        return enrollCert(data);
+    }
+
+    public CertRequestInfo enrollCert(EnrollmentRequestData data) {
+        
+        if (data == null) {
+            throw new  WebApplicationException(Response.Status.BAD_REQUEST);    
+        }
+        CertRequestDAO dao = new CertRequestDAO();
+        
+        try {
+            dao.submitRequest(data,uriInfo);
+        } catch (EBaseException e) {
+            
+        }
+        
+        //ToDo implement
+        throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
+    }
+
+    
+    public void approveRequest(RequestId id) {
+        if (id == null) {
+            throw new  WebApplicationException(Response.Status.BAD_REQUEST);
+        }
+      //ToDo implement
+        throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
+    }
+
+    public void rejectRequest(RequestId id) {
+        if (id == null) {
+            throw new  WebApplicationException(Response.Status.BAD_REQUEST);
+        }
+      //ToDo implement
+        throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
+        
+    }
+
+    public void cancelRequest(RequestId id) {
+        if (id == null) {
+            throw new  WebApplicationException(Response.Status.BAD_REQUEST);
+        }
+      //ToDo implement
+        throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
+    }
+}
diff --git a/base/common/src/com/netscape/cms/servlet/request/CertRequestsResource.java b/base/common/src/com/netscape/cms/servlet/request/CertRequestsResource.java
new file mode 100644
index 0000000..8c1a1ba
--- /dev/null
+++ b/base/common/src/com/netscape/cms/servlet/request/CertRequestsResource.java
@@ -0,0 +1,33 @@
+package com.netscape.cms.servlet.request;
+
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+
+import com.netscape.certsrv.request.RequestId;
+import com.netscape.cms.servlet.request.model.CertRequestInfos;
+
+@Path("/certrequests")
+public interface CertRequestsResource {
+
+    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 cert requests based on the search parameters
+     */
+    @GET
+    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.TEXT_XML })
+    public CertRequestInfos listRequests(@QueryParam("requestState") String requestState,
+                                            @QueryParam("requestType") String requestType,
+                                            @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);
+
+}
\ No newline at end of file
diff --git a/base/common/src/com/netscape/cms/servlet/request/CertRequestsResourceService.java b/base/common/src/com/netscape/cms/servlet/request/CertRequestsResourceService.java
new file mode 100644
index 0000000..195a2a4
--- /dev/null
+++ b/base/common/src/com/netscape/cms/servlet/request/CertRequestsResourceService.java
@@ -0,0 +1,91 @@
+// --- 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) 2011 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+ 
+package com.netscape.cms.servlet.request;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Response;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.request.RequestId;
+import com.netscape.cms.servlet.base.CMSResourceService;
+import com.netscape.cms.servlet.request.model.CertRequestDAO;
+import com.netscape.cms.servlet.request.model.CertRequestInfos;
+import com.netscape.cmsutil.ldap.LDAPUtil;
+
+/**
+ * @author alee
+ *
+ */
+public class CertRequestsResourceService extends CMSResourceService implements CertRequestsResource{
+
+    /**
+     * Used to generate list of cert requests based on the search parameters
+     */
+    public CertRequestInfos listRequests(String requestState, String requestType, 
+            RequestId start, int pageSize, int maxResults, int maxTime) {
+        // auth and authz
+        
+        // get ldap filter
+        String filter = createSearchFilter(requestState, requestType);
+        CMS.debug("listRequests: filter is " + filter);
+       
+        // get start marker
+        if (start == null) {
+            start = new RequestId(KeyRequestsResource.DEFAULT_START);
+        }
+        
+        CertRequestDAO reqDAO = new CertRequestDAO();
+        CertRequestInfos requests;
+        try {
+            requests = reqDAO.listRequests(filter, start, pageSize, maxResults, maxTime, uriInfo);
+        } catch (EBaseException e) {
+            CMS.debug("listRequests: error in obtaining request results" + e);
+            e.printStackTrace();
+            throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
+        }
+        return requests;
+    }
+
+    private String createSearchFilter(String requestState, String requestType) {
+        String filter = "";
+        int matches = 0;
+        
+        if ((requestState == null) && (requestType == null) ) {
+            filter = "(requeststate=*)";
+            return filter;
+        }
+        
+        if (requestState != null) {
+            filter += "(requeststate=" + LDAPUtil.escape(requestState) + ")";
+            matches ++;
+        }
+        
+        if (requestType != null) {
+            filter += "(requesttype=" + LDAPUtil.escape(requestType) + ")";
+            matches ++;
+        }
+        
+        if (matches > 1) {
+            filter = "(&" + filter + ")";
+        }
+        
+        return filter;
+    }
+}
diff --git a/base/common/src/com/netscape/cms/servlet/request/model/CertRequestDAO.java b/base/common/src/com/netscape/cms/servlet/request/model/CertRequestDAO.java
new file mode 100644
index 0000000..162aadf
--- /dev/null
+++ b/base/common/src/com/netscape/cms/servlet/request/model/CertRequestDAO.java
@@ -0,0 +1,231 @@
+// --- 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) 2011 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cms.servlet.request.model;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.ws.rs.Path;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.ca.ICertificateAuthority;
+import com.netscape.certsrv.request.IRequest;
+import com.netscape.certsrv.request.IRequestList;
+import com.netscape.certsrv.request.IRequestQueue;
+import com.netscape.certsrv.request.IRequestVirtualList;
+import com.netscape.certsrv.request.RequestId;
+import com.netscape.certsrv.request.RequestStatus;
+import com.netscape.cms.servlet.base.model.Link;
+import com.netscape.cms.servlet.request.CertRequestResource;
+
+/**
+ * @author alee
+ *
+ */
+
+//ToDo: Take some of this code and make it into a common base class to be used
+// by Cert Requests and Key Requests
+public class CertRequestDAO {
+    private IRequestQueue queue;
+    private ICertificateAuthority ca;
+
+    
+    private String[] vlvFilters = {
+            "(requeststate=*)", "(requesttype=enrollment)",
+            "(requesttype=recovery)", "(requeststate=canceled)",
+            "(&(requeststate=canceled)(requesttype=enrollment))",
+            "(&(requeststate=canceled)(requesttype=recovery))", 
+            "(requeststate=rejected)", 
+            "(&(requeststate=rejected)(requesttype=enrollment))",
+            "(&(requeststate=rejected)(requesttype=recovery))",
+            "(requeststate=complete)",
+            "(&(requeststate=complete)(requesttype=enrollment))",
+            "(&(requeststate=complete)(requesttype=recovery))"
+    };
+    
+    public static final String ATTR_SERIALNO = "serialNumber";
+
+    public CertRequestDAO() {
+        ca = ( ICertificateAuthority ) CMS.getSubsystem( "ca" );
+        queue = ca.getRequestQueue();
+    }
+
+    /**
+     * Finds list of requests matching the specified search filter.  
+     * 
+     * If the filter corresponds to a VLV search, then that search is executed and the pageSize 
+     * and start parameters are used.  Otherwise, the maxResults and maxTime parameters are
+     * used in the regularly indexed search.
+     * 
+     * @param filter - ldap search filter
+     * @param start - start position for VLV search
+     * @param pageSize - page size for VLV search
+     * @param maxResults - max results to be returned in normal search
+     * @param maxTime - max time for normal search
+     * @param uriInfo - uri context of request
+     * @return collection of key request info
+     * @throws EBaseException
+     */
+    public CertRequestInfos listRequests(String filter, RequestId start, int pageSize, int maxResults, int maxTime,
+            UriInfo uriInfo) throws EBaseException {
+        List <CertRequestInfo> list = new ArrayList<CertRequestInfo>();
+        List <Link> links = new ArrayList<Link>();
+        int totalSize = 0;
+        int current = 0;
+        
+        if (isVLVSearch(filter)) {
+            IRequestVirtualList vlvlist = queue.getPagedRequestsByFilter(start, false, filter,
+                                                                         pageSize +1 , "requestId");
+            totalSize = vlvlist.getSize();
+            current = vlvlist.getCurrentIndex();
+            
+            int numRecords = (totalSize > (current + pageSize)) ? pageSize :
+                totalSize - current;
+            
+            for (int i=0; i < numRecords; i++) {
+                IRequest request = vlvlist.getElementAt(i);
+                list.add(createCertRequestInfo(request, uriInfo));
+            }
+        } else {
+            // The non-vlv requests are indexed, but are not paginated.
+            // We should think about whether they should be, or if we need to
+            // limit the number of results returned.
+            IRequestList requests = queue.listRequestsByFilter(filter, maxResults, maxTime);
+
+            if (requests == null) {
+                return null;
+            }
+            while (requests.hasMoreElements()) {
+                RequestId rid = requests.nextElement();
+                IRequest request = queue.findRequest(rid);
+                if (request != null) {
+                    list.add(createCertRequestInfo(request, uriInfo));
+                }
+            }
+        }
+        
+        // builder for vlv links
+        MultivaluedMap<String, String> params = uriInfo.getQueryParameters();
+        UriBuilder builder = uriInfo.getAbsolutePathBuilder();
+        if (params.containsKey("requestState")) {
+            builder.queryParam("requestState", params.getFirst("requestState"));
+        }
+        if (params.containsKey("requestType")) {
+            builder.queryParam("requestType", params.getFirst("requestType"));
+        }
+        builder.queryParam("start", "{start}");
+        builder.queryParam("pageSize", "{pageSize}");
+        
+        // next link
+        if (totalSize > current + pageSize) {
+            int next = current + pageSize + 1;
+            URI nextUri = builder.clone().build(next,pageSize);
+            Link nextLink = new Link("next", nextUri.toString(), "application/xml");
+            links.add(nextLink);
+        }
+        
+        // previous link
+        if (current >0) {
+            int previous = current - pageSize;
+            URI previousUri = builder.clone().build(previous,pageSize);
+            Link previousLink = new Link("previous", previousUri.toString(), "application/xml");
+            links.add(previousLink);
+        }
+        
+        CertRequestInfos ret = new CertRequestInfos();
+        ret.setRequests(list);
+        ret.setLinks(links);
+        return ret;
+    }
+    
+    /**
+     * Gets info for a specific request
+     * @param id
+     * @return info for specific request
+     * @throws EBaseException 
+     */
+    public CertRequestInfo getRequest(RequestId id, UriInfo uriInfo) throws EBaseException {
+        IRequest request = queue.findRequest(id);
+        if (request == null) {
+            return null;
+        }
+        CertRequestInfo info = createCertRequestInfo(request, uriInfo);
+        return info;
+    }
+    /**
+     * Submits an enrollment request and processes it.
+     * @param data
+     * @return info for the request submitted.
+     * @throws EBaseException 
+     */
+    public CertRequestInfo submitRequest(EnrollmentRequestData data, UriInfo uriInfo) throws EBaseException {
+
+        //ToDo perform actual profile request.
+    
+        throw new EBaseException("Not implemented.");
+    }
+
+    public void approveRequest(RequestId id) throws EBaseException {
+        IRequest request = queue.findRequest(id);
+        request.setRequestStatus(RequestStatus.APPROVED);
+        queue.updateRequest(request);
+    }
+    
+    public void rejectRequest(RequestId id) throws EBaseException {
+        IRequest request = queue.findRequest(id);
+        request.setRequestStatus(RequestStatus.CANCELED);
+        queue.updateRequest(request);
+    }
+    
+    public void cancelRequest(RequestId id) throws EBaseException {
+        IRequest request = queue.findRequest(id);
+        request.setRequestStatus(RequestStatus.REJECTED);
+        queue.updateRequest(request);
+    }
+    
+    public CertRequestInfo createCertRequestInfo(IRequest request, UriInfo uriInfo) {
+        CertRequestInfo ret = new CertRequestInfo();
+        
+        ret.setRequestType(request.getRequestType());
+        ret.setRequestStatus(request.getRequestStatus().toString());
+        ret.setCertRequestType(request.getExtDataInString("cert_request_type"));
+        
+        Path certRequestPath = CertRequestResource.class.getAnnotation(Path.class);
+        RequestId rid = request.getRequestId();
+
+        UriBuilder reqBuilder = uriInfo.getBaseUriBuilder();
+        reqBuilder.path(certRequestPath.value() + "/" + rid);
+        ret.setRequestURL(reqBuilder.build().toString());
+        
+        return ret;
+    }
+    
+    private boolean isVLVSearch(String filter) {
+        for (int i=0; i < vlvFilters.length; i++) {
+            if (vlvFilters[i].equalsIgnoreCase(filter)) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
diff --git a/base/common/src/com/netscape/cms/servlet/request/model/CertRequestInfo.java b/base/common/src/com/netscape/cms/servlet/request/model/CertRequestInfo.java
new file mode 100644
index 0000000..001bbe6
--- /dev/null
+++ b/base/common/src/com/netscape/cms/servlet/request/model/CertRequestInfo.java
@@ -0,0 +1,115 @@
+// --- 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) 2011 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package com.netscape.cms.servlet.request.model;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+
+import com.netscape.certsrv.request.RequestId;
+
+@XmlRootElement(name="CertRequestInfo")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class CertRequestInfo {
+
+    @XmlElement
+    protected String requestType;
+    
+    @XmlElement
+    protected String requestStatus;
+    
+    @XmlElement
+    protected String requestURL;
+    
+    @XmlElement
+    protected String certRequestType;
+    
+    public CertRequestInfo(){
+        // required to be here for JAXB (defaults)
+    }
+    
+    /**
+     * @return the requestType
+     */
+    public String getRequestType() {
+        return requestType;
+    }
+
+    /**
+     * @param requestType the requestType to set
+     */
+    public void setRequestType(String requestType) {
+        this.requestType = requestType;
+    }
+
+    /**
+     * @return the requestStatus
+     */
+    public String getRequestStatus() {
+        return requestStatus;
+    }
+
+    /**
+     * @param requestStatus the requestStatus to set
+     */
+    public void setRequestStatus(String requestStatus) {
+        this.requestStatus = requestStatus;
+    }
+
+    /**
+     * @return the requestURL
+     */
+    public String getRequestURL() {
+        return requestURL;
+    }
+
+    /**
+     * @return the request ID in the requestURL
+     */
+    public RequestId getRequestId() {
+        String id = requestURL.substring(requestURL.lastIndexOf("/") + 1);
+        return new RequestId(id);
+    }
+
+    /**
+     * @param requestURL the requestURL to set
+     */
+    public void setRequestURL(String requestURL) {
+        this.requestURL = requestURL;
+    }
+
+    
+    /**
+     * @param certRequestType to set
+     */
+    
+    public void setCertRequestType(String certRequestType) {
+        this.certRequestType = certRequestType;
+    }
+    
+    /**
+     * @return the certRequestType
+     */
+    
+    public String getCertRequestType() {
+        return certRequestType;
+    }
+
+}
diff --git a/base/common/src/com/netscape/cms/servlet/request/model/CertRequestInfos.java b/base/common/src/com/netscape/cms/servlet/request/model/CertRequestInfos.java
new file mode 100644
index 0000000..a4c39a3
--- /dev/null
+++ b/base/common/src/com/netscape/cms/servlet/request/model/CertRequestInfos.java
@@ -0,0 +1,89 @@
+// --- 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) 2011 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cms.servlet.request.model;
+
+import java.util.Collection;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlElementRef;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlTransient;
+
+import com.netscape.cms.servlet.base.model.Link;
+
+@XmlRootElement(name = "CertRequestInfos")
+public class CertRequestInfos {
+    protected Collection<CertRequestInfo> requests;
+    protected List<Link> links;
+
+    /**
+     * @return the requests
+     */
+    @XmlElementRef
+    public Collection<CertRequestInfo> getRequests() {
+        return requests;
+    }
+
+    /**
+     * @param requests the requests to set
+     */
+    public void setRequests(Collection<CertRequestInfo> requests) {
+        this.requests = requests;
+    }
+
+    /**
+     * @return the links
+     */
+    @XmlElementRef
+    public List<Link> getLinks() {
+        return links;
+    }
+
+    /**
+     * @param links the links to set
+     */
+    public void setLinks(List<Link> links) {
+        this.links = links;
+    }
+
+    @XmlTransient
+    public String getNext() {
+        if (links == null) {
+            return null;
+        }
+        for (Link link : links) {
+            if ("next".equals(link.getRelationship())) {
+                return link.getHref();
+            }
+        }
+        return null;
+    }
+
+    @XmlTransient
+    public String getPrevious() {
+        if (links == null) {
+            return null;
+        }
+        for (Link link : links) {
+            if ("previous".equals(link.getRelationship())) {
+                return link.getHref();
+            }
+        }
+        return null;
+    }
+}
diff --git a/base/common/src/com/netscape/cms/servlet/request/model/CertRetrievalRequestData.java b/base/common/src/com/netscape/cms/servlet/request/model/CertRetrievalRequestData.java
new file mode 100644
index 0000000..99e841b
--- /dev/null
+++ b/base/common/src/com/netscape/cms/servlet/request/model/CertRetrievalRequestData.java
@@ -0,0 +1,78 @@
+// --- 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) 2011 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+/**
+ * 
+ */
+package com.netscape.cms.servlet.request.model;
+
+import javax.ws.rs.core.MultivaluedMap;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+
+import com.netscape.certsrv.dbs.certdb.CertId;
+import com.netscape.certsrv.dbs.certdb.CertIdAdapter;
+import com.netscape.certsrv.request.RequestId;
+import com.netscape.certsrv.request.RequestIdAdapter;
+
+/**
+ * @author alee
+ *
+ */
+@XmlRootElement(name="CertRetrievalRequest")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class CertRetrievalRequestData {
+    
+    private static final String CERT_ID = "certId";
+
+    @XmlElement
+    @XmlJavaTypeAdapter(CertIdAdapter.class)
+    protected CertId certId;
+    
+    @XmlElement
+    @XmlJavaTypeAdapter(RequestIdAdapter.class)
+    protected RequestId requestId;
+
+    public CertRetrievalRequestData() {
+        // required for JAXB (defaults)
+    }
+    
+    public CertRetrievalRequestData(MultivaluedMap<String, String> form) {
+        if (form.containsKey(CERT_ID)) {
+            certId = new CertId(form.getFirst(CERT_ID));
+        }
+    }
+
+    /**
+     * @return the CertId
+     */
+    public CertId getCertId() {
+        return certId;
+    }
+
+    /**
+     * @param CertId the CertId to set
+     */
+    public void setCertId(CertId certId) {
+        this.certId = certId;
+    }
+    
+}
diff --git a/base/common/src/com/netscape/cms/servlet/request/model/EnrollmentRequestData.java b/base/common/src/com/netscape/cms/servlet/request/model/EnrollmentRequestData.java
new file mode 100644
index 0000000..cc95abb
--- /dev/null
+++ b/base/common/src/com/netscape/cms/servlet/request/model/EnrollmentRequestData.java
@@ -0,0 +1,203 @@
+// --- 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) 2011 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+/**
+ * 
+ */
+package com.netscape.cms.servlet.request.model;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.ws.rs.core.MultivaluedMap;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+
+import com.netscape.cms.servlet.profile.model.ProfileInput;
+
+/**
+ * @author jmagne
+ *
+ */
+
+@XmlRootElement(name="EnrollmentRequest")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class EnrollmentRequestData {
+
+    private static final String PROFILE_ID = "profileId";
+    private static final String RENEWAL = "renewal";
+    
+    @XmlElement
+    protected String profileId;
+    
+    @XmlElement
+    protected String renewal;
+    
+    @XmlElement(name="Input")
+    protected List<ProfileInput> inputs = new ArrayList<ProfileInput>();
+    
+    public EnrollmentRequestData() {
+    }
+    
+    public EnrollmentRequestData(MultivaluedMap<String, String> form) {        
+        profileId = form.getFirst(PROFILE_ID);
+        renewal = form.getFirst(RENEWAL);
+        
+    }
+
+    /**
+     * @return the profileId
+     */
+    public String getProfileId() {
+        return profileId;
+    }
+    
+    /**
+     * @param profileId the profileId to set
+     */
+    
+    public void setProfileId(String profileId) {
+        this.profileId = profileId;
+    }
+    
+    /**
+    * @return renewal
+    */
+    
+   public String getRenewal() {
+       return renewal;
+   }
+   
+   public ProfileInput addInput(String name) {
+       
+       ProfileInput oldInput = getInput(name);
+       
+       if (oldInput != null)
+           return oldInput;
+       
+       ProfileInput newInput = new ProfileInput();
+       newInput.setInputId(name);
+       
+       
+       inputs.add(newInput);
+       
+       return newInput;
+   }
+   
+   public ProfileInput getInput(String name) {
+       
+       ProfileInput input = null;
+       
+       Iterator<ProfileInput> it= inputs.iterator();
+
+       ProfileInput curInput = null;
+       while(it.hasNext())
+
+       {
+           curInput = it.next();
+           
+           if (curInput != null && curInput.getInputId().equals(name))
+               break;
+       }
+       
+       return input;
+   }
+   
+   /**
+    * @param renewal the renewal to set
+    */
+   public void setRenewal(String renewal) {
+       this.renewal = renewal;
+   }
+   public static void main(String args[]) throws Exception {
+       EnrollmentRequestData data = new EnrollmentRequestData();
+       data.setProfileId("caUserCert");
+       data.setRenewal("false");
+       
+       
+       //Simulate a "caUserCert" Profile enrollment
+       
+       ProfileInput certReq = data.addInput("KeyGenInput");
+       certReq.setInputAttr("cert_request_type","crmf");
+       certReq.setInputAttr("cert_request", "MIIBozCCAZ8wggEFAgQBMQp8MIHHgAECpQ4wDDEKMAgGA1UEAxMBeKaBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA2NgaPHp0jiohcP4M+ufrJOZEqH8GV+liu5JLbT8nWpkfhC+8EUBqT6g+n3qroSxIcNVGNdcsBEqs1utvpItzyslAbpdyat3WwQep1dWMzo6RHrPDuIoxNA0Yka1n3qEX4U//08cLQtUv2bYglYgN/hOCNQemLV6vZWAv0n7zelkCAwEAAakQMA4GA1UdDwEB/wQEAwIF4DAzMBUGCSsGAQUFBwUBAQwIcmVnVG9rZW4wGgYJKwYBBQUHBQECDA1hdXRoZW50aWNhdG9yoYGTMA0GCSqGSIb3DQEBBQUAA4GBAJ1VOQcaSEhdHa94s8kifVbSZ2WZeYE5//qxL6wVlEst20vq4ybj13CetnbN3+WT49Zkwp7Fg+6lALKgSk47suTg3EbbQDm+8yOrC0nc/q4PTRoHl0alMmUxIhirYc1t3xoCMqJewmjX1bNP8lpVIZAYFZo4eZCpZaiSkM5BeHhz");
+
+       
+       ProfileInput subjectName = data.addInput("SubjectNameInput");
+       subjectName.setInputAttr("sn_uid","jmagne");
+       subjectName.setInputAttr("sn_e","jmagne@redhat.com");
+       subjectName.setInputAttr("sn_c","US");
+       subjectName.setInputAttr("sn_ou","Development");
+       subjectName.setInputAttr("sn_ou1","IPA");
+       subjectName.setInputAttr("sn_ou2","Dogtag");
+       subjectName.setInputAttr("sn_ou3","CA");
+       subjectName.setInputAttr("sn_cn","Common");
+       subjectName.setInputAttr("sn_o","RedHat");
+       
+       ProfileInput submitter =   data.addInput("SubmitterInfoInput");
+       submitter.setInputAttr("requestor_name", "admin");
+       submitter.setInputAttr("requestor_email", "admin@redhat.com");
+       submitter.setInputAttr("requestor_phone","650-555-5555");
+
+       try {
+           JAXBContext context = JAXBContext.newInstance(EnrollmentRequestData.class);
+           Marshaller marshaller = context.createMarshaller();
+           marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
+       
+           ByteArrayOutputStream  stream = new ByteArrayOutputStream();
+       
+       
+           marshaller.marshal(data, stream);
+           
+           System.out.println("Originally marshalled enrollment object. \n");
+       
+           System.out.println(stream.toString());
+       
+           //Try to unmarshall
+       
+           Unmarshaller  unmarshaller = context.createUnmarshaller();
+       
+       
+           ByteArrayInputStream bais = new ByteArrayInputStream(stream.toByteArray());
+           Object unmarshalled = unmarshaller.unmarshal( bais );
+           
+           //Try re-marshalling, unmarshalled object to compare
+           
+           stream.reset();
+           
+           marshaller.marshal(unmarshalled, stream);
+           
+           System.out.println("Remarshalled unmarshalled enrollment object. \n");
+           
+           System.out.println(stream.toString());
+           
+       
+       } catch (JAXBException e) {
+           System.out.println(e.toString());
+       }
+   }
+
+}
diff --git a/base/common/src/com/netscape/cms/servlet/request/model/ProfileRetrievalRequestData.java b/base/common/src/com/netscape/cms/servlet/request/model/ProfileRetrievalRequestData.java
new file mode 100644
index 0000000..b8e0d5a
--- /dev/null
+++ b/base/common/src/com/netscape/cms/servlet/request/model/ProfileRetrievalRequestData.java
@@ -0,0 +1,67 @@
+// --- 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) 2011 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+/**
+ * 
+ */
+package com.netscape.cms.servlet.request.model;
+
+import javax.ws.rs.core.MultivaluedMap;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+
+/**
+ * @author alee
+ *
+ */
+@XmlRootElement(name="ProfileRetrievalRequest")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class ProfileRetrievalRequestData {
+    
+    private static final String PROFILE_ID = "profileId";
+
+    @XmlElement 
+    protected String profileId;
+
+    public ProfileRetrievalRequestData() {
+        // required for JAXB (defaults)
+    }
+    
+    public ProfileRetrievalRequestData(MultivaluedMap<String, String> form) {
+        if (form.containsKey(PROFILE_ID)) {
+            profileId = form.getFirst(PROFILE_ID);
+        }
+    }
+
+    /**
+     * @return the ProfileId
+     */
+    public String getProfileId() {
+        return profileId;
+    }
+
+    /**
+     * @param CertId the CertId to set
+     */
+    public void setProfileId(String profileId) {
+        this.profileId = profileId;
+    }
+    
+}
\ No newline at end of file
diff --git a/base/kra/functional/src/com/netscape/cms/servlet/test/DRMRestClient.java b/base/kra/functional/src/com/netscape/cms/servlet/test/DRMRestClient.java
index f346526..4c7cd00 100644
--- a/base/kra/functional/src/com/netscape/cms/servlet/test/DRMRestClient.java
+++ b/base/kra/functional/src/com/netscape/cms/servlet/test/DRMRestClient.java
@@ -1,30 +1,11 @@
 package com.netscape.cms.servlet.test;
 
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.net.URI;
 import java.net.URISyntaxException;
-import java.net.UnknownHostException;
 import java.util.Collection;
-import java.util.Enumeration;
 import java.util.Iterator;
 
-import org.apache.commons.httpclient.ConnectTimeoutException;
-import org.apache.http.client.HttpClient;
-import org.apache.http.conn.scheme.LayeredSchemeSocketFactory;
-import org.apache.http.conn.scheme.Scheme;
-import org.apache.http.conn.scheme.SchemeSocketFactory;
-import org.apache.http.impl.client.DefaultHttpClient;
-import org.apache.http.params.HttpParams;
-import org.jboss.resteasy.client.ClientExecutor;
 import org.jboss.resteasy.client.ClientResponse;
 import org.jboss.resteasy.client.ProxyFactory;
-import org.jboss.resteasy.client.core.executors.ApacheHttpClient4Executor;
-import org.jboss.resteasy.spi.ResteasyProviderFactory;
-import org.mozilla.jss.ssl.SSLCertificateApprovalCallback;
-import org.mozilla.jss.ssl.SSLSocket;
 
 import com.netscape.certsrv.dbs.keydb.KeyId;
 import com.netscape.certsrv.request.RequestId;
@@ -43,129 +24,7 @@ import com.netscape.cms.servlet.request.model.KeyRequestInfos;
 import com.netscape.cms.servlet.request.model.RecoveryRequestData;
 import com.netscape.cmsutil.util.Utils;
 
-public class DRMRestClient {
-
-    // Callback to approve or deny returned SSL server certs
-    // Right now, simply approve the cert.
-    // ToDO: Look into taking this JSS http client code and move it into
-    // its own class to be used by possible future clients.
-    private class ServerCertApprovalCB implements SSLCertificateApprovalCallback {
-
-        public boolean approve(org.mozilla.jss.crypto.X509Certificate servercert,
-                SSLCertificateApprovalCallback.ValidityStatus status) {
-
-            //For now lets just accept the server cert. This is a test tool, being
-            // pointed at a well know kra instance.
-
-            if (servercert != null) {
-                System.out.println("Peer cert details: " +
-                        "\n     subject: " + servercert.getSubjectDN().toString() +
-                        "\n     issuer:  " + servercert.getIssuerDN().toString() +
-                        "\n     serial:  " + servercert.getSerialNumber().toString()
-                        );
-            }
-
-            SSLCertificateApprovalCallback.ValidityItem item;
-
-            Enumeration<?> errors = status.getReasons();
-            int i = 0;
-            while (errors.hasMoreElements()) {
-                i++;
-                item = (SSLCertificateApprovalCallback.ValidityItem) errors.nextElement();
-                System.out.println("item " + i +
-                        " reason=" + item.getReason() +
-                        " depth=" + item.getDepth());
-
-                int reason = item.getReason();
-
-                if (reason ==
-                        SSLCertificateApprovalCallback.ValidityStatus.UNTRUSTED_ISSUER ||
-                        reason == SSLCertificateApprovalCallback.ValidityStatus.BAD_CERT_DOMAIN) {
-
-                    //Allow these two since we haven't necessarily installed the CA cert for trust
-                    // and we are choosing "localhost" as the host for this client.
-
-                    return true;
-
-                }
-            }
-
-            //For other errors return false
-
-            return false;
-        }
-    }
-
-    private class JSSProtocolSocketFactory implements SchemeSocketFactory, LayeredSchemeSocketFactory {
-
-        @Override
-        public Socket createSocket(HttpParams params)
-                throws IOException {
-
-            return null;
-
-        }
-
-        @Override
-        public Socket connectSocket(Socket sock,
-                InetSocketAddress remoteAddress,
-                InetSocketAddress localAddress,
-                HttpParams params)
-                throws IOException,
-                UnknownHostException,
-                ConnectTimeoutException {
-
-            SSLSocket socket;
-
-            String hostName = null;
-            int port = 0;
-            if (remoteAddress != null) {
-                hostName = remoteAddress.getHostName();
-                port = remoteAddress.getPort();
-
-            }
-
-            int localPort = 0;
-            InetAddress localAddr = null;
-
-            if (localAddress != null) {
-                localPort = localAddress.getPort();
-                localAddr = localAddress.getAddress();
-            }
-
-            if (sock == null) {
-                socket = new SSLSocket(InetAddress.getByName(hostName),
-                        port,
-                        localAddr,
-                        localPort,
-                        new ServerCertApprovalCB(),
-                        null);
-
-            } else {
-                socket = new SSLSocket(sock, hostName, new ServerCertApprovalCB(), null);
-            }
-
-            if (socket != null && clientCertNickname != null) {
-                socket.setClientCertNickname(clientCertNickname);
-            }
-
-            return socket;
-        }
-
-        @Override
-        public boolean isSecure(Socket sock) {
-            //We only use this factory in the case of SSL Connections
-            return true;
-        }
-
-        @Override
-        public Socket createLayeredSocket(Socket arg0, String arg1, int arg2, boolean arg3) throws IOException,
-                UnknownHostException {
-            //This method implementation is required to get SSL working.
-            return null;
-        }
-
-    }
+public class DRMRestClient  extends CMSRestClient {
 
     private KeyResource keyClient;
     private KeysResource keysClient;
@@ -173,33 +32,9 @@ public class DRMRestClient {
     private KeyRequestResource keyRequestClient;
     private SystemCertificateResource systemCertClient;
 
-    private String clientCertNickname = null;
-
     public DRMRestClient(String baseUri, String clientCertNick) throws URISyntaxException {
+        super(baseUri,clientCertNick);
 
-        // For SSL we are assuming the caller has already intialized JSS and has
-        // a valid CryptoManager and CryptoToken
-        // optional clientCertNickname is provided for use if required.
-
-        URI uri = new URI(baseUri);
-
-        String protocol = uri.getScheme();
-        int port = uri.getPort();
-
-        clientCertNickname = clientCertNick;
-        HttpClient httpclient = new DefaultHttpClient();
-        if (protocol != null && protocol.equals("https")) {
-
-            Scheme scheme = new Scheme("https", port, new JSSProtocolSocketFactory());
-
-            // Register for port 443 our SSLSocketFactory to the ConnectionManager
-            httpclient.getConnectionManager().getSchemeRegistry().register(scheme);
-
-        }
-
-        ClientExecutor executor = new ApacheHttpClient4Executor(httpclient);
-
-        ResteasyProviderFactory providerFactory = ResteasyProviderFactory.getInstance();
         providerFactory.addClientErrorInterceptor(new DRMErrorInterceptor());
 
         systemCertClient = ProxyFactory.create(SystemCertificateResource.class, uri, executor, providerFactory);
-- 
1.7.7.6

