[Pki-devel] CLI for editing profiles

Fraser Tweedale ftweedal at redhat.com
Wed Jul 23 07:09:24 UTC 2014


On Wed, Jul 23, 2014 at 11:27:11AM +1000, Fraser Tweedale wrote:
> Along with LDAP profiles, we will be adding modules to the CLI for
> adding and editing profiles in the ConfigStore format that was used
> for file-based profiles.  For more info, see:
> 
>   http://pki.fedoraproject.org/wiki/LDAP_Profile_Storage#Command-line_utilities
> 
> There is an existing CLI for adding and modifying profiles, in the
> XML format, e.g. ``pki ca profile add caCustomProfile.xml``.  The
> XML format carries information including the profile ID and
> class_id, but these data must be supplied out-of-band when dealing
> with the ConfigStore format.
> 
> Because of this, I intend to:
> 
> - add new commands to the existing profile CLI for working with the
>   "raw" (i.e., ConfigStore) format, e.g. "edit-raw", "add-raw".
>   Where necessary, these commands will take compulsory
>   ``--profile-id`` and/or ``--class-id`` arguments, to account for
>   the absense of such information in the profile ConfigStore format;
> 
>   and
> 
> - transport this information in the XML format - not in the "raw"
>   format - so that it will be unnecessary to make changes to
>   ProfileClient or the ProfileService API.
> 
> As usual, I welcome feedback - especially if you feel I am going the
> wrong way ^_^
> 

An update: due to the various Profile and ProfileInput/Output/Policy
classes not being distributed in the pki-tools package (or
dependencies thereof), I /did/ end up adding methods to the REST
API.

The `pki ca profile show-raw <profileId>` command is implemented in
the attached patch 0009.  I expected I will complete the edit-raw
and add-raw commands tomorrow, and after that will move on to
testing replication and polling/monitoring for changes to profiles.

Cheers,

Fraser

> _______________________________________________
> Pki-devel mailing list
> Pki-devel at redhat.com
> https://www.redhat.com/mailman/listinfo/pki-devel
-------------- next part --------------
>From 019e82e4987659f1f1e066dff943355a254f2179 Mon Sep 17 00:00:00 2001
From: Fraser Tweedale <ftweedal at redhat.com>
Date: Mon, 7 Jul 2014 23:35:35 -0400
Subject: [PATCH] add schema for LDAP-based profiles

---
 base/ca/shared/conf/db.ldif     |  9 +++++++++
 base/ca/shared/conf/schema.ldif | 30 ++++++++++++++++++++++++++++++
 2 files changed, 39 insertions(+)

diff --git a/base/ca/shared/conf/db.ldif b/base/ca/shared/conf/db.ldif
index 00fa919b7df38ed97f0bc21b5616a9998845c7d4..b0f36b6d85f70900d0b2c5e0ee92d9fb8c1cb3e8 100644
--- a/base/ca/shared/conf/db.ldif
+++ b/base/ca/shared/conf/db.ldif
@@ -160,4 +160,13 @@ objectClass: top
 objectClass: organizationalUnit
 ou: certificateRepository
 
+dn: ou=certProfiles,{rootSuffix}
+objectClass: top
+objectClass: organizationalUnit
+ou: certProfiles
 
+dn: cn=certProfilesInfo,{rootSuffix}
+objectClass: top
+objectClass: certProfilesInfo
+cn: certProfilesInfo
+certProfilesLastModified: 197001010000Z
diff --git a/base/ca/shared/conf/schema.ldif b/base/ca/shared/conf/schema.ldif
index 70578e21ce4e102909a1b7b45fa84c184a997bdf..4f74869da1e46b39469dd17ddb2517e111300b43 100644
--- a/base/ca/shared/conf/schema.ldif
+++ b/base/ca/shared/conf/schema.ldif
@@ -487,3 +487,33 @@ dn: cn=schema
 changetype: modify
 add: objectClasses
 objectClasses: ( securityDomainSessionEntry-oid NAME 'securityDomainSessionEntry' DESC 'CMS defined class' SUP top STRUCTURAL MUST ( cn $ host $ uid $ cmsUserGroup $ dateOfCreate ) X-ORIGIN 'user defined' ) 
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( classId-oid NAME 'classId' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( certProfileIsDefault-oid NAME 'certProfileIsDefault' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( certProfileConfig-oid NAME 'certProfileConfig' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: objectClasses
+objectClasses: ( certProfile-oid NAME 'certProfile' DESC 'CMS defined class' SUP top STRUCTURAL MUST cn MAY ( classId $ certProfileIsDefault $ certProfileConfig ) X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: attributeTypes
+attributeTypes: ( certProfilesLastModified-oid NAME 'certProfilesLastModified' DESC 'CMS defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 X-ORIGIN 'user defined' )
+
+dn: cn=schema
+changetype: modify
+add: objectClasses
+objectClasses: ( certProfilesInfo-oid NAME 'certProfilesInfo' DESC 'CMS defined class' SUP top STRUCTURAL MUST cn MAY certProfilesLastModified X-ORIGIN 'user defined' )
-- 
1.9.3

-------------- next part --------------
>From 732286e87aadc1bca90232b4af8c29106cbb27eb Mon Sep 17 00:00:00 2001
From: Fraser Tweedale <frase at frase.id.au>
Date: Tue, 15 Jul 2014 02:48:35 -0400
Subject: [PATCH] add LDAPConfigStore class

The LDAPConfigStore class is an IConfigStore that reads and writes
its configuration to a given attribute and DN in an LDAP database.
---
 .../com/netscape/cmscore/base/LDAPConfigStore.java | 190 +++++++++++++++++++++
 1 file changed, 190 insertions(+)
 create mode 100644 base/server/cmscore/src/com/netscape/cmscore/base/LDAPConfigStore.java

diff --git a/base/server/cmscore/src/com/netscape/cmscore/base/LDAPConfigStore.java b/base/server/cmscore/src/com/netscape/cmscore/base/LDAPConfigStore.java
new file mode 100644
index 0000000000000000000000000000000000000000..8ff477bb3cdad02092c56834e043bcd6e0108625
--- /dev/null
+++ b/base/server/cmscore/src/com/netscape/cmscore/base/LDAPConfigStore.java
@@ -0,0 +1,190 @@
+// --- 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, 2014 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package com.netscape.cmscore.base;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+import netscape.ldap.LDAPAttribute;
+import netscape.ldap.LDAPAttributeSet;
+import netscape.ldap.LDAPConnection;
+import netscape.ldap.LDAPEntry;
+import netscape.ldap.LDAPException;
+import netscape.ldap.LDAPModification;
+
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.IConfigStore;
+import com.netscape.certsrv.ldap.ILdapConnFactory;
+
+/**
+ * LDAPConfigStore:
+ * Extends PropConfigStore with methods to load/save from/to file for
+ * persistent storage. This is a configuration store agent who
+ * reads data from an LDAP entry.
+ * <P>
+ *
+ * @version $Revision$, $Date$
+ * @see PropConfigStore
+ */
+public class LDAPConfigStore extends PropConfigStore implements IConfigStore {
+
+    private ILdapConnFactory mDbFactory;
+    private String mDn;
+    private String mAttr;
+    private LDAPAttribute[] mAttrs;
+    private boolean mInDatabase;
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 3642124526598175633L;
+
+    /**
+     * Constructs a file configuration store.
+     * <P>
+     *
+     * @param dbFactory Database connection factory
+     * @param cn Common name of record containing config store
+     * @param dn Distinguished name of record containing config store
+     * @param attr Name of attribute containing config store
+     * @param attrs Set of initial attributes if creating the entry.  Should
+     *              contain cn, objectclass and possibly other attributes.
+     *
+     * @exception EBaseException failed to create file configuration
+     */
+    public LDAPConfigStore(
+        ILdapConnFactory dbFactory,
+        String dn, LDAPAttribute[] attrs, String attr
+    ) throws EBaseException {
+        super(null);  // top-level store without a name
+
+        mDbFactory = dbFactory;
+        mDn = dn;
+        mAttrs = attrs;
+        mAttr = attr;
+
+        LDAPConnection conn = mDbFactory.getConn();
+
+        String[] readAttrs = {mAttr};
+        try {
+            LDAPEntry ldapEntry = conn.read(mDn, readAttrs);
+
+            InputStream data = new ByteArrayInputStream( (byte[])
+                ldapEntry.getAttribute(mAttr).getByteValues().nextElement());
+            load(data);
+        }
+        catch (LDAPException e) {
+            // if there is no such object, we will create it on commit()
+            if (e.getLDAPResultCode() != LDAPException.NO_SUCH_OBJECT) {
+                throw new EBaseException(
+                    "Error reading LDAPConfigStore '"
+                    + mDn + "': " + e.toString()
+                );
+            }
+        }
+        catch (IOException e) {
+            throw new EBaseException(
+                "Error reading LDAPConfigStore '"
+                + mDn + "': " + e.toString()
+            );
+        }
+        finally {
+            mDbFactory.returnConn(conn);
+        }
+    }
+
+    /**
+     * Commit the configuration to the database.
+     *
+     * All uses of LDAPProfileStore at time of writing call with
+     * backup=false, so the argument is ignored.
+     *
+     * If backup becomes necessary, the constructor should be
+     * modified to take a String backupAttr, and the existing
+     * content be copied to that attribute.
+     *
+     * @param backup Ignored.
+     */
+    public void commit(boolean createBackup) throws EBaseException {
+        ByteArrayOutputStream data = new ByteArrayOutputStream();
+        save(data, null);
+
+        LDAPAttribute configAttr = new LDAPAttribute(mAttr, data.toByteArray());
+
+        LDAPConnection conn = mDbFactory.getConn();
+
+        // first attempt to modify; if modification fails (due
+        // to no such object), try and add the entry instead.
+        try {
+            try {
+                commitModify(conn, configAttr);
+            }
+            catch (LDAPException e) {
+                if (e.getLDAPResultCode() == LDAPException.NO_SUCH_OBJECT) {
+                    commitAdd(conn, configAttr);
+                }
+                else {
+                    throw e;
+                }
+            }
+        }
+        catch (LDAPException e) {
+            throw new EBaseException(
+                "Error writing LDAPConfigStore '"
+                + mDn + "': " + e.toString()
+            );
+        }
+        finally {
+            mDbFactory.returnConn(conn);
+        }
+    }
+
+    /**
+     * Update the record via an LDAPModification.
+     *
+     * @param conn LDAP connection.
+     * @param configAttr Config store attribute.
+     * @return true on success, false if the entry does not exist.
+     */
+    private void commitModify(LDAPConnection conn, LDAPAttribute configAttr)
+        throws LDAPException
+    {
+        LDAPModification ldapMod =
+            new LDAPModification(LDAPModification.REPLACE, configAttr);
+        conn.modify(mDn, ldapMod);
+    }
+
+    /**
+     * Add the LDAPEntry via LDAPConnection.add.
+     *
+     * @param conn LDAP connection.
+     * @param configAttr Config store attribute.
+     * @return true on success, false if the entry already exists.
+     */
+    private void commitAdd(LDAPConnection conn, LDAPAttribute configAttr)
+        throws LDAPException
+    {
+        LDAPAttributeSet attrSet = new LDAPAttributeSet(mAttrs);
+        attrSet.add(configAttr);
+        LDAPEntry ldapEntry = new LDAPEntry(mDn, attrSet);
+        conn.add(ldapEntry);
+    }
+}
-- 
1.9.3

-------------- next part --------------
>From 392f22cd77497434e6db9af73399b4593124fdb1 Mon Sep 17 00:00:00 2001
From: Fraser Tweedale <frase at frase.id.au>
Date: Thu, 17 Jul 2014 00:24:06 -0400
Subject: [PATCH] change ProfileSubsystem to use LDAP database

---
 .../dogtagpki/server/ca/rest/ProfileService.java   |  14 +-
 base/server/cmsbundle/src/UserMessages.properties  |   2 +
 .../com/netscape/cmscore/base/FileConfigStore.java |   4 +-
 .../netscape/cmscore/profile/ProfileSubsystem.java | 175 ++++++++++++---------
 4 files changed, 108 insertions(+), 87 deletions(-)

diff --git a/base/ca/src/org/dogtagpki/server/ca/rest/ProfileService.java b/base/ca/src/org/dogtagpki/server/ca/rest/ProfileService.java
index 3b2f8a50ebcd18fe0098b2e92e0300645b904fa3..cf0d4db7f8bed44baf6d2abbf70a61406ddb4b7c 100644
--- a/base/ca/src/org/dogtagpki/server/ca/rest/ProfileService.java
+++ b/base/ca/src/org/dogtagpki/server/ca/rest/ProfileService.java
@@ -18,7 +18,6 @@
 
 package org.dogtagpki.server.ca.rest;
 
-import java.io.File;
 import java.io.IOException;
 import java.net.URI;
 import java.security.Principal;
@@ -244,7 +243,7 @@ public class ProfileService extends PKIService implements ProfileResource {
 
         data.setAuthenticatorId(profile.getAuthenticatorId());
         data.setAuthzAcl(profile.getAuthzAcl());
-        data.setClassId(cs.getString(profileId + ".class_id"));
+        data.setClassId(ps.getProfileClassId(profileId));
         data.setDescription(profile.getDescription(getLocale(headers)));
         data.setEnabled(ps.isProfileEnable(profileId));
         data.setEnabledBy(ps.getProfileEnableBy(profileId));
@@ -472,18 +471,15 @@ public class ProfileService extends PKIService implements ProfileResource {
             auditParams.put("description", data.getDescription());
             auditParams.put("visible", Boolean.toString(data.isVisible()));
 
-            String config = CMS.getConfigStore().getString("instanceRoot") + "/ca/profiles/ca/" +
-                    profileId + ".cfg";
-            File configFile = new File(config);
-            configFile.createNewFile();
             IPluginInfo info = registry.getPluginInfo("profile", data.getClassId());
 
-            profile = ps.createProfile(profileId, data.getClassId(), info.getClassName(), config);
+            String dn = "cn=" + profileId + ",ou=certProfiles,"
+                + CMS.getConfigStore().getString("internaldb.basedn");
+            profile = ps.createProfile(profileId, data.getClassId(), info.getClassName(), dn);
             profile.setName(getLocale(headers), data.getName());
             profile.setDescription(getLocale(headers), data.getDescription());
             profile.setVisible(data.isVisible());
             profile.getConfigStore().commit(false);
-            ps.createProfileConfig(profileId, data.getClassId(), config);
 
             if (profile instanceof IProfileEx) {
                 // populates profile specific plugins such as
@@ -504,7 +500,7 @@ public class ProfileService extends PKIService implements ProfileResource {
 
             return createCreatedResponse(profileData, profileData.getLink().getHref());
 
-        } catch (EBaseException | IOException e) {
+        } catch (EBaseException e) {
             CMS.debug("createProfile: error in creating profile: " + e);
             e.printStackTrace();
 
diff --git a/base/server/cmsbundle/src/UserMessages.properties b/base/server/cmsbundle/src/UserMessages.properties
index fe43094e6b2a0531502570bc626da557fc9061ae..cd7fa18bfb1e17bc4ab4aa9e0dac06f815861291 100644
--- a/base/server/cmsbundle/src/UserMessages.properties
+++ b/base/server/cmsbundle/src/UserMessages.properties
@@ -754,6 +754,8 @@ CMS_PROFILE_CONFIG_KEY_USAGE_EXTENSION_CHECKING=Allow duplicate subject names wi
 CMS_PROFILE_INTERNAL_ERROR=Profile internal error: {0}
 CMS_PROFILE_DENY_OPERATION=Not authorized to do this operation.
 CMS_PROFILE_DELETE_ENABLEPROFILE=Cannot delete enabled profile: {0}
+CMS_PROFILE_DELETE_UNKNOWNPROFILE=Cannot delete unknown profile: {0}
+CMS_PROFILE_DELETE_DATABASEERROR=Failed to delete profile: {0}
 CMS_PROFILE_INVALID_REQUEST=Invalid Request
 CMS_PROFILE_EMPTY_REQUEST_TYPE=Request type is not specified. Check your profile input.
 CMS_PROFILE_CREATE_POLICY_FAILED=Failed to create profile policy: {0}
diff --git a/base/server/cmscore/src/com/netscape/cmscore/base/FileConfigStore.java b/base/server/cmscore/src/com/netscape/cmscore/base/FileConfigStore.java
index b77f86d781995e27bb0fe16135fc45a7d6fc4da3..4f8cb2743fdecc354338042a5219a9aaf6e27880 100644
--- a/base/server/cmscore/src/com/netscape/cmscore/base/FileConfigStore.java
+++ b/base/server/cmscore/src/com/netscape/cmscore/base/FileConfigStore.java
@@ -33,12 +33,10 @@ import com.netscape.cmsutil.util.Utils;
 
 /**
  * FileConfigStore:
- * Extends HashConfigStore with methods to load/save from/to file for
+ * Extends PropConfigStore with methods to load/save from/to file for
  * persistent storage. This is a configuration store agent who
  * reads data from a file.
  * <P>
- * Note that a LdapConfigStore can be implemented so that it reads the configuration stores from the Ldap directory.
- * <P>
  *
  * @version $Revision$, $Date$
  * @see PropConfigStore
diff --git a/base/server/cmscore/src/com/netscape/cmscore/profile/ProfileSubsystem.java b/base/server/cmscore/src/com/netscape/cmscore/profile/ProfileSubsystem.java
index 27e72352ef22c742b5ea09a180d440d58452dd49..aaa3b29b46ae4579a59cee9f5f7bab750a40a057 100644
--- a/base/server/cmscore/src/com/netscape/cmscore/profile/ProfileSubsystem.java
+++ b/base/server/cmscore/src/com/netscape/cmscore/profile/ProfileSubsystem.java
@@ -17,26 +17,30 @@
 // --- END COPYRIGHT BLOCK ---
 package com.netscape.cmscore.profile;
 
-import java.io.File;
 import java.util.Enumeration;
 import java.util.Hashtable;
-import java.util.StringTokenizer;
 import java.util.Vector;
 
+import netscape.ldap.LDAPAttribute;
+import netscape.ldap.LDAPConnection;
+import netscape.ldap.LDAPEntry;
+import netscape.ldap.LDAPException;
+import netscape.ldap.LDAPSearchResults;
+
 import com.netscape.certsrv.apps.CMS;
 import com.netscape.certsrv.base.EBaseException;
 import com.netscape.certsrv.base.IConfigStore;
 import com.netscape.certsrv.base.ISubsystem;
+import com.netscape.certsrv.ldap.ELdapException;
+import com.netscape.certsrv.ldap.ILdapConnFactory;
 import com.netscape.certsrv.profile.EProfileException;
 import com.netscape.certsrv.profile.IProfile;
 import com.netscape.certsrv.profile.IProfileSubsystem;
 import com.netscape.certsrv.registry.IPluginInfo;
 import com.netscape.certsrv.registry.IPluginRegistry;
+import com.netscape.cmscore.base.LDAPConfigStore;
 
 public class ProfileSubsystem implements IProfileSubsystem {
-    private static final String PROP_LIST = "list";
-    private static final String PROP_CLASS_ID = "class_id";
-    private static final String PROP_CONFIG = "config";
     private static final String PROP_CHECK_OWNER = "checkOwner";
 
     private static final String PROP_ENABLE = "enable";
@@ -45,9 +49,12 @@ public class ProfileSubsystem implements IProfileSubsystem {
     private IConfigStore mConfig = null;
     @SuppressWarnings("unused")
     private ISubsystem mOwner;
-    private Vector<String> mProfileIds = new Vector<String>();
-    private Hashtable<String, IProfile> mProfiles = new Hashtable<String, IProfile>();
-    private Hashtable<String, String> mProfileClassIds = new Hashtable<String, String>();
+    private Vector<String> mProfileIds;
+    private Hashtable<String, IProfile> mProfiles;
+    private Hashtable<String, String> mProfileClassIds;
+    private Hashtable<String, String> mProfileDNs;
+
+    private ILdapConnFactory dbFactory;
 
     /**
      * Retrieves the name of this subsystem.
@@ -74,9 +81,21 @@ public class ProfileSubsystem implements IProfileSubsystem {
     public void init(ISubsystem owner, IConfigStore config)
             throws EBaseException {
         CMS.debug("ProfileSubsystem: start init");
+
+        // (re)init member collections
+        mProfileIds = new Vector<String>();
+        mProfiles = new Hashtable<String, IProfile>();
+        mProfileClassIds = new Hashtable<String, String>();
+        mProfileDNs = new Hashtable<String, String>();
+
         IPluginRegistry registry = (IPluginRegistry)
                 CMS.getSubsystem(CMS.SUBSYSTEM_REGISTRY);
 
+        IConfigStore cs = CMS.getConfigStore();
+        IConfigStore dbCfg = cs.getSubStore("internaldb");
+        dbFactory = CMS.getLdapBoundConnFactory();
+        dbFactory.init(dbCfg);
+
         mConfig = config;
         mOwner = owner;
 
@@ -88,24 +107,45 @@ public class ProfileSubsystem implements IProfileSubsystem {
         // *.profile2.config=config/profiles/profile2.cfg
 
         // read profile id, implementation, and its configuration files
-        String ids = config.getString(PROP_LIST, "");
-        StringTokenizer st = new StringTokenizer(ids, ",");
-
-        while (st.hasMoreTokens()) {
-            String id = st.nextToken();
-            IConfigStore subStore = config.getSubStore(id);
-            String classid = subStore.getString(PROP_CLASS_ID);
-            IPluginInfo info = registry.getPluginInfo("profile", classid);
-            if (info == null) {
-                throw new EBaseException("No plugins for type : profile, with id " + classid);
-            }
-            String configPath = subStore.getString(PROP_CONFIG);
+        String basedn = cs.getString("internaldb.basedn");
+        String dn = "ou=certProfiles," + basedn;
+        LDAPConnection conn = dbFactory.getConn();
+
+        String[] attrs = {"cn", "classId"};
+        try {
+            LDAPSearchResults ldapProfiles = conn.search(
+                dn, LDAPConnection.SCOPE_ONE, "(objectclass=*)", attrs, false);
+
+            while (ldapProfiles.hasMoreElements()) {
+                LDAPEntry ldapProfile = ldapProfiles.next();
+
+                String id = (String)
+                    ldapProfile.getAttribute("cn").getStringValues().nextElement();
+
+                String classid = (String)
+                    ldapProfile.getAttribute("classId").getStringValues().nextElement();
 
-            CMS.debug("Start Profile Creation - " + id + " " + classid + " " + info.getClassName());
-            createProfile(id, classid, info.getClassName(),
-                    configPath);
+                IPluginInfo info = registry.getPluginInfo("profile", classid);
+                if (info == null) {
+                    throw new EBaseException("No plugins for type : profile, with id " + classid);
+                }
 
-            CMS.debug("Done Profile Creation - " + id);
+                CMS.debug("Start Profile Creation - " + id + " " + classid + " " + info.getClassName());
+
+                createProfile(id, classid, info.getClassName(), ldapProfile.getDN());
+
+                CMS.debug("Done Profile Creation - " + id);
+            }
+        }
+        catch (LDAPException e) {
+            throw new EBaseException("Error reading profiles: " + e.toString());
+        }
+        finally {
+            try {
+                dbFactory.returnConn(conn);
+            } catch (Exception e) {
+                throw new EProfileException("Error releasing the ldap connection" + e.toString());
+            }
         }
 
         Enumeration<String> ee = getProfileIds();
@@ -121,20 +161,27 @@ public class ProfileSubsystem implements IProfileSubsystem {
      * Creates a profile instance.
      */
     public IProfile createProfile(String id, String classid, String className,
-            String configPath)
+            String dn)
             throws EProfileException {
-        IProfile profile = null;
-
         try {
-            profile = (IProfile) Class.forName(className).newInstance();
-            IConfigStore subStoreConfig = CMS.createFileConfigStore(configPath);
+            String[] objectClasses = {"top", "certProfile"};
+            LDAPAttribute[] createAttrs = {
+                new LDAPAttribute("objectclass", objectClasses),
+                new LDAPAttribute("cn", id),
+                new LDAPAttribute("classId", classid)
+            };
+
+            IConfigStore subStoreConfig = new LDAPConfigStore(
+                dbFactory, dn, createAttrs, "certProfileConfig");
 
             CMS.debug("ProfileSubsystem: initing " + className);
+            IProfile profile = (IProfile) Class.forName(className).newInstance();
             profile.setId(id);
             profile.init(this, subStoreConfig);
             mProfileIds.addElement(id);
             mProfiles.put(id, profile);
             mProfileClassIds.put(id, classid);
+            mProfileDNs.put(id, dn);
             return profile;
         } catch (Exception e) {
             // throw exceptions
@@ -145,62 +192,46 @@ public class ProfileSubsystem implements IProfileSubsystem {
     }
 
     public void deleteProfile(String id, String configPath) throws EProfileException {
-
         if (isProfileEnable(id)) {
             throw new EProfileException("CMS_PROFILE_DELETE_ENABLEPROFILE");
         }
 
-        String ids = "";
-        try {
-            ids = mConfig.getString(PROP_LIST, "");
-        } catch (Exception e) {
+        String dn = mProfileDNs.get(id);
+        if (dn == null) {
+            throw new EProfileException("CMS_PROFILE_DELETE_UNKNOWNPROFILE");
         }
 
-        StringTokenizer tokenizer = new StringTokenizer(ids, ",");
-        StringBuffer list = new StringBuffer();
-
-        while (tokenizer.hasMoreTokens()) {
-            String element = tokenizer.nextToken();
-
-            if (!element.equals(id)) {
-                list.append(element + ",");
+        LDAPConnection conn;
+        try {
+            conn = dbFactory.getConn();
+        }
+        catch (ELdapException e) {
+            throw new EProfileException("Error acquiring the ldap connection" + e.toString());
+        }
+        try {
+            conn.delete(dn);
+        }
+        catch (LDAPException e) {
+            throw new EProfileException("CMS_PROFILE_DELETE_DATABASEERROR");
+        }
+        finally {
+            try {
+                dbFactory.returnConn(conn);
+            } catch (Exception e) {
+                throw new EProfileException("Error releasing the ldap connection" + e.toString());
             }
         }
-        if (list.length() != 0)
-            list.deleteCharAt(list.length() - 1);
 
-        mConfig.putString(PROP_LIST, list.toString());
-        mConfig.removeSubStore(id);
-        File file1 = new File(configPath);
-
-        if (!file1.delete()) {
-            CMS.debug("ProfileSubsystem: deleteProfile: Cannot delete the configuration file : " + configPath);
-        }
         mProfileIds.removeElement(id);
         mProfiles.remove(id);
         mProfileClassIds.remove(id);
-        try {
-            CMS.getConfigStore().commit(false);
-        } catch (Exception e) {
-        }
+        mProfileDNs.remove(id);
     }
 
     public void createProfileConfig(String id, String classId,
             String configPath)
             throws EProfileException {
-        try {
-            if (mProfiles.size() > 0) {
-                mConfig.putString(PROP_LIST,
-                        mConfig.getString(PROP_LIST) + "," + id);
-            } else {
-                mConfig.putString(PROP_LIST, id);
-            }
-            mConfig.putString(id + "." + PROP_CLASS_ID, classId);
-            mConfig.putString(id + "." + PROP_CONFIG, configPath);
-            CMS.getConfigStore().commit(true);
-        } catch (EBaseException e) {
-            CMS.debug(e.toString());
-        }
+        // nothing to do
     }
 
     /**
@@ -219,6 +250,7 @@ public class ProfileSubsystem implements IProfileSubsystem {
         mProfileIds.clear();
         mProfiles.clear();
         mProfileClassIds.clear();
+        mProfileDNs.clear();
     }
 
     /**
@@ -231,13 +263,6 @@ public class ProfileSubsystem implements IProfileSubsystem {
         return mConfig;
     }
 
-    /**
-     * Adds a profile.
-     */
-    public void addProfile(String id, IProfile profile)
-            throws EProfileException {
-    }
-
     public boolean isProfileEnable(String id) {
         IProfile profile = mProfiles.get(id);
         String enable = null;
-- 
1.9.3

-------------- next part --------------
>From 4813bf7d9052bbf6d1d68771f05329891c1acbc4 Mon Sep 17 00:00:00 2001
From: Fraser Tweedale <frase at frase.id.au>
Date: Tue, 22 Jul 2014 00:03:47 -0400
Subject: [PATCH] add configuration to disable a dynamic subsystem

Add the ability to disable a dynamic subsystem by configuring it
with `enabled=false' in CS.cfg.  Subsystems are enabled by default.

This will be used during `pkispawn' to disable the ProfileSubsystem
until the database configuration is established.
---
 .../src/com/netscape/cmscore/apps/CMSEngine.java   | 36 +++++++++++++---------
 1 file changed, 21 insertions(+), 15 deletions(-)

diff --git a/base/server/cmscore/src/com/netscape/cmscore/apps/CMSEngine.java b/base/server/cmscore/src/com/netscape/cmscore/apps/CMSEngine.java
index 68c64824e37bcad282a5bbeabf6b943fabf39481..b6e92bfbdd372d3980c584ba8c9571a4ec52ec8d 100644
--- a/base/server/cmscore/src/com/netscape/cmscore/apps/CMSEngine.java
+++ b/base/server/cmscore/src/com/netscape/cmscore/apps/CMSEngine.java
@@ -208,25 +208,25 @@ public class CMSEngine implements ICMSEngine {
     // static subsystems - must be singletons
     private static SubsystemInfo[] mStaticSubsystems = {
             new SubsystemInfo(
-                    Debug.ID, Debug.getInstance()),
+                    Debug.ID, Debug.getInstance(), true),
             new SubsystemInfo(LogSubsystem.ID,
-                    LogSubsystem.getInstance()),
+                    LogSubsystem.getInstance(), true),
             new SubsystemInfo(
-                    JssSubsystem.ID, JssSubsystem.getInstance()),
+                    JssSubsystem.ID, JssSubsystem.getInstance(), true),
             new SubsystemInfo(
-                    DBSubsystem.ID, DBSubsystem.getInstance()),
+                    DBSubsystem.ID, DBSubsystem.getInstance(), true),
             new SubsystemInfo(
-                    UGSubsystem.ID, UGSubsystem.getInstance()),
+                    UGSubsystem.ID, UGSubsystem.getInstance(), true),
             new SubsystemInfo(
-                    PluginRegistry.ID, new PluginRegistry()),
+                    PluginRegistry.ID, new PluginRegistry(), true),
             new SubsystemInfo(
-                    OidLoaderSubsystem.ID, OidLoaderSubsystem.getInstance()),
+                    OidLoaderSubsystem.ID, OidLoaderSubsystem.getInstance(), true),
             new SubsystemInfo(
-                    X500NameSubsystem.ID, X500NameSubsystem.getInstance()),
+                    X500NameSubsystem.ID, X500NameSubsystem.getInstance(), true),
             // skip TP subsystem;
             // problem in needing dbsubsystem in constructor. and it's not used.
             new SubsystemInfo(
-                    RequestSubsystem.ID, RequestSubsystem.getInstance()),
+                    RequestSubsystem.ID, RequestSubsystem.getInstance(), true),
         };
 
     // dynamic subsystems are loaded at init time, not neccessarily singletons.
@@ -235,11 +235,11 @@ public class CMSEngine implements ICMSEngine {
     // final static subsystems - must be singletons.
     private static SubsystemInfo[] mFinalSubsystems = {
             new SubsystemInfo(
-                    AuthSubsystem.ID, AuthSubsystem.getInstance()),
+                    AuthSubsystem.ID, AuthSubsystem.getInstance(), true),
             new SubsystemInfo(
-                    AuthzSubsystem.ID, AuthzSubsystem.getInstance()),
+                    AuthzSubsystem.ID, AuthzSubsystem.getInstance(), true),
             new SubsystemInfo(
-                    JobsScheduler.ID, JobsScheduler.getInstance()),
+                    JobsScheduler.ID, JobsScheduler.getInstance(), true),
         };
 
     private static final int IP = 0;
@@ -892,6 +892,7 @@ public class CMSEngine implements ICMSEngine {
                     ssconfig.getSubStore(String.valueOf(i));
             String id = config.getString(PROP_ID);
             String classname = config.getString(PROP_CLASS);
+            boolean enabled = config.getBoolean("enabled", true);
             ISubsystem ss = null;
 
             try {
@@ -906,7 +907,7 @@ public class CMSEngine implements ICMSEngine {
                 throw new EBaseException(
                         CMS.getUserMessage("CMS_BASE_LOAD_FAILED_1", id, e.toString()));
             }
-            mDynSubsystems[i] = new SubsystemInfo(id, ss);
+            mDynSubsystems[i] = new SubsystemInfo(id, ss, enabled);
             Debug.trace("loaded dyn subsystem " + id);
         }
     }
@@ -928,6 +929,10 @@ public class CMSEngine implements ICMSEngine {
         IConfigStore ssConfig = mConfig.getSubStore(id);
 
         CMS.debug("CMSEngine: initSubsystem id=" + id);
+        if (!ssinfo.mEnabled) {
+            CMS.debug("CMSEngine: subsystem disabled id=" + id);
+            return;
+        }
         if (doSetId)
             ss.setId(id);
         CMS.debug("CMSEngine: ready to init id=" + id);
@@ -2000,10 +2005,11 @@ class WarningListener implements ILogEventListener {
 class SubsystemInfo {
     public final String mId;
     public final ISubsystem mInstance;
+    public final boolean mEnabled;
 
-    public SubsystemInfo(String id, ISubsystem ssInstance) {
+    public SubsystemInfo(String id, ISubsystem ssInstance, boolean enabled) {
         mId = id;
         mInstance = ssInstance;
+        mEnabled = enabled;
     }
-
 }
-- 
1.9.3

-------------- next part --------------
>From fe1c42feb64fdc21b185e2aa62c58c2908b5fd2d Mon Sep 17 00:00:00 2001
From: Fraser Tweedale <frase at frase.id.au>
Date: Fri, 18 Jul 2014 02:01:58 -0400
Subject: [PATCH] import profiles when spawning CA instance

---
 base/ca/shared/conf/CS.cfg.in                      |   1 +
 .../server/ca/rest/CAInstallerService.java         | 118 +++++++++++++++++++++
 2 files changed, 119 insertions(+)

diff --git a/base/ca/shared/conf/CS.cfg.in b/base/ca/shared/conf/CS.cfg.in
index 4ab8974e6340d81d23bb7f5ea05a07b0936b6463..13ed9c4b9f43f8e76c6f5faffbc78c4a61ccf718 100644
--- a/base/ca/shared/conf/CS.cfg.in
+++ b/base/ca/shared/conf/CS.cfg.in
@@ -1139,6 +1139,7 @@ subsystem.0.class=com.netscape.ca.CertificateAuthority
 subsystem.0.id=ca
 subsystem.1.class=com.netscape.cmscore.profile.ProfileSubsystem
 subsystem.1.id=profile
+subsystem.1.enabled=false
 subsystem.2.class=com.netscape.cmscore.selftests.SelfTestSubsystem
 subsystem.2.id=selftests
 subsystem.3.class=com.netscape.cmscore.cert.CrossCertPairSubsystem
diff --git a/base/ca/src/org/dogtagpki/server/ca/rest/CAInstallerService.java b/base/ca/src/org/dogtagpki/server/ca/rest/CAInstallerService.java
index bb823eece4729599b6badd9ca0e24ef560b9f279..431a0c548818c1810051d47a6484520dccd8e142 100644
--- a/base/ca/src/org/dogtagpki/server/ca/rest/CAInstallerService.java
+++ b/base/ca/src/org/dogtagpki/server/ca/rest/CAInstallerService.java
@@ -17,13 +17,27 @@
 // --- END COPYRIGHT BLOCK ---
 package org.dogtagpki.server.ca.rest;
 
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.StringTokenizer;
+
+import netscape.ldap.LDAPAttribute;
+
 import org.dogtagpki.server.rest.SystemConfigService;
 
 import com.netscape.certsrv.apps.CMS;
 import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.IConfigStore;
 import com.netscape.certsrv.base.PKIException;
+import com.netscape.certsrv.ldap.ELdapException;
+import com.netscape.certsrv.ldap.ILdapConnFactory;
+import com.netscape.certsrv.registry.IPluginInfo;
+import com.netscape.certsrv.registry.IPluginRegistry;
 import com.netscape.certsrv.system.ConfigurationRequest;
 import com.netscape.cms.servlet.csadmin.ConfigurationUtils;
+import com.netscape.cmscore.base.LDAPConfigStore;
+
 
 /**
  * @author alee
@@ -64,5 +78,109 @@ public class CAInstallerService extends SystemConfigService {
             CMS.debug(e);
             throw new PKIException("Errors in determining if security domain host is a master CA");
         }
+
+        try {
+            cs.remove("subsystem.1.enabled");
+        } catch (Exception e) {
+            CMS.debug(e);
+            throw new PKIException("Error enabling ProfileSubsystem");
+        }
+    }
+
+    @Override
+    public void initializeDatabase(ConfigurationRequest data) {
+        super.initializeDatabase(data);
+
+        if (!data.isClone()) {
+            try {
+                importProfiles("/usr/share/pki");
+            } catch (Exception e) {
+                throw new PKIException("Error importing profiles.");
+            }
+        }
+    }
+
+    /**
+     * Import profiles from the filesystem into the database.
+     *
+     * @param configRoot Where to look for the profile files.  For a
+     *                   fresh installation this should be
+     *                   "/usr/share/pki".  For existing installations it
+     *                   should be CMS.getConfigStore().getString("instanceRoot").
+     *
+     */
+    public static void importProfiles(String configRoot)
+            throws EBaseException, ELdapException {
+        IPluginRegistry registry = (IPluginRegistry)
+            CMS.getSubsystem(CMS.SUBSYSTEM_REGISTRY);
+        IConfigStore cfg = CMS.getConfigStore();
+        IConfigStore profileCfg = cfg.getSubStore("profile");
+        String profileIds = profileCfg.getString("list", "");
+        StringTokenizer st = new StringTokenizer(profileIds, ",");
+
+        IConfigStore dbCfg = cfg.getSubStore("internaldb");
+        ILdapConnFactory dbFactory = CMS.getLdapBoundConnFactory();
+        dbFactory.init(dbCfg);
+
+        while (st.hasMoreTokens()) {
+            String profileId = st.nextToken();
+            IConfigStore profileSubCfg = profileCfg.getSubStore(profileId);
+            String classId = profileSubCfg.getString("class_id", "");
+            try {
+                IPluginInfo info = registry.getPluginInfo("profile", classId);
+                if (info == null) {
+                    throw new EBaseException("No plugins for type : profile, with id " + classId);
+                }
+                String className = info.getClassName();
+
+                String profilePath = configRoot + "/ca/profiles/ca/" + profileId + ".cfg";
+                CMS.debug("Importing profile '" + profileId + "' from " + profilePath);
+                importProfile(dbFactory, classId, profileId, profilePath);
+            }
+            catch (EBaseException e) {
+                CMS.debug("Error importing profile '" + profileId + "': " + e.toString());
+                throw e;
+            }
+        }
+    }
+
+    /**
+     * Import one profile from the filesystem into the database.
+     *
+     * @param dbFactory LDAP connection factory.
+     * @param profileFile The profile to import.
+     */
+    public static void importProfile(
+            ILdapConnFactory dbFactory, String classId,
+            String profileId, String profilePath)
+            throws EBaseException {
+
+        IConfigStore cfg = CMS.getConfigStore();
+        String basedn = cfg.getString("internaldb.basedn", "");
+
+        String dn = "cn=" + profileId + ",ou=certProfiles," + basedn;
+
+        String[] objectClasses = {"top", "certProfile"};
+        LDAPAttribute[] createAttrs = {
+            new LDAPAttribute("objectclass", objectClasses),
+            new LDAPAttribute("cn", profileId),
+            new LDAPAttribute("classId", classId)
+        };
+
+        IConfigStore configStore = new LDAPConfigStore(
+            dbFactory, dn, createAttrs, "certProfileConfig");
+
+        try {
+            FileInputStream input = new FileInputStream(profilePath);
+            configStore.load(input);
+        }
+        catch (FileNotFoundException e) {
+            throw new EBaseException("Could not find file for profile: " + profileId);
+        }
+        catch (IOException e) {
+            throw new EBaseException("Error loading data for profile: " + profileId);
+        }
+
+        configStore.commit(false /* no backup */);
     }
 }
-- 
1.9.3

-------------- next part --------------
>From 7eca0dd3f819588d53e71dea84ce23a21186c586 Mon Sep 17 00:00:00 2001
From: Fraser Tweedale <frase at frase.id.au>
Date: Wed, 23 Jul 2014 02:40:07 -0400
Subject: [PATCH] add "pki ca profile show-raw" CLI command

---
 .../dogtagpki/server/ca/rest/ProfileService.java   |  47 +++++-----
 .../netscape/certsrv/profile/ProfileClient.java    |   5 +
 .../netscape/certsrv/profile/ProfileResource.java  |   8 +-
 .../com/netscape/cmstools/profile/ProfileCLI.java  |   1 +
 .../cmstools/profile/ProfileShowRawCLI.java        | 102 +++++++++++++++++++++
 5 files changed, 141 insertions(+), 22 deletions(-)
 create mode 100644 base/java-tools/src/com/netscape/cmstools/profile/ProfileShowRawCLI.java

diff --git a/base/ca/src/org/dogtagpki/server/ca/rest/ProfileService.java b/base/ca/src/org/dogtagpki/server/ca/rest/ProfileService.java
index cf0d4db7f8bed44baf6d2abbf70a61406ddb4b7c..9d851145f5e681f1044f81654130a2d0114ce36d 100644
--- a/base/ca/src/org/dogtagpki/server/ca/rest/ProfileService.java
+++ b/base/ca/src/org/dogtagpki/server/ca/rest/ProfileService.java
@@ -18,6 +18,7 @@
 
 package org.dogtagpki.server.ca.rest;
 
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.net.URI;
 import java.security.Principal;
@@ -163,9 +164,7 @@ public class ProfileService extends PKIService implements ProfileResource {
         return createOKResponse(infos);
     }
 
-    @Override
-    public Response retrieveProfile(String profileId) throws ProfileNotFoundException {
-        ProfileData data = null;
+    private IProfile getProfile(String profileId) throws ProfileNotFoundException {
         boolean visibleOnly = true;
 
         if (profileId == null) {
@@ -185,24 +184,12 @@ public class ProfileService extends PKIService implements ProfileResource {
             visibleOnly = false;
         }
 
-        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;
-                }
-            }
+        IProfile profile;
+        try {
+            profile = ps.getProfile(profileId);
+        } catch (EProfileException e) {
+            e.printStackTrace();
+            throw new ProfileNotFoundException(profileId);
         }
 
         if (profile == null) {
@@ -213,6 +200,14 @@ public class ProfileService extends PKIService implements ProfileResource {
             throw new ProfileNotFoundException(profileId);
         }
 
+        return profile;
+    }
+
+    @Override
+    public Response retrieveProfile(String profileId) throws ProfileNotFoundException {
+        IProfile profile = getProfile(profileId);
+
+        ProfileData data = null;
         try {
             data = createProfileData(profileId);
         } catch (EBaseException e) {
@@ -228,6 +223,16 @@ public class ProfileService extends PKIService implements ProfileResource {
         return createOKResponse(data);
     }
 
+    @Override
+    public Response retrieveProfileRaw(String profileId)
+            throws ProfileNotFoundException {
+        IProfile profile = getProfile(profileId);
+        ByteArrayOutputStream data = new ByteArrayOutputStream();
+        profile.getConfigStore().save(data, null);
+        return createOKResponse(data.toByteArray());
+    }
+
+
     public ProfileData createProfileData(String profileId) throws EBaseException {
 
         IProfile profile;
diff --git a/base/common/src/com/netscape/certsrv/profile/ProfileClient.java b/base/common/src/com/netscape/certsrv/profile/ProfileClient.java
index 51d159aca687719a2dace939da5b09c4809872ec..94b087230d46db342dff365da3c57734d98f02dc 100644
--- a/base/common/src/com/netscape/certsrv/profile/ProfileClient.java
+++ b/base/common/src/com/netscape/certsrv/profile/ProfileClient.java
@@ -45,6 +45,11 @@ public class ProfileClient extends Client {
         return client.getEntity(response, ProfileData.class);
     }
 
+    public byte[] retrieveProfileRaw(String id) {
+        Response response = profileClient.retrieveProfileRaw(id);
+        return client.getEntity(response, byte[].class);
+    }
+
     public ProfileDataInfos listProfiles(Integer start, Integer size) {
         Response response =  profileClient.listProfiles(start, size);
         return client.getEntity(response, ProfileDataInfos.class);
diff --git a/base/common/src/com/netscape/certsrv/profile/ProfileResource.java b/base/common/src/com/netscape/certsrv/profile/ProfileResource.java
index 87449b27e749c6088f65b53192eb5ac101263f1e..d0b84eeb61688fe4bbc107c2bdd368f848e568cd 100644
--- a/base/common/src/com/netscape/certsrv/profile/ProfileResource.java
+++ b/base/common/src/com/netscape/certsrv/profile/ProfileResource.java
@@ -31,6 +31,12 @@ public interface ProfileResource {
     @ACLMapping("profiles.read")
     public Response retrieveProfile(@PathParam("id") String id);
 
+    @GET
+    @Path("{id}/raw")
+    @ClientResponseType(entityType=byte[].class)
+    @ACLMapping("profiles.read")
+    public Response retrieveProfileRaw(@PathParam("id") String id);
+
     @POST
     @ClientResponseType(entityType=ProfileData.class)
     @ACLMapping("profiles.create")
@@ -53,4 +59,4 @@ public interface ProfileResource {
     @ClientResponseType(entityType=Void.class)
     @ACLMapping("profiles.delete")
     public Response deleteProfile(@PathParam("id") String id);
-}
\ No newline at end of file
+}
diff --git a/base/java-tools/src/com/netscape/cmstools/profile/ProfileCLI.java b/base/java-tools/src/com/netscape/cmstools/profile/ProfileCLI.java
index 732b597afd1dbb5b9440d451f34b2f39e20fb904..a57c741946b40f0cc02a10acaf6d895081b151d9 100644
--- a/base/java-tools/src/com/netscape/cmstools/profile/ProfileCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/profile/ProfileCLI.java
@@ -30,6 +30,7 @@ public class ProfileCLI extends CLI {
 
         addModule(new ProfileFindCLI(this));
         addModule(new ProfileShowCLI(this));
+        addModule(new ProfileShowRawCLI(this));
         addModule(new ProfileAddCLI(this));
         addModule(new ProfileModifyCLI(this));
         addModule(new ProfileRemoveCLI(this));
diff --git a/base/java-tools/src/com/netscape/cmstools/profile/ProfileShowRawCLI.java b/base/java-tools/src/com/netscape/cmstools/profile/ProfileShowRawCLI.java
new file mode 100644
index 0000000000000000000000000000000000000000..a15c4e08629a759a2cd66ecfa79578fd9eab6e2e
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/profile/ProfileShowRawCLI.java
@@ -0,0 +1,102 @@
+//--- 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) 2014 Red Hat, Inc.
+//All rights reserved.
+//--- END COPYRIGHT BLOCK ---
+
+package com.netscape.cmstools.profile;
+
+import java.io.FileOutputStream;
+import java.util.Arrays;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.ParseException;
+
+import com.netscape.certsrv.profile.ProfileData;
+import com.netscape.cmstools.cli.CLI;
+import com.netscape.cmstools.cli.MainCLI;
+
+public class ProfileShowRawCLI extends CLI {
+
+    public ProfileCLI profileCLI;
+
+    public ProfileShowRawCLI(ProfileCLI profileCLI) {
+        super("show-raw", "Show profiles (config-store format)", profileCLI);
+        this.profileCLI = profileCLI;
+
+        createOptions();
+    }
+
+    public void printHelp() {
+        formatter.printHelp(getFullName() + " <Profile ID> [OPTIONS...]", options);
+    }
+
+    public void createOptions() {
+        Option option = new Option(null, "output", true, "Output filename");
+        option.setArgName("filename");
+        options.addOption(option);
+    }
+
+    public void execute(String[] args) throws Exception {
+        // Always check for "--help" prior to parsing
+        if (Arrays.asList(args).contains("--help")) {
+            // Display usage
+            printHelp();
+            System.exit(0);
+        }
+
+        CommandLine cmd = null;
+
+        try {
+            cmd = parser.parse(options, args);
+        } catch (ParseException e) {
+            System.err.println("Error: " + e.getMessage());
+            printHelp();
+            System.exit(-1);
+        }
+
+        String[] cmdArgs = cmd.getArgs();
+
+        if (cmdArgs.length < 1) {
+            System.err.println("Error: No Profile ID specified.");
+            printHelp();
+            System.exit(-1);
+        }
+
+        String profileId = cmdArgs[0];
+
+        String filename = null;
+        if (cmd.hasOption("output")) {
+            filename = cmd.getOptionValue("output");
+
+            if (filename == null || filename.trim().length() == 0) {
+                System.err.println("Error: Missing output file name.");
+                printHelp();
+                System.exit(-1);
+            }
+        }
+
+        byte[] profileConfig = profileCLI.profileClient.retrieveProfileRaw(profileId);
+
+        MainCLI.printMessage("Profile \"" + profileId + "\"");
+
+        if (filename != null) {
+            (new FileOutputStream(filename)).write(profileConfig);
+        } else {
+            System.out.println(new String(profileConfig));
+        }
+    }
+}
-- 
1.9.3



More information about the Pki-devel mailing list