Blob Blame History Raw
From 7efc9fbd120885109eb19bfc98d6109a98751b25 Mon Sep 17 00:00:00 2001
From: "Endi S. Dewata" <edewata@redhat.com>
Date: Tue, 29 Oct 2013 10:56:15 -0400
Subject: [PATCH 5/6] Added CLI command aliases.

New aliases for some CLI commands have been added for consistency:

* client-cert-find       -> client-find-cert
* client-cert-import     -> client-import-cert
* client-cert-del        -> client-remove-cert
* group-member-add       -> group-add-member
* group-member-find      -> group-find-member
* group-member-show      -> group-show-member
* group-member-del       -> group-remove-member
* user-cert-add          -> user-add-cert
* user-cert-find         -> user-find-cert
* user-cert-show         -> user-show-cert
* user-cert-del          -> user-remove-cert
* user-membership-add    -> user-add-membership
* user-membership-find   -> user-find-membership
* user-membership-show   -> user-show-membership
* user-membership-del    -> user-remove-membership

The original commands will continue to work as before.
---
 base/java-tools/man/man1/pki.1                     |   4 +-
 .../src/com/netscape/cmstools/cli/CLI.java         |  55 +++++++++
 .../com/netscape/cmstools/client/ClientCLI.java    |  24 +---
 .../cmstools/client/ClientCertFindCLI.java         |  89 +++++++++++++++
 .../cmstools/client/ClientCertImportCLI.java       | 124 +++++++++++++++++++++
 .../cmstools/client/ClientCertRemoveCLI.java       |  70 ++++++++++++
 .../cmstools/client/ClientFindCertCLI.java         |  60 +---------
 .../cmstools/client/ClientImportCertCLI.java       |  95 +---------------
 .../cmstools/client/ClientRemoveCertCLI.java       |  41 +------
 .../netscape/cmstools/group/GroupAddMemberCLI.java |  32 +-----
 .../src/com/netscape/cmstools/group/GroupCLI.java  |  23 +---
 .../cmstools/group/GroupFindMemberCLI.java         |  79 +------------
 .../netscape/cmstools/group/GroupMemberAddCLI.java |  61 ++++++++++
 .../cmstools/group/GroupMemberFindCLI.java         | 108 ++++++++++++++++++
 .../cmstools/group/GroupMemberRemoveCLI.java       |  58 ++++++++++
 .../cmstools/group/GroupMemberShowCLI.java         |  61 ++++++++++
 .../cmstools/group/GroupRemoveMemberCLI.java       |  29 +----
 .../cmstools/group/GroupShowMemberCLI.java         |  32 +-----
 .../com/netscape/cmstools/user/UserAddCertCLI.java |  72 +-----------
 .../cmstools/user/UserAddMembershipCLI.java        |  32 +-----
 .../src/com/netscape/cmstools/user/UserCLI.java    |  28 ++---
 .../com/netscape/cmstools/user/UserCertAddCLI.java | 105 +++++++++++++++++
 .../netscape/cmstools/user/UserCertFindCLI.java    | 108 ++++++++++++++++++
 .../netscape/cmstools/user/UserCertRemoveCLI.java  |  65 +++++++++++
 .../netscape/cmstools/user/UserCertShowCLI.java    | 100 +++++++++++++++++
 .../netscape/cmstools/user/UserFindCertCLI.java    |  79 +------------
 .../cmstools/user/UserFindMembershipCLI.java       |  79 +------------
 .../cmstools/user/UserMembershipAddCLI.java        |  61 ++++++++++
 .../cmstools/user/UserMembershipFindCLI.java       | 108 ++++++++++++++++++
 .../cmstools/user/UserMembershipRemoveCLI.java     |  58 ++++++++++
 .../netscape/cmstools/user/UserRemoveCertCLI.java  |  35 +-----
 .../cmstools/user/UserRemoveMembershipCLI.java     |  29 +----
 .../netscape/cmstools/user/UserShowCertCLI.java    |  71 +-----------
 33 files changed, 1290 insertions(+), 785 deletions(-)
 create mode 100644 base/java-tools/src/com/netscape/cmstools/client/ClientCertFindCLI.java
 create mode 100644 base/java-tools/src/com/netscape/cmstools/client/ClientCertImportCLI.java
 create mode 100644 base/java-tools/src/com/netscape/cmstools/client/ClientCertRemoveCLI.java
 create mode 100644 base/java-tools/src/com/netscape/cmstools/group/GroupMemberAddCLI.java
 create mode 100644 base/java-tools/src/com/netscape/cmstools/group/GroupMemberFindCLI.java
 create mode 100644 base/java-tools/src/com/netscape/cmstools/group/GroupMemberRemoveCLI.java
 create mode 100644 base/java-tools/src/com/netscape/cmstools/group/GroupMemberShowCLI.java
 create mode 100644 base/java-tools/src/com/netscape/cmstools/user/UserCertAddCLI.java
 create mode 100644 base/java-tools/src/com/netscape/cmstools/user/UserCertFindCLI.java
 create mode 100644 base/java-tools/src/com/netscape/cmstools/user/UserCertRemoveCLI.java
 create mode 100644 base/java-tools/src/com/netscape/cmstools/user/UserCertShowCLI.java
 create mode 100644 base/java-tools/src/com/netscape/cmstools/user/UserMembershipAddCLI.java
 create mode 100644 base/java-tools/src/com/netscape/cmstools/user/UserMembershipFindCLI.java
 create mode 100644 base/java-tools/src/com/netscape/cmstools/user/UserMembershipRemoveCLI.java

diff --git a/base/java-tools/man/man1/pki.1 b/base/java-tools/man/man1/pki.1
index ec0af7c..b3c5356 100644
--- a/base/java-tools/man/man1/pki.1
+++ b/base/java-tools/man/man1/pki.1
@@ -199,11 +199,11 @@ To delete a group:
 
 To add a user to a group:
 
-.B pki <admin authentication> group-add-member <group ID> <Member ID>
+.B pki <admin authentication> group-member-add <group ID> <Member ID>
 
 To delete a user from a group:
 
-.B pki <admin authentication> group-remove-member <group ID> <Member ID>
+.B pki <admin authentication> group-member-del <group ID> <Member ID>
 
 .\".SS Key Management Commands
 .\"\fBpki\fP can be used with a KRA to find specific keys and key requests.  This will be documented in more detail at a later time.
diff --git a/base/java-tools/src/com/netscape/cmstools/cli/CLI.java b/base/java-tools/src/com/netscape/cmstools/cli/CLI.java
index a1fc4f7..c9c3606 100644
--- a/base/java-tools/src/com/netscape/cmstools/cli/CLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/cli/CLI.java
@@ -18,6 +18,8 @@
 
 package com.netscape.cmstools.cli;
 
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.LinkedHashMap;
 import java.util.Map;
 
@@ -25,6 +27,7 @@ import org.apache.commons.cli.CommandLineParser;
 import org.apache.commons.cli.HelpFormatter;
 import org.apache.commons.cli.Options;
 import org.apache.commons.cli.PosixParser;
+import org.apache.commons.lang.StringUtils;
 
 
 /**
@@ -64,6 +67,10 @@ public class CLI {
         this.description = description;
     }
 
+    public boolean isDeprecated() {
+        return getClass().getAnnotation(Deprecated.class) != null;
+    }
+
     public void addModule(CLI module) {
         modules.put(module.getName(), module);
     }
@@ -75,7 +82,55 @@ public class CLI {
     public void execute(String[] args) throws Exception {
     }
 
+    public Collection<CLI> getDeprecatedModules() {
+        Collection<CLI> list = new ArrayList<CLI>();
+        for (CLI module : modules.values()) {
+            if (!module.isDeprecated()) continue;
+            list.add(module);
+        }
+        return list;
+    }
+
     public void printHelp() {
+
+        int leftPadding = 1;
+        int rightPadding = 25;
+
+        System.out.println("Commands:");
+
+        for (CLI module : modules.values()) {
+            if (module.isDeprecated()) continue;
+
+            String label = name + "-" + module.getName();
+
+            int padding = rightPadding - leftPadding - label.length();
+            if (padding < 1)
+                padding = 1;
+
+            System.out.print(StringUtils.repeat(" ", leftPadding));
+            System.out.print(label);
+            System.out.print(StringUtils.repeat(" ", padding));
+            System.out.println(module.getDescription());
+        }
+
+        Collection<CLI> deprecatedModules = getDeprecatedModules();
+
+        if (!deprecatedModules.isEmpty()) {
+            System.out.println();
+            System.out.println("Deprecated:");
+
+            for (CLI module : deprecatedModules) {
+                String label = name+"-"+module.getName();
+
+                int padding = rightPadding - leftPadding - label.length();
+                if (padding < 1) padding = 1;
+
+                System.out.print(StringUtils.repeat(" ", leftPadding));
+                System.out.print(label);
+                System.out.print(StringUtils.repeat(" ", padding));
+                System.out.println(module.getDescription());
+            }
+        }
     }
 
     public static boolean isVerbose() {
diff --git a/base/java-tools/src/com/netscape/cmstools/client/ClientCLI.java b/base/java-tools/src/com/netscape/cmstools/client/ClientCLI.java
index 34d09f3..147b4d6 100644
--- a/base/java-tools/src/com/netscape/cmstools/client/ClientCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/client/ClientCLI.java
@@ -20,7 +20,6 @@ package com.netscape.cmstools.client;
 
 import java.util.Arrays;
 
-import org.apache.commons.lang.StringUtils;
 import org.mozilla.jss.crypto.X509Certificate;
 
 import com.netscape.certsrv.dbs.certdb.CertId;
@@ -41,27 +40,10 @@ public class ClientCLI extends CLI {
         addModule(new ClientFindCertCLI(this));
         addModule(new ClientImportCertCLI(this));
         addModule(new ClientRemoveCertCLI(this));
-    }
-
-    public void printHelp() {
-
-        System.out.println("Commands:");
-
-        int leftPadding = 1;
-        int rightPadding = 25;
 
-        for (CLI module : modules.values()) {
-            String label = name + "-" + module.getName();
-
-            int padding = rightPadding - leftPadding - label.length();
-            if (padding < 1)
-                padding = 1;
-
-            System.out.print(StringUtils.repeat(" ", leftPadding));
-            System.out.print(label);
-            System.out.print(StringUtils.repeat(" ", padding));
-            System.out.println(module.getDescription());
-        }
+        addModule(new ClientCertFindCLI(this));
+        addModule(new ClientCertImportCLI(this));
+        addModule(new ClientCertRemoveCLI(this));
     }
 
     public void execute(String[] args) throws Exception {
diff --git a/base/java-tools/src/com/netscape/cmstools/client/ClientCertFindCLI.java b/base/java-tools/src/com/netscape/cmstools/client/ClientCertFindCLI.java
new file mode 100644
index 0000000..c4e1aca
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/client/ClientCertFindCLI.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) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package com.netscape.cmstools.client;
+
+import org.apache.commons.cli.CommandLine;
+import org.mozilla.jss.crypto.X509Certificate;
+
+import com.netscape.cmstools.cli.CLI;
+import com.netscape.cmstools.cli.MainCLI;
+
+/**
+ * @author Endi S. Dewata
+ */
+public class ClientCertFindCLI extends CLI {
+
+    public ClientCLI parent;
+
+    public ClientCertFindCLI(String name, ClientCLI parent) {
+        super(name, "Find certificates in client security database");
+        this.parent = parent;
+    }
+
+    public ClientCertFindCLI(ClientCLI parent) {
+        this("cert-find", parent);
+    }
+
+    public void printHelp() {
+        formatter.printHelp(parent.name + "-" + name + " [OPTIONS]", options);
+    }
+
+    public void execute(String[] args) throws Exception {
+
+        options.addOption(null, "ca", false, "Find CA certificates only");
+
+        CommandLine cmd = null;
+        try {
+            cmd = parser.parse(options, args);
+
+        } catch (Exception e) {
+            System.err.println("Error: " + e.getMessage());
+            printHelp();
+            System.exit(1);
+        }
+
+        X509Certificate[] certs;
+        if (cmd.hasOption("ca")) {
+            certs = parent.parent.client.getCACerts();
+        } else {
+            certs = parent.parent.client.getCerts();
+        }
+
+        if (certs == null || certs.length == 0) {
+            MainCLI.printMessage("No certificates found");
+            System.exit(0); // valid result
+        }
+
+        MainCLI.printMessage(certs.length + " certificate(s) found");
+
+        boolean first = true;
+
+        for (X509Certificate cert : certs) {
+            if (first) {
+                first = false;
+            } else {
+                System.out.println();
+            }
+
+            ClientCLI.printCertInfo(cert);
+        }
+
+        MainCLI.printMessage("Number of entries returned " + certs.length);
+   }
+}
diff --git a/base/java-tools/src/com/netscape/cmstools/client/ClientCertImportCLI.java b/base/java-tools/src/com/netscape/cmstools/client/ClientCertImportCLI.java
new file mode 100644
index 0000000..ffd68d9
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/client/ClientCertImportCLI.java
@@ -0,0 +1,124 @@
+// --- 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) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package com.netscape.cmstools.client;
+
+import java.io.File;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+import org.apache.commons.io.FileUtils;
+import org.mozilla.jss.crypto.X509Certificate;
+
+import com.netscape.certsrv.client.ClientConfig;
+import com.netscape.cmstools.cli.CLI;
+import com.netscape.cmstools.cli.MainCLI;
+
+/**
+ * @author Endi S. Dewata
+ */
+public class ClientCertImportCLI extends CLI {
+
+    public ClientCLI parent;
+
+    public ClientCertImportCLI(String name, ClientCLI parent) {
+        super(name, "Import certificate into client security database");
+        this.parent = parent;
+    }
+
+    public ClientCertImportCLI(ClientCLI parent) {
+        this("cert-import", parent);
+    }
+
+    public void printHelp() {
+        formatter.printHelp(parent.name + "-" + name + " [OPTIONS]", options);
+    }
+
+    public void execute(String[] args) throws Exception {
+
+        Option option = new Option(null, "cert", true, "Import certificate file");
+        option.setArgName("path");
+        options.addOption(option);
+
+        option = new Option(null, "ca-cert", true, "Import CA certificate file");
+        option.setArgName("path");
+        options.addOption(option);
+
+        options.addOption(null, "ca-server", false, "Import CA certificate from CA server");
+
+        CommandLine cmd = null;
+
+        try {
+            cmd = parser.parse(options, args);
+
+        } catch (Exception e) {
+            System.err.println("Error: " + e.getMessage());
+            printHelp();
+            System.exit(1);
+        }
+
+        byte[] bytes = null;
+        X509Certificate cert = null;
+
+        String certPath = cmd.getOptionValue("cert");
+        String caCertPath = cmd.getOptionValue("ca-cert");
+        boolean importFromCAServer = cmd.hasOption("ca-server");
+
+        boolean isCACert = false;
+
+        // load the certificate
+        if (certPath != null) {
+            if (verbose) System.out.println("Loading certificate from " + certPath + ".");
+            bytes = FileUtils.readFileToByteArray(new File(certPath));
+
+
+        } else if (caCertPath != null) {
+            if (verbose) System.out.println("Loading CA certificate from " + caCertPath + ".");
+            bytes = FileUtils.readFileToByteArray(new File(caCertPath));
+
+            isCACert = true;
+
+        } else if (importFromCAServer) {
+            ClientConfig config = parent.parent.config;
+            String caServerURI = "http://" + config.getServerURI().getHost() + ":8080/ca";
+
+            if (verbose) System.out.println("Downloading CA certificate from " + caServerURI + ".");
+            bytes = parent.parent.client.downloadCACertChain(caServerURI);
+
+            isCACert = true;
+
+        } else {
+            System.err.println("Error: Missing certificate to import");
+            printHelp();
+            System.exit(1);
+        }
+
+        // import the certificate
+        if (isCACert) {
+            if (verbose) System.out.println("Importing CA certificate.");
+            cert = parent.parent.client.importCACertPackage(bytes);
+
+        } else {
+            if (verbose) System.out.println("Importing certificate.");
+            cert = parent.parent.client.importCertPackage(bytes, parent.parent.client.config.getCertNickname());
+        }
+
+        MainCLI.printMessage("Imported certificate \"" + cert.getNickname() + "\"");
+        ClientCLI.printCertInfo(cert);
+    }
+}
diff --git a/base/java-tools/src/com/netscape/cmstools/client/ClientCertRemoveCLI.java b/base/java-tools/src/com/netscape/cmstools/client/ClientCertRemoveCLI.java
new file mode 100644
index 0000000..2c05446
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/client/ClientCertRemoveCLI.java
@@ -0,0 +1,70 @@
+// --- 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) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package com.netscape.cmstools.client;
+
+import org.apache.commons.cli.CommandLine;
+
+import com.netscape.cmstools.cli.CLI;
+import com.netscape.cmstools.cli.MainCLI;
+
+/**
+ * @author Endi S. Dewata
+ */
+public class ClientCertRemoveCLI extends CLI {
+
+    public ClientCLI parent;
+
+    public ClientCertRemoveCLI(String name, ClientCLI parent) {
+        super(name, "Remove certificate from client security database");
+        this.parent = parent;
+    }
+
+    public ClientCertRemoveCLI(ClientCLI parent) {
+        this("cert-del", parent);
+    }
+
+    public void printHelp() {
+        formatter.printHelp(parent.name + "-" + name + " <nickname>", options);
+    }
+
+    public void execute(String[] args) throws Exception {
+
+        CommandLine cmd = null;
+        try {
+            cmd = parser.parse(options, args);
+
+        } catch (Exception e) {
+            System.err.println("Error: " + e.getMessage());
+            printHelp();
+            System.exit(1);
+        }
+
+        String[] cmdArgs = cmd.getArgs();
+
+        if (cmdArgs.length != 1) {
+            printHelp();
+            System.exit(1);
+        }
+
+        String nickname = cmdArgs[0];
+        parent.parent.client.removeCert(nickname);
+
+        MainCLI.printMessage("Removed certificate \"" + nickname + "\"");
+   }
+}
diff --git a/base/java-tools/src/com/netscape/cmstools/client/ClientFindCertCLI.java b/base/java-tools/src/com/netscape/cmstools/client/ClientFindCertCLI.java
index 80690b7..379e95a 100644
--- a/base/java-tools/src/com/netscape/cmstools/client/ClientFindCertCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/client/ClientFindCertCLI.java
@@ -18,68 +18,14 @@
 
 package com.netscape.cmstools.client;
 
-import org.apache.commons.cli.CommandLine;
-import org.mozilla.jss.crypto.X509Certificate;
-
-import com.netscape.cmstools.cli.CLI;
-import com.netscape.cmstools.cli.MainCLI;
 
 /**
  * @author Endi S. Dewata
  */
-public class ClientFindCertCLI extends CLI {
-
-    public ClientCLI parent;
+@Deprecated
+public class ClientFindCertCLI extends ClientCertFindCLI {
 
     public ClientFindCertCLI(ClientCLI parent) {
-        super("find-cert", "Find certificates in client security database");
-        this.parent = parent;
-    }
-
-    public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " [OPTIONS]", options);
+        super("find-cert", parent);
     }
-
-    public void execute(String[] args) throws Exception {
-
-        options.addOption(null, "ca", false, "Find CA certificates only");
-
-        CommandLine cmd = null;
-        try {
-            cmd = parser.parse(options, args);
-
-        } catch (Exception e) {
-            System.err.println("Error: " + e.getMessage());
-            printHelp();
-            System.exit(1);
-        }
-
-        X509Certificate[] certs;
-        if (cmd.hasOption("ca")) {
-            certs = parent.parent.client.getCACerts();
-        } else {
-            certs = parent.parent.client.getCerts();
-        }
-
-        if (certs == null || certs.length == 0) {
-            MainCLI.printMessage("No certificates found");
-            System.exit(0); // valid result
-        }
-
-        MainCLI.printMessage(certs.length + " certificate(s) found");
-
-        boolean first = true;
-
-        for (X509Certificate cert : certs) {
-            if (first) {
-                first = false;
-            } else {
-                System.out.println();
-            }
-
-            ClientCLI.printCertInfo(cert);
-        }
-
-        MainCLI.printMessage("Number of entries returned " + certs.length);
-   }
 }
diff --git a/base/java-tools/src/com/netscape/cmstools/client/ClientImportCertCLI.java b/base/java-tools/src/com/netscape/cmstools/client/ClientImportCertCLI.java
index e89f954..db0736d 100644
--- a/base/java-tools/src/com/netscape/cmstools/client/ClientImportCertCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/client/ClientImportCertCLI.java
@@ -18,103 +18,14 @@
 
 package com.netscape.cmstools.client;
 
-import java.io.File;
-
-import org.apache.commons.cli.CommandLine;
-import org.apache.commons.cli.Option;
-import org.apache.commons.io.FileUtils;
-import org.mozilla.jss.crypto.X509Certificate;
-
-import com.netscape.certsrv.client.ClientConfig;
-import com.netscape.cmstools.cli.CLI;
-import com.netscape.cmstools.cli.MainCLI;
 
 /**
  * @author Endi S. Dewata
  */
-public class ClientImportCertCLI extends CLI {
-
-    public ClientCLI parent;
+@Deprecated
+public class ClientImportCertCLI extends ClientCertImportCLI {
 
     public ClientImportCertCLI(ClientCLI parent) {
-        super("import-cert", "Import certificate into client security database");
-        this.parent = parent;
-    }
-
-    public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " [OPTIONS]", options);
-    }
-
-    public void execute(String[] args) throws Exception {
-
-        Option option = new Option(null, "cert", true, "Import certificate file");
-        option.setArgName("path");
-        options.addOption(option);
-
-        option = new Option(null, "ca-cert", true, "Import CA certificate file");
-        option.setArgName("path");
-        options.addOption(option);
-
-        options.addOption(null, "ca-server", false, "Import CA certificate from CA server");
-
-        CommandLine cmd = null;
-
-        try {
-            cmd = parser.parse(options, args);
-
-        } catch (Exception e) {
-            System.err.println("Error: " + e.getMessage());
-            printHelp();
-            System.exit(1);
-        }
-
-        byte[] bytes = null;
-        X509Certificate cert = null;
-
-        String certPath = cmd.getOptionValue("cert");
-        String caCertPath = cmd.getOptionValue("ca-cert");
-        boolean importFromCAServer = cmd.hasOption("ca-server");
-
-        boolean isCACert = false;
-
-        // load the certificate
-        if (certPath != null) {
-            if (verbose) System.out.println("Loading certificate from " + certPath + ".");
-            bytes = FileUtils.readFileToByteArray(new File(certPath));
-
-
-        } else if (caCertPath != null) {
-            if (verbose) System.out.println("Loading CA certificate from " + caCertPath + ".");
-            bytes = FileUtils.readFileToByteArray(new File(caCertPath));
-
-            isCACert = true;
-
-        } else if (importFromCAServer) {
-            ClientConfig config = parent.parent.config;
-            String caServerURI = "http://" + config.getServerURI().getHost() + ":8080/ca";
-
-            if (verbose) System.out.println("Downloading CA certificate from " + caServerURI + ".");
-            bytes = parent.parent.client.downloadCACertChain(caServerURI);
-
-            isCACert = true;
-
-        } else {
-            System.err.println("Error: Missing certificate to import");
-            printHelp();
-            System.exit(1);
-        }
-
-        // import the certificate
-        if (isCACert) {
-            if (verbose) System.out.println("Importing CA certificate.");
-            cert = parent.parent.client.importCACertPackage(bytes);
-
-        } else {
-            if (verbose) System.out.println("Importing certificate.");
-            cert = parent.parent.client.importCertPackage(bytes, parent.parent.client.config.getCertNickname());
-        }
-
-        MainCLI.printMessage("Imported certificate \"" + cert.getNickname() + "\"");
-        ClientCLI.printCertInfo(cert);
+        super("import-cert", parent);
     }
 }
diff --git a/base/java-tools/src/com/netscape/cmstools/client/ClientRemoveCertCLI.java b/base/java-tools/src/com/netscape/cmstools/client/ClientRemoveCertCLI.java
index fab4296..2b217ac 100644
--- a/base/java-tools/src/com/netscape/cmstools/client/ClientRemoveCertCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/client/ClientRemoveCertCLI.java
@@ -18,49 +18,14 @@
 
 package com.netscape.cmstools.client;
 
-import org.apache.commons.cli.CommandLine;
-
-import com.netscape.cmstools.cli.CLI;
-import com.netscape.cmstools.cli.MainCLI;
 
 /**
  * @author Endi S. Dewata
  */
-public class ClientRemoveCertCLI extends CLI {
-
-    public ClientCLI parent;
+@Deprecated
+public class ClientRemoveCertCLI extends ClientCertRemoveCLI {
 
     public ClientRemoveCertCLI(ClientCLI parent) {
-        super("remove-cert", "Remove certificate from client security database");
-        this.parent = parent;
-    }
-
-    public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <nickname>", options);
+        super("remove-cert", parent);
     }
-
-    public void execute(String[] args) throws Exception {
-
-        CommandLine cmd = null;
-        try {
-            cmd = parser.parse(options, args);
-
-        } catch (Exception e) {
-            System.err.println("Error: " + e.getMessage());
-            printHelp();
-            System.exit(1);
-        }
-
-        String[] cmdArgs = cmd.getArgs();
-
-        if (cmdArgs.length != 1) {
-            printHelp();
-            System.exit(1);
-        }
-
-        String nickname = cmdArgs[0];
-        parent.parent.client.removeCert(nickname);
-
-        MainCLI.printMessage("Removed certificate \"" + nickname + "\"");
-   }
 }
diff --git a/base/java-tools/src/com/netscape/cmstools/group/GroupAddMemberCLI.java b/base/java-tools/src/com/netscape/cmstools/group/GroupAddMemberCLI.java
index 36d3c06..a761853 100644
--- a/base/java-tools/src/com/netscape/cmstools/group/GroupAddMemberCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/group/GroupAddMemberCLI.java
@@ -18,40 +18,14 @@
 
 package com.netscape.cmstools.group;
 
-import com.netscape.certsrv.group.GroupMemberData;
-import com.netscape.cmstools.cli.CLI;
-import com.netscape.cmstools.cli.MainCLI;
 
 /**
  * @author Endi S. Dewata
  */
-public class GroupAddMemberCLI extends CLI {
-
-    public GroupCLI parent;
+@Deprecated
+public class GroupAddMemberCLI extends GroupMemberAddCLI {
 
     public GroupAddMemberCLI(GroupCLI parent) {
-        super("add-member", "Add group member");
-        this.parent = parent;
-    }
-
-    public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <Group ID> <Member ID>", options);
-    }
-
-    public void execute(String[] args) throws Exception {
-
-        if (args.length != 2) {
-            printHelp();
-            System.exit(1);
-        }
-
-        String groupID = args[0];
-        String memberID = args[1];
-
-        GroupMemberData groupMemberData = parent.client.addGroupMember(groupID, memberID);
-
-        MainCLI.printMessage("Added group member \""+memberID+"\"");
-
-        GroupCLI.printGroupMember(groupMemberData);
+        super("add-member", parent);
     }
 }
diff --git a/base/java-tools/src/com/netscape/cmstools/group/GroupCLI.java b/base/java-tools/src/com/netscape/cmstools/group/GroupCLI.java
index bd8cec7..bc4d573 100644
--- a/base/java-tools/src/com/netscape/cmstools/group/GroupCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/group/GroupCLI.java
@@ -51,26 +51,11 @@ public class GroupCLI extends CLI {
         addModule(new GroupShowMemberCLI(this));
         addModule(new GroupAddMemberCLI(this));
         addModule(new GroupRemoveMemberCLI(this));
-    }
-
-    public void printHelp() {
-
-        System.out.println("Commands:");
-
-        int leftPadding = 1;
-        int rightPadding = 25;
 
-        for (CLI module : modules.values()) {
-            String label = name+"-"+module.getName();
-
-            int padding = rightPadding - leftPadding - label.length();
-            if (padding < 1) padding = 1;
-
-            System.out.print(StringUtils.repeat(" ", leftPadding));
-            System.out.print(label);
-            System.out.print(StringUtils.repeat(" ", padding));
-            System.out.println(module.getDescription());
-        }
+        addModule(new GroupMemberFindCLI(this));
+        addModule(new GroupMemberShowCLI(this));
+        addModule(new GroupMemberAddCLI(this));
+        addModule(new GroupMemberRemoveCLI(this));
     }
 
     public void execute(String[] args) throws Exception {
diff --git a/base/java-tools/src/com/netscape/cmstools/group/GroupFindMemberCLI.java b/base/java-tools/src/com/netscape/cmstools/group/GroupFindMemberCLI.java
index f0498f0..4850910 100644
--- a/base/java-tools/src/com/netscape/cmstools/group/GroupFindMemberCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/group/GroupFindMemberCLI.java
@@ -18,87 +18,14 @@
 
 package com.netscape.cmstools.group;
 
-import java.util.Collection;
-
-import org.apache.commons.cli.CommandLine;
-import org.apache.commons.cli.Option;
-
-import com.netscape.certsrv.group.GroupMemberCollection;
-import com.netscape.certsrv.group.GroupMemberData;
-import com.netscape.cmstools.cli.CLI;
-import com.netscape.cmstools.cli.MainCLI;
 
 /**
  * @author Endi S. Dewata
  */
-public class GroupFindMemberCLI extends CLI {
-
-    public GroupCLI parent;
+@Deprecated
+public class GroupFindMemberCLI extends GroupMemberFindCLI {
 
     public GroupFindMemberCLI(GroupCLI parent) {
-        super("find-member", "Find group members");
-        this.parent = parent;
-    }
-
-    public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <Group ID> [OPTIONS...]", options);
-    }
-
-    public void execute(String[] args) throws Exception {
-
-        Option option = new Option(null, "start", true, "Page start");
-        option.setArgName("start");
-        options.addOption(option);
-
-        option = new Option(null, "size", true, "Page size");
-        option.setArgName("size");
-        options.addOption(option);
-
-        CommandLine cmd = null;
-
-        try {
-            cmd = parser.parse(options, args);
-
-        } catch (Exception e) {
-            System.err.println("Error: " + e.getMessage());
-            printHelp();
-            System.exit(1);
-        }
-
-        String[] cmdArgs = cmd.getArgs();
-
-        if (cmdArgs.length != 1) {
-            printHelp();
-            System.exit(1);
-        }
-
-        String groupID = cmdArgs[0];
-
-        String s = cmd.getOptionValue("start");
-        Integer start = s == null ? null : Integer.valueOf(s);
-
-        s = cmd.getOptionValue("size");
-        Integer size = s == null ? null : Integer.valueOf(s);
-
-        GroupMemberCollection response = parent.client.findGroupMembers(groupID, start, size);
-
-        Collection<GroupMemberData> entries = response.getMembers();
-
-        MainCLI.printMessage(entries.size()+" group member(s) matched");
-
-        boolean first = true;
-
-        for (GroupMemberData groupMemberData : entries) {
-
-            if (first) {
-                first = false;
-            } else {
-                System.out.println();
-            }
-
-            GroupCLI.printGroupMember(groupMemberData);
-        }
-
-        MainCLI.printMessage("Number of entries returned "+entries.size());
+        super("find-member", parent);
     }
 }
diff --git a/base/java-tools/src/com/netscape/cmstools/group/GroupMemberAddCLI.java b/base/java-tools/src/com/netscape/cmstools/group/GroupMemberAddCLI.java
new file mode 100644
index 0000000..5945e21
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/group/GroupMemberAddCLI.java
@@ -0,0 +1,61 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2012 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package com.netscape.cmstools.group;
+
+import com.netscape.certsrv.group.GroupMemberData;
+import com.netscape.cmstools.cli.CLI;
+import com.netscape.cmstools.cli.MainCLI;
+
+/**
+ * @author Endi S. Dewata
+ */
+public class GroupMemberAddCLI extends CLI {
+
+    public GroupCLI parent;
+
+    public GroupMemberAddCLI(String name, GroupCLI parent) {
+        super(name, "Add group member");
+        this.parent = parent;
+    }
+
+    public GroupMemberAddCLI(GroupCLI parent) {
+        this("member-add", parent);
+    }
+
+    public void printHelp() {
+        formatter.printHelp(parent.name + "-" + name + " <Group ID> <Member ID>", options);
+    }
+
+    public void execute(String[] args) throws Exception {
+
+        if (args.length != 2) {
+            printHelp();
+            System.exit(1);
+        }
+
+        String groupID = args[0];
+        String memberID = args[1];
+
+        GroupMemberData groupMemberData = parent.client.addGroupMember(groupID, memberID);
+
+        MainCLI.printMessage("Added group member \""+memberID+"\"");
+
+        GroupCLI.printGroupMember(groupMemberData);
+    }
+}
diff --git a/base/java-tools/src/com/netscape/cmstools/group/GroupMemberFindCLI.java b/base/java-tools/src/com/netscape/cmstools/group/GroupMemberFindCLI.java
new file mode 100644
index 0000000..c36d041
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/group/GroupMemberFindCLI.java
@@ -0,0 +1,108 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2012 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package com.netscape.cmstools.group;
+
+import java.util.Collection;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+
+import com.netscape.certsrv.group.GroupMemberCollection;
+import com.netscape.certsrv.group.GroupMemberData;
+import com.netscape.cmstools.cli.CLI;
+import com.netscape.cmstools.cli.MainCLI;
+
+/**
+ * @author Endi S. Dewata
+ */
+public class GroupMemberFindCLI extends CLI {
+
+    public GroupCLI parent;
+
+    public GroupMemberFindCLI(String name, GroupCLI parent) {
+        super(name, "Find group members");
+        this.parent = parent;
+    }
+
+    public GroupMemberFindCLI(GroupCLI parent) {
+        this("member-find", parent);
+    }
+
+    public void printHelp() {
+        formatter.printHelp(parent.name + "-" + name + " <Group ID> [OPTIONS...]", options);
+    }
+
+    public void execute(String[] args) throws Exception {
+
+        Option option = new Option(null, "start", true, "Page start");
+        option.setArgName("start");
+        options.addOption(option);
+
+        option = new Option(null, "size", true, "Page size");
+        option.setArgName("size");
+        options.addOption(option);
+
+        CommandLine cmd = null;
+
+        try {
+            cmd = parser.parse(options, args);
+
+        } catch (Exception e) {
+            System.err.println("Error: " + e.getMessage());
+            printHelp();
+            System.exit(1);
+        }
+
+        String[] cmdArgs = cmd.getArgs();
+
+        if (cmdArgs.length != 1) {
+            printHelp();
+            System.exit(1);
+        }
+
+        String groupID = cmdArgs[0];
+
+        String s = cmd.getOptionValue("start");
+        Integer start = s == null ? null : Integer.valueOf(s);
+
+        s = cmd.getOptionValue("size");
+        Integer size = s == null ? null : Integer.valueOf(s);
+
+        GroupMemberCollection response = parent.client.findGroupMembers(groupID, start, size);
+
+        Collection<GroupMemberData> entries = response.getMembers();
+
+        MainCLI.printMessage(entries.size()+" group member(s) matched");
+
+        boolean first = true;
+
+        for (GroupMemberData groupMemberData : entries) {
+
+            if (first) {
+                first = false;
+            } else {
+                System.out.println();
+            }
+
+            GroupCLI.printGroupMember(groupMemberData);
+        }
+
+        MainCLI.printMessage("Number of entries returned "+entries.size());
+    }
+}
diff --git a/base/java-tools/src/com/netscape/cmstools/group/GroupMemberRemoveCLI.java b/base/java-tools/src/com/netscape/cmstools/group/GroupMemberRemoveCLI.java
new file mode 100644
index 0000000..db85822
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/group/GroupMemberRemoveCLI.java
@@ -0,0 +1,58 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2012 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package com.netscape.cmstools.group;
+
+import com.netscape.cmstools.cli.CLI;
+import com.netscape.cmstools.cli.MainCLI;
+
+/**
+ * @author Endi S. Dewata
+ */
+public class GroupMemberRemoveCLI extends CLI {
+
+    public GroupCLI parent;
+
+    public GroupMemberRemoveCLI(String name, GroupCLI parent) {
+        super(name, "Remove group member");
+        this.parent = parent;
+    }
+
+    public GroupMemberRemoveCLI(GroupCLI parent) {
+        this("member-del", parent);
+    }
+
+    public void printHelp() {
+        formatter.printHelp(parent.name + "-" + name + " <Group ID> <Member ID>", options);
+    }
+
+    public void execute(String[] args) throws Exception {
+
+        if (args.length != 2) {
+            printHelp();
+            System.exit(1);
+        }
+
+        String groupID = args[0];
+        String memberID = args[1];
+
+        parent.client.removeGroupMember(groupID, memberID);
+
+        MainCLI.printMessage("Deleted group member \""+memberID+"\"");
+    }
+}
diff --git a/base/java-tools/src/com/netscape/cmstools/group/GroupMemberShowCLI.java b/base/java-tools/src/com/netscape/cmstools/group/GroupMemberShowCLI.java
new file mode 100644
index 0000000..214f71d
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/group/GroupMemberShowCLI.java
@@ -0,0 +1,61 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2012 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package com.netscape.cmstools.group;
+
+import com.netscape.certsrv.group.GroupMemberData;
+import com.netscape.cmstools.cli.CLI;
+import com.netscape.cmstools.cli.MainCLI;
+
+/**
+ * @author Endi S. Dewata
+ */
+public class GroupMemberShowCLI extends CLI {
+
+    public GroupCLI parent;
+
+    public GroupMemberShowCLI(String name, GroupCLI parent) {
+        super(name, "Show group member");
+        this.parent = parent;
+    }
+
+    public GroupMemberShowCLI(GroupCLI parent) {
+        this("member-show", parent);
+    }
+
+    public void printHelp() {
+        formatter.printHelp(parent.name + "-" + name + " <Group ID> <Member ID>", options);
+    }
+
+    public void execute(String[] args) throws Exception {
+
+        if (args.length != 2) {
+            printHelp();
+            System.exit(1);
+        }
+
+        String groupID = args[0];
+        String memberID = args[1];
+
+        GroupMemberData groupMemberData = parent.client.getGroupMember(groupID, memberID);
+
+        MainCLI.printMessage("Group member \""+memberID+"\"");
+
+        GroupCLI.printGroupMember(groupMemberData);
+    }
+}
diff --git a/base/java-tools/src/com/netscape/cmstools/group/GroupRemoveMemberCLI.java b/base/java-tools/src/com/netscape/cmstools/group/GroupRemoveMemberCLI.java
index c12cc89..9672488 100644
--- a/base/java-tools/src/com/netscape/cmstools/group/GroupRemoveMemberCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/group/GroupRemoveMemberCLI.java
@@ -18,37 +18,14 @@
 
 package com.netscape.cmstools.group;
 
-import com.netscape.cmstools.cli.CLI;
-import com.netscape.cmstools.cli.MainCLI;
 
 /**
  * @author Endi S. Dewata
  */
-public class GroupRemoveMemberCLI extends CLI {
-
-    public GroupCLI parent;
+@Deprecated
+public class GroupRemoveMemberCLI extends GroupMemberRemoveCLI {
 
     public GroupRemoveMemberCLI(GroupCLI parent) {
-        super("remove-member", "Remove group member");
-        this.parent = parent;
-    }
-
-    public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <Group ID> <Member ID>", options);
-    }
-
-    public void execute(String[] args) throws Exception {
-
-        if (args.length != 2) {
-            printHelp();
-            System.exit(1);
-        }
-
-        String groupID = args[0];
-        String memberID = args[1];
-
-        parent.client.removeGroupMember(groupID, memberID);
-
-        MainCLI.printMessage("Deleted group member \""+memberID+"\"");
+        super("remove-member", parent);
     }
 }
diff --git a/base/java-tools/src/com/netscape/cmstools/group/GroupShowMemberCLI.java b/base/java-tools/src/com/netscape/cmstools/group/GroupShowMemberCLI.java
index 47ca43c..6e493d3 100644
--- a/base/java-tools/src/com/netscape/cmstools/group/GroupShowMemberCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/group/GroupShowMemberCLI.java
@@ -18,40 +18,14 @@
 
 package com.netscape.cmstools.group;
 
-import com.netscape.certsrv.group.GroupMemberData;
-import com.netscape.cmstools.cli.CLI;
-import com.netscape.cmstools.cli.MainCLI;
 
 /**
  * @author Endi S. Dewata
  */
-public class GroupShowMemberCLI extends CLI {
-
-    public GroupCLI parent;
+@Deprecated
+public class GroupShowMemberCLI extends GroupMemberShowCLI {
 
     public GroupShowMemberCLI(GroupCLI parent) {
-        super("show-member", "Show group member");
-        this.parent = parent;
-    }
-
-    public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <Group ID> <Member ID>", options);
-    }
-
-    public void execute(String[] args) throws Exception {
-
-        if (args.length != 2) {
-            printHelp();
-            System.exit(1);
-        }
-
-        String groupID = args[0];
-        String memberID = args[1];
-
-        GroupMemberData groupMemberData = parent.client.getGroupMember(groupID, memberID);
-
-        MainCLI.printMessage("Group member \""+memberID+"\"");
-
-        GroupCLI.printGroupMember(groupMemberData);
+        super("show-member", parent);
     }
 }
diff --git a/base/java-tools/src/com/netscape/cmstools/user/UserAddCertCLI.java b/base/java-tools/src/com/netscape/cmstools/user/UserAddCertCLI.java
index 7bec2ff..528d39c 100644
--- a/base/java-tools/src/com/netscape/cmstools/user/UserAddCertCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/user/UserAddCertCLI.java
@@ -18,80 +18,14 @@
 
 package com.netscape.cmstools.user;
 
-import java.io.File;
-import java.util.Scanner;
-
-import org.apache.commons.cli.CommandLine;
-import org.apache.commons.cli.Option;
-
-import com.netscape.certsrv.user.UserCertData;
-import com.netscape.cmstools.cli.CLI;
-import com.netscape.cmstools.cli.MainCLI;
 
 /**
  * @author Endi S. Dewata
  */
-public class UserAddCertCLI extends CLI {
-
-    public UserCLI parent;
+@Deprecated
+public class UserAddCertCLI extends UserCertAddCLI {
 
     public UserAddCertCLI(UserCLI parent) {
-        super("add-cert", "Add user cert");
-        this.parent = parent;
-    }
-
-    public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <User ID> [OPTIONS...]", options);
-    }
-
-    public void execute(String[] args) throws Exception {
-
-        Option option = new Option(null, "input", true, "Input file");
-        option.setArgName("file");
-        option.setRequired(true);
-        options.addOption(option);
-
-        CommandLine cmd = null;
-
-        try {
-            cmd = parser.parse(options, args);
-
-        } catch (Exception e) {
-            System.err.println("Error: " + e.getMessage());
-            printHelp();
-            System.exit(1);
-        }
-
-        String[] cmdArgs = cmd.getArgs();
-
-        if (cmdArgs.length != 1) {
-            printHelp();
-            System.exit(1);
-        }
-
-        String userId = cmdArgs[0];
-        String file = cmd.getOptionValue("input");
-
-        // get cert from file
-        if (verbose) {
-            System.out.println("Reading cert from "+file+".");
-        }
-        String encoded = new Scanner(new File(file)).useDelimiter("\\A").next();
-        if (verbose) {
-            System.out.println(encoded);
-        }
-
-        UserCertData userCertData = new UserCertData();
-        userCertData.setEncoded(encoded);
-
-        if (verbose) {
-            System.out.println(userCertData);
-        }
-
-        userCertData = parent.client.addUserCert(userId, userCertData);
-
-        MainCLI.printMessage("Added certificate \"" + userCertData.getID() + "\"");
-
-        UserCLI.printCert(userCertData, false, false);
+        super("add-cert", parent);
     }
 }
diff --git a/base/java-tools/src/com/netscape/cmstools/user/UserAddMembershipCLI.java b/base/java-tools/src/com/netscape/cmstools/user/UserAddMembershipCLI.java
index 224f226..43a55ea 100644
--- a/base/java-tools/src/com/netscape/cmstools/user/UserAddMembershipCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/user/UserAddMembershipCLI.java
@@ -18,40 +18,14 @@
 
 package com.netscape.cmstools.user;
 
-import com.netscape.certsrv.user.UserMembershipData;
-import com.netscape.cmstools.cli.CLI;
-import com.netscape.cmstools.cli.MainCLI;
 
 /**
  * @author Endi S. Dewata
  */
-public class UserAddMembershipCLI extends CLI {
-
-    public UserCLI parent;
+@Deprecated
+public class UserAddMembershipCLI extends UserMembershipAddCLI {
 
     public UserAddMembershipCLI(UserCLI parent) {
-        super("add-membership", "Add user membership");
-        this.parent = parent;
-    }
-
-    public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <User ID> <Group ID>", options);
-    }
-
-    public void execute(String[] args) throws Exception {
-
-        if (args.length != 2) {
-            printHelp();
-            System.exit(1);
-        }
-
-        String userID = args[0];
-        String groupID = args[1];
-
-        UserMembershipData userMembershipData = parent.client.addUserMembership(userID, groupID);
-
-        MainCLI.printMessage("Added membership in \""+groupID+"\"");
-
-        UserCLI.printUserMembership(userMembershipData);
+        super("add-membership", parent);
     }
 }
diff --git a/base/java-tools/src/com/netscape/cmstools/user/UserCLI.java b/base/java-tools/src/com/netscape/cmstools/user/UserCLI.java
index 2343d19..be404b8 100644
--- a/base/java-tools/src/com/netscape/cmstools/user/UserCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/user/UserCLI.java
@@ -53,30 +53,18 @@ public class UserCLI extends CLI {
         addModule(new UserAddCertCLI(this));
         addModule(new UserRemoveCertCLI(this));
 
+        addModule(new UserCertFindCLI(this));
+        addModule(new UserCertShowCLI(this));
+        addModule(new UserCertAddCLI(this));
+        addModule(new UserCertRemoveCLI(this));
+
         addModule(new UserFindMembershipCLI(this));
         addModule(new UserAddMembershipCLI(this));
         addModule(new UserRemoveMembershipCLI(this));
-    }
-
-    public void printHelp() {
-
-        System.out.println("Commands:");
 
-        int leftPadding = 1;
-        int rightPadding = 25;
-
-        for (CLI module : modules.values()) {
-            String label = name + "-" + module.getName();
-
-            int padding = rightPadding - leftPadding - label.length();
-            if (padding < 1)
-                padding = 1;
-
-            System.out.print(StringUtils.repeat(" ", leftPadding));
-            System.out.print(label);
-            System.out.print(StringUtils.repeat(" ", padding));
-            System.out.println(module.getDescription());
-        }
+        addModule(new UserMembershipFindCLI(this));
+        addModule(new UserMembershipAddCLI(this));
+        addModule(new UserMembershipRemoveCLI(this));
     }
 
     public void execute(String[] args) throws Exception {
diff --git a/base/java-tools/src/com/netscape/cmstools/user/UserCertAddCLI.java b/base/java-tools/src/com/netscape/cmstools/user/UserCertAddCLI.java
new file mode 100644
index 0000000..6e2e5cc
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/user/UserCertAddCLI.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) 2012 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package com.netscape.cmstools.user;
+
+import java.io.File;
+import java.util.Scanner;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+
+import com.netscape.certsrv.user.UserCertData;
+import com.netscape.cmstools.cli.CLI;
+import com.netscape.cmstools.cli.MainCLI;
+
+/**
+ * @author Endi S. Dewata
+ */
+public class UserCertAddCLI extends CLI {
+
+    public UserCLI parent;
+
+    public UserCertAddCLI(String name, UserCLI parent) {
+        super(name, "Add user cert");
+        this.parent = parent;
+    }
+
+    public UserCertAddCLI(UserCLI parent) {
+        this("cert-add", parent);
+    }
+
+    public void printHelp() {
+        formatter.printHelp(parent.name + "-" + name + " <User ID> [OPTIONS...]", options);
+    }
+
+    public void execute(String[] args) throws Exception {
+
+        Option option = new Option(null, "input", true, "Input file");
+        option.setArgName("file");
+        option.setRequired(true);
+        options.addOption(option);
+
+        CommandLine cmd = null;
+
+        try {
+            cmd = parser.parse(options, args);
+
+        } catch (Exception e) {
+            System.err.println("Error: " + e.getMessage());
+            printHelp();
+            System.exit(1);
+        }
+
+        String[] cmdArgs = cmd.getArgs();
+
+        if (cmdArgs.length != 1) {
+            printHelp();
+            System.exit(1);
+        }
+
+        String userId = cmdArgs[0];
+        String file = cmd.getOptionValue("input");
+
+        // get cert from file
+        if (verbose) {
+            System.out.println("Reading cert from "+file+".");
+        }
+
+        UserCertData userCertData = new UserCertData();
+
+        try (Scanner scanner = new Scanner(new File(file))) {
+            String encoded = scanner.useDelimiter("\\A").next();
+            if (verbose) {
+                System.out.println(encoded);
+            }
+
+            userCertData.setEncoded(encoded);
+        }
+
+        if (verbose) {
+            System.out.println(userCertData);
+        }
+
+        userCertData = parent.client.addUserCert(userId, userCertData);
+
+        MainCLI.printMessage("Added certificate \"" + userCertData.getID() + "\"");
+
+        UserCLI.printCert(userCertData, false, false);
+    }
+}
diff --git a/base/java-tools/src/com/netscape/cmstools/user/UserCertFindCLI.java b/base/java-tools/src/com/netscape/cmstools/user/UserCertFindCLI.java
new file mode 100644
index 0000000..c0c85a0
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/user/UserCertFindCLI.java
@@ -0,0 +1,108 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2012 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package com.netscape.cmstools.user;
+
+import java.util.Collection;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+
+import com.netscape.certsrv.user.UserCertCollection;
+import com.netscape.certsrv.user.UserCertData;
+import com.netscape.cmstools.cli.CLI;
+import com.netscape.cmstools.cli.MainCLI;
+
+/**
+ * @author Endi S. Dewata
+ */
+public class UserCertFindCLI extends CLI {
+
+    public UserCLI parent;
+
+    public UserCertFindCLI(String name, UserCLI parent) {
+        super(name, "Find user certs");
+        this.parent = parent;
+    }
+
+    public UserCertFindCLI(UserCLI parent) {
+        this("cert-find", parent);
+    }
+
+    public void printHelp() {
+        formatter.printHelp(parent.name + "-" + name + " <User ID> [OPTIONS...]", options);
+    }
+
+    public void execute(String[] args) throws Exception {
+
+        Option option = new Option(null, "start", true, "Page start");
+        option.setArgName("start");
+        options.addOption(option);
+
+        option = new Option(null, "size", true, "Page size");
+        option.setArgName("size");
+        options.addOption(option);
+
+        CommandLine cmd = null;
+
+        try {
+            cmd = parser.parse(options, args);
+
+        } catch (Exception e) {
+            System.err.println("Error: " + e.getMessage());
+            printHelp();
+            System.exit(1);
+        }
+
+        String[] cmdArgs = cmd.getArgs();
+
+        if (cmdArgs.length != 1) {
+            printHelp();
+            System.exit(1);
+        }
+
+        String userID = cmdArgs[0];
+
+        String s = cmd.getOptionValue("start");
+        Integer start = s == null ? null : Integer.valueOf(s);
+
+        s = cmd.getOptionValue("size");
+        Integer size = s == null ? null : Integer.valueOf(s);
+
+        UserCertCollection response = parent.client.findUserCerts(userID, start, size);
+
+        Collection<UserCertData> entries = response.getCerts();
+
+        MainCLI.printMessage(entries.size() + " user cert(s) matched");
+
+        boolean first = true;
+
+        for (UserCertData userCertData : entries) {
+
+            if (first) {
+                first = false;
+            } else {
+                System.out.println();
+            }
+
+            UserCLI.printCert(userCertData, false, false);
+        }
+
+        MainCLI.printMessage("Number of entries returned " + entries.size());
+    }
+}
diff --git a/base/java-tools/src/com/netscape/cmstools/user/UserCertRemoveCLI.java b/base/java-tools/src/com/netscape/cmstools/user/UserCertRemoveCLI.java
new file mode 100644
index 0000000..503e137
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/user/UserCertRemoveCLI.java
@@ -0,0 +1,65 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2012 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package com.netscape.cmstools.user;
+
+import java.net.URLEncoder;
+
+import com.netscape.cmstools.cli.CLI;
+import com.netscape.cmstools.cli.MainCLI;
+
+
+/**
+ * @author Endi S. Dewata
+ */
+public class UserCertRemoveCLI extends CLI {
+
+    public UserCLI parent;
+
+    public UserCertRemoveCLI(String name, UserCLI parent) {
+        super(name, "Remove user cert");
+        this.parent = parent;
+    }
+
+    public UserCertRemoveCLI(UserCLI parent) {
+        this("cert-del", parent);
+    }
+
+    public void printHelp() {
+        formatter.printHelp(parent.name + "-" + name + " <User ID> <Cert ID>", options);
+    }
+
+    public void execute(String[] args) throws Exception {
+
+        if (args.length != 2) {
+            printHelp();
+            System.exit(1);
+        }
+
+        String userID = args[0];
+        String certID = args[1];
+
+        if (verbose) {
+            System.out.println("Removing cert "+certID+" from user "+userID+".");
+        }
+
+        parent.client.removeUserCert(userID, URLEncoder.encode(certID, "UTF-8"));
+
+        MainCLI.printMessage("Deleted certificate \"" + certID + "\"");
+    }
+}
diff --git a/base/java-tools/src/com/netscape/cmstools/user/UserCertShowCLI.java b/base/java-tools/src/com/netscape/cmstools/user/UserCertShowCLI.java
new file mode 100644
index 0000000..fcf5159
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/user/UserCertShowCLI.java
@@ -0,0 +1,100 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2012 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package com.netscape.cmstools.user;
+
+import java.io.FileWriter;
+import java.io.PrintWriter;
+import java.net.URLEncoder;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+
+import com.netscape.certsrv.user.UserCertData;
+import com.netscape.cmstools.cli.CLI;
+import com.netscape.cmstools.cli.MainCLI;
+
+/**
+ * @author Endi S. Dewata
+ */
+public class UserCertShowCLI extends CLI {
+
+    public UserCLI parent;
+
+    public UserCertShowCLI(String name, UserCLI parent) {
+        super(name, "Show user cert");
+        this.parent = parent;
+    }
+
+    public UserCertShowCLI(UserCLI parent) {
+        this("cert-show", parent);
+    }
+
+    public void printHelp() {
+        formatter.printHelp(parent.name + "-" + name + " <User ID> <Cert ID> [OPTIONS...]", options);
+    }
+
+    public void execute(String[] args) throws Exception {
+
+        Option option = new Option(null, "output", true, "Output file");
+        option.setArgName("file");
+        options.addOption(option);
+
+        options.addOption(null, "pretty", false, "Pretty print");
+        options.addOption(null, "encoded", false, "Base-64 encoded");
+
+        CommandLine cmd = null;
+
+        try {
+            cmd = parser.parse(options, args);
+
+        } catch (Exception e) {
+            System.err.println("Error: " + e.getMessage());
+            printHelp();
+            System.exit(1);
+        }
+
+        boolean showPrettyPrint = cmd.hasOption("pretty");
+        boolean showEncoded = cmd.hasOption("encoded");
+
+        String[] cmdArgs = cmd.getArgs();
+
+        if (cmdArgs.length != 2) {
+            printHelp();
+            System.exit(1);
+        }
+
+        String userID = cmdArgs[0];
+        String certID = cmdArgs[1];
+        String file = cmd.getOptionValue("output");
+
+        UserCertData userCertData = parent.client.getUserCert(userID, URLEncoder.encode(certID, "UTF-8"));
+
+        String encoded = userCertData.getEncoded();
+        if (encoded != null && file != null) {
+            // store cert to file
+            PrintWriter out = new PrintWriter(new FileWriter(file));
+            out.print(encoded);
+            out.close();
+        }
+
+        MainCLI.printMessage("Certificate \"" + userCertData.getID() + "\"");
+
+        UserCLI.printCert(userCertData, showPrettyPrint, showEncoded);
+    }
+}
diff --git a/base/java-tools/src/com/netscape/cmstools/user/UserFindCertCLI.java b/base/java-tools/src/com/netscape/cmstools/user/UserFindCertCLI.java
index 08f6879..baf73c9 100644
--- a/base/java-tools/src/com/netscape/cmstools/user/UserFindCertCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/user/UserFindCertCLI.java
@@ -18,87 +18,14 @@
 
 package com.netscape.cmstools.user;
 
-import java.util.Collection;
-
-import org.apache.commons.cli.CommandLine;
-import org.apache.commons.cli.Option;
-
-import com.netscape.certsrv.user.UserCertCollection;
-import com.netscape.certsrv.user.UserCertData;
-import com.netscape.cmstools.cli.CLI;
-import com.netscape.cmstools.cli.MainCLI;
 
 /**
  * @author Endi S. Dewata
  */
-public class UserFindCertCLI extends CLI {
-
-    public UserCLI parent;
+@Deprecated
+public class UserFindCertCLI extends UserCertFindCLI {
 
     public UserFindCertCLI(UserCLI parent) {
-        super("find-cert", "Find user certs");
-        this.parent = parent;
-    }
-
-    public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <User ID> [OPTIONS...]", options);
-    }
-
-    public void execute(String[] args) throws Exception {
-
-        Option option = new Option(null, "start", true, "Page start");
-        option.setArgName("start");
-        options.addOption(option);
-
-        option = new Option(null, "size", true, "Page size");
-        option.setArgName("size");
-        options.addOption(option);
-
-        CommandLine cmd = null;
-
-        try {
-            cmd = parser.parse(options, args);
-
-        } catch (Exception e) {
-            System.err.println("Error: " + e.getMessage());
-            printHelp();
-            System.exit(1);
-        }
-
-        String[] cmdArgs = cmd.getArgs();
-
-        if (cmdArgs.length != 1) {
-            printHelp();
-            System.exit(1);
-        }
-
-        String userID = cmdArgs[0];
-
-        String s = cmd.getOptionValue("start");
-        Integer start = s == null ? null : Integer.valueOf(s);
-
-        s = cmd.getOptionValue("size");
-        Integer size = s == null ? null : Integer.valueOf(s);
-
-        UserCertCollection response = parent.client.findUserCerts(userID, start, size);
-
-        Collection<UserCertData> entries = response.getCerts();
-
-        MainCLI.printMessage(entries.size() + " user cert(s) matched");
-
-        boolean first = true;
-
-        for (UserCertData userCertData : entries) {
-
-            if (first) {
-                first = false;
-            } else {
-                System.out.println();
-            }
-
-            UserCLI.printCert(userCertData, false, false);
-        }
-
-        MainCLI.printMessage("Number of entries returned " + entries.size());
+        super("find-cert", parent);
     }
 }
diff --git a/base/java-tools/src/com/netscape/cmstools/user/UserFindMembershipCLI.java b/base/java-tools/src/com/netscape/cmstools/user/UserFindMembershipCLI.java
index 494c3c3..24fb9ca 100644
--- a/base/java-tools/src/com/netscape/cmstools/user/UserFindMembershipCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/user/UserFindMembershipCLI.java
@@ -18,87 +18,14 @@
 
 package com.netscape.cmstools.user;
 
-import java.util.Collection;
-
-import org.apache.commons.cli.CommandLine;
-import org.apache.commons.cli.Option;
-
-import com.netscape.certsrv.user.UserMembershipCollection;
-import com.netscape.certsrv.user.UserMembershipData;
-import com.netscape.cmstools.cli.CLI;
-import com.netscape.cmstools.cli.MainCLI;
 
 /**
  * @author Endi S. Dewata
  */
-public class UserFindMembershipCLI extends CLI {
-
-    public UserCLI parent;
+@Deprecated
+public class UserFindMembershipCLI extends UserMembershipFindCLI {
 
     public UserFindMembershipCLI(UserCLI parent) {
-        super("find-membership", "Find user memberships");
-        this.parent = parent;
-    }
-
-    public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <User ID> [OPTIONS...]", options);
-    }
-
-    public void execute(String[] args) throws Exception {
-
-        Option option = new Option(null, "start", true, "Page start");
-        option.setArgName("start");
-        options.addOption(option);
-
-        option = new Option(null, "size", true, "Page size");
-        option.setArgName("size");
-        options.addOption(option);
-
-        CommandLine cmd = null;
-
-        try {
-            cmd = parser.parse(options, args);
-
-        } catch (Exception e) {
-            System.err.println("Error: " + e.getMessage());
-            printHelp();
-            System.exit(1);
-        }
-
-        String[] cmdArgs = cmd.getArgs();
-
-        if (cmdArgs.length != 1) {
-            printHelp();
-            System.exit(1);
-        }
-
-        String userID = cmdArgs[0];
-
-        String s = cmd.getOptionValue("start");
-        Integer start = s == null ? null : Integer.valueOf(s);
-
-        s = cmd.getOptionValue("size");
-        Integer size = s == null ? null : Integer.valueOf(s);
-
-        UserMembershipCollection response = parent.client.findUserMemberships(userID, start, size);
-
-        Collection<UserMembershipData> entries = response.getMemberships();
-
-        MainCLI.printMessage(entries.size()+" membership(s) matched");
-
-        boolean first = true;
-
-        for (UserMembershipData userMembershipData : entries) {
-
-            if (first) {
-                first = false;
-            } else {
-                System.out.println();
-            }
-
-            UserCLI.printUserMembership(userMembershipData);
-        }
-
-        MainCLI.printMessage("Number of entries returned "+entries.size());
+        super("find-membership", parent);
     }
 }
diff --git a/base/java-tools/src/com/netscape/cmstools/user/UserMembershipAddCLI.java b/base/java-tools/src/com/netscape/cmstools/user/UserMembershipAddCLI.java
new file mode 100644
index 0000000..44cb578
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/user/UserMembershipAddCLI.java
@@ -0,0 +1,61 @@
+// --- 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) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package com.netscape.cmstools.user;
+
+import com.netscape.certsrv.user.UserMembershipData;
+import com.netscape.cmstools.cli.CLI;
+import com.netscape.cmstools.cli.MainCLI;
+
+/**
+ * @author Endi S. Dewata
+ */
+public class UserMembershipAddCLI extends CLI {
+
+    public UserCLI parent;
+
+    public UserMembershipAddCLI(String name, UserCLI parent) {
+        super(name, "Add user membership");
+        this.parent = parent;
+    }
+
+    public UserMembershipAddCLI(UserCLI parent) {
+        this("membership-add", parent);
+    }
+
+    public void printHelp() {
+        formatter.printHelp(parent.name + "-" + name + " <User ID> <Group ID>", options);
+    }
+
+    public void execute(String[] args) throws Exception {
+
+        if (args.length != 2) {
+            printHelp();
+            System.exit(1);
+        }
+
+        String userID = args[0];
+        String groupID = args[1];
+
+        UserMembershipData userMembershipData = parent.client.addUserMembership(userID, groupID);
+
+        MainCLI.printMessage("Added membership in \""+groupID+"\"");
+
+        UserCLI.printUserMembership(userMembershipData);
+    }
+}
diff --git a/base/java-tools/src/com/netscape/cmstools/user/UserMembershipFindCLI.java b/base/java-tools/src/com/netscape/cmstools/user/UserMembershipFindCLI.java
new file mode 100644
index 0000000..beca5f4
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/user/UserMembershipFindCLI.java
@@ -0,0 +1,108 @@
+// --- 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) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package com.netscape.cmstools.user;
+
+import java.util.Collection;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+
+import com.netscape.certsrv.user.UserMembershipCollection;
+import com.netscape.certsrv.user.UserMembershipData;
+import com.netscape.cmstools.cli.CLI;
+import com.netscape.cmstools.cli.MainCLI;
+
+/**
+ * @author Endi S. Dewata
+ */
+public class UserMembershipFindCLI extends CLI {
+
+    public UserCLI parent;
+
+    public UserMembershipFindCLI(String name, UserCLI parent) {
+        super(name, "Find user memberships");
+        this.parent = parent;
+    }
+
+    public UserMembershipFindCLI(UserCLI parent) {
+        this("membership-find", parent);
+    }
+
+    public void printHelp() {
+        formatter.printHelp(parent.name + "-" + name + " <User ID> [OPTIONS...]", options);
+    }
+
+    public void execute(String[] args) throws Exception {
+
+        Option option = new Option(null, "start", true, "Page start");
+        option.setArgName("start");
+        options.addOption(option);
+
+        option = new Option(null, "size", true, "Page size");
+        option.setArgName("size");
+        options.addOption(option);
+
+        CommandLine cmd = null;
+
+        try {
+            cmd = parser.parse(options, args);
+
+        } catch (Exception e) {
+            System.err.println("Error: " + e.getMessage());
+            printHelp();
+            System.exit(1);
+        }
+
+        String[] cmdArgs = cmd.getArgs();
+
+        if (cmdArgs.length != 1) {
+            printHelp();
+            System.exit(1);
+        }
+
+        String userID = cmdArgs[0];
+
+        String s = cmd.getOptionValue("start");
+        Integer start = s == null ? null : Integer.valueOf(s);
+
+        s = cmd.getOptionValue("size");
+        Integer size = s == null ? null : Integer.valueOf(s);
+
+        UserMembershipCollection response = parent.client.findUserMemberships(userID, start, size);
+
+        Collection<UserMembershipData> entries = response.getMemberships();
+
+        MainCLI.printMessage(entries.size()+" membership(s) matched");
+
+        boolean first = true;
+
+        for (UserMembershipData userMembershipData : entries) {
+
+            if (first) {
+                first = false;
+            } else {
+                System.out.println();
+            }
+
+            UserCLI.printUserMembership(userMembershipData);
+        }
+
+        MainCLI.printMessage("Number of entries returned "+entries.size());
+    }
+}
diff --git a/base/java-tools/src/com/netscape/cmstools/user/UserMembershipRemoveCLI.java b/base/java-tools/src/com/netscape/cmstools/user/UserMembershipRemoveCLI.java
new file mode 100644
index 0000000..ba43b05
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/user/UserMembershipRemoveCLI.java
@@ -0,0 +1,58 @@
+// --- 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) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package com.netscape.cmstools.user;
+
+import com.netscape.cmstools.cli.CLI;
+import com.netscape.cmstools.cli.MainCLI;
+
+/**
+ * @author Endi S. Dewata
+ */
+public class UserMembershipRemoveCLI extends CLI {
+
+    public UserCLI parent;
+
+    public UserMembershipRemoveCLI(String name, UserCLI parent) {
+        super(name, "Remove user membership");
+        this.parent = parent;
+    }
+
+    public UserMembershipRemoveCLI(UserCLI parent) {
+        this("membership-del", parent);
+    }
+
+    public void printHelp() {
+        formatter.printHelp(parent.name + "-" + name + " <User ID> <Group ID>", options);
+    }
+
+    public void execute(String[] args) throws Exception {
+
+        if (args.length != 2) {
+            printHelp();
+            System.exit(1);
+        }
+
+        String userID = args[0];
+        String groupID = args[1];
+
+        parent.client.removeUserMembership(userID, groupID);
+
+        MainCLI.printMessage("Deleted membership in group \""+groupID+"\"");
+    }
+}
diff --git a/base/java-tools/src/com/netscape/cmstools/user/UserRemoveCertCLI.java b/base/java-tools/src/com/netscape/cmstools/user/UserRemoveCertCLI.java
index 264458b..58fd57e 100644
--- a/base/java-tools/src/com/netscape/cmstools/user/UserRemoveCertCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/user/UserRemoveCertCLI.java
@@ -18,44 +18,15 @@
 
 package com.netscape.cmstools.user;
 
-import java.net.URLEncoder;
-
-import com.netscape.cmstools.cli.CLI;
-import com.netscape.cmstools.cli.MainCLI;
 
 
 /**
  * @author Endi S. Dewata
  */
-public class UserRemoveCertCLI extends CLI {
-
-    public UserCLI parent;
+@Deprecated
+public class UserRemoveCertCLI extends UserCertRemoveCLI {
 
     public UserRemoveCertCLI(UserCLI parent) {
-        super("remove-cert", "Remove user cert");
-        this.parent = parent;
-    }
-
-    public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <User ID> <Cert ID>", options);
-    }
-
-    public void execute(String[] args) throws Exception {
-
-        if (args.length != 2) {
-            printHelp();
-            System.exit(1);
-        }
-
-        String userID = args[0];
-        String certID = args[1];
-
-        if (verbose) {
-            System.out.println("Removing cert "+certID+" from user "+userID+".");
-        }
-
-        parent.client.removeUserCert(userID, URLEncoder.encode(certID, "UTF-8"));
-
-        MainCLI.printMessage("Deleted certificate \"" + certID + "\"");
+        super("remove-cert", parent);
     }
 }
diff --git a/base/java-tools/src/com/netscape/cmstools/user/UserRemoveMembershipCLI.java b/base/java-tools/src/com/netscape/cmstools/user/UserRemoveMembershipCLI.java
index 26a5a6e..4cafcec 100644
--- a/base/java-tools/src/com/netscape/cmstools/user/UserRemoveMembershipCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/user/UserRemoveMembershipCLI.java
@@ -18,37 +18,14 @@
 
 package com.netscape.cmstools.user;
 
-import com.netscape.cmstools.cli.CLI;
-import com.netscape.cmstools.cli.MainCLI;
 
 /**
  * @author Endi S. Dewata
  */
-public class UserRemoveMembershipCLI extends CLI {
-
-    public UserCLI parent;
+@Deprecated
+public class UserRemoveMembershipCLI extends UserMembershipRemoveCLI {
 
     public UserRemoveMembershipCLI(UserCLI parent) {
-        super("remove-membership", "Remove user membership");
-        this.parent = parent;
-    }
-
-    public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <User ID> <Group ID>", options);
-    }
-
-    public void execute(String[] args) throws Exception {
-
-        if (args.length != 2) {
-            printHelp();
-            System.exit(1);
-        }
-
-        String userID = args[0];
-        String groupID = args[1];
-
-        parent.client.removeUserMembership(userID, groupID);
-
-        MainCLI.printMessage("Deleted membership in group \""+groupID+"\"");
+        super("remove-membership", parent);
     }
 }
diff --git a/base/java-tools/src/com/netscape/cmstools/user/UserShowCertCLI.java b/base/java-tools/src/com/netscape/cmstools/user/UserShowCertCLI.java
index f30c723..5177281 100644
--- a/base/java-tools/src/com/netscape/cmstools/user/UserShowCertCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/user/UserShowCertCLI.java
@@ -18,79 +18,14 @@
 
 package com.netscape.cmstools.user;
 
-import java.io.FileWriter;
-import java.io.PrintWriter;
-import java.net.URLEncoder;
-
-import org.apache.commons.cli.CommandLine;
-import org.apache.commons.cli.Option;
-
-import com.netscape.certsrv.user.UserCertData;
-import com.netscape.cmstools.cli.CLI;
-import com.netscape.cmstools.cli.MainCLI;
 
 /**
  * @author Endi S. Dewata
  */
-public class UserShowCertCLI extends CLI {
-
-    public UserCLI parent;
+@Deprecated
+public class UserShowCertCLI extends UserCertShowCLI {
 
     public UserShowCertCLI(UserCLI parent) {
-        super("show-cert", "Show user cert");
-        this.parent = parent;
-    }
-
-    public void printHelp() {
-        formatter.printHelp(parent.name + "-" + name + " <User ID> <Cert ID> [OPTIONS...]", options);
-    }
-
-    public void execute(String[] args) throws Exception {
-
-        Option option = new Option(null, "output", true, "Output file");
-        option.setArgName("file");
-        options.addOption(option);
-
-        options.addOption(null, "pretty", false, "Pretty print");
-        options.addOption(null, "encoded", false, "Base-64 encoded");
-
-        CommandLine cmd = null;
-
-        try {
-            cmd = parser.parse(options, args);
-
-        } catch (Exception e) {
-            System.err.println("Error: " + e.getMessage());
-            printHelp();
-            System.exit(1);
-        }
-
-        boolean showPrettyPrint = cmd.hasOption("pretty");
-        boolean showEncoded = cmd.hasOption("encoded");
-
-        String[] cmdArgs = cmd.getArgs();
-
-        if (cmdArgs.length != 2) {
-            printHelp();
-            System.exit(1);
-        }
-
-        String userID = cmdArgs[0];
-        String certID = cmdArgs[1];
-        String file = cmd.getOptionValue("output");
-
-        UserCertData userCertData = parent.client.getUserCert(userID, URLEncoder.encode(certID, "UTF-8"));
-
-        String encoded = userCertData.getEncoded();
-        if (encoded != null && file != null) {
-            // store cert to file
-            PrintWriter out = new PrintWriter(new FileWriter(file));
-            out.print(encoded);
-            out.close();
-        }
-
-        MainCLI.printMessage("Certificate \"" + userCertData.getID() + "\"");
-
-        UserCLI.printCert(userCertData, showPrettyPrint, showEncoded);
+        super("show-cert", parent);
     }
 }
-- 
1.8.3.1