>From c79946b6f28f7290fe122590538449fd8bf0e879 Mon Sep 17 00:00:00 2001
From: Ade Lee <alee@redhat.com>
Date: Wed, 21 Aug 2013 11:39:03 -0400
Subject: [PATCH] Add TPS profile ID auxilliary object to tps users

---
 .../src/com/netscape/certsrv/user/UserData.java    | 62 ++++++++++++++++
 .../com/netscape/certsrv/user/UserResource.java    |  3 +
 .../src/com/netscape/certsrv/usrgrp/IUser.java     | 13 ++++
 .../netscape/certsrv/usrgrp/IUserConstants.java    |  5 ++
 .../netscape/cms/servlet/admin/UserService.java    | 38 ++++++++++
 .../cms/servlet/csadmin/ConfigurationUtils.java    | 14 ++++
 .../cms/servlet/csadmin/SystemConfigService.java   |  6 +-
 .../com/netscape/cmscore/usrgrp/UGSubsystem.java   | 86 +++++++++++++++++++++-
 .../src/com/netscape/cmscore/usrgrp/User.java      | 33 ++++++++-
 .../src/com/netscape/cmstools/user/UserCLI.java    |  9 +++
 10 files changed, 263 insertions(+), 6 deletions(-)

diff --git a/base/common/src/com/netscape/certsrv/user/UserData.java b/base/common/src/com/netscape/certsrv/user/UserData.java
index b62d0223195caac6d25ebd1cc6c4d1b47766604a..da771f2e73f155c45a4e415219632aacaaf29c2a 100644
--- a/base/common/src/com/netscape/certsrv/user/UserData.java
+++ b/base/common/src/com/netscape/certsrv/user/UserData.java
@@ -20,6 +20,10 @@ package com.netscape.certsrv.user;
 
 import java.io.StringReader;
 import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
 
 import javax.ws.rs.FormParam;
 import javax.xml.bind.JAXBContext;
@@ -28,6 +32,9 @@ import javax.xml.bind.Unmarshaller;
 import javax.xml.bind.annotation.XmlAttribute;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlValue;
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 
 import org.jboss.resteasy.plugins.providers.atom.Link;
 
@@ -62,6 +69,18 @@ public class UserData {
 
     Link link;
 
+    @XmlElement(name="Attributes")
+    @XmlJavaTypeAdapter(MapAdapter.class)
+    Map<String, String> attributes = new LinkedHashMap<String, String>();
+
+    public String getAttribute(String name) {
+        return attributes.get(name);
+    }
+
+    public void setAttribute(String name, String value) {
+        attributes.put(name, value);
+    }
+
     @XmlAttribute(name="id")
     public String getID() {
         return id;
@@ -144,6 +163,7 @@ public class UserData {
     public int hashCode() {
         final int prime = 31;
         int result = 1;
+        result = prime * result + ((attributes == null) ? 0 : attributes.hashCode());
         result = prime * result + ((email == null) ? 0 : email.hashCode());
         result = prime * result + ((fullName == null) ? 0 : fullName.hashCode());
         result = prime * result + ((id == null) ? 0 : id.hashCode());
@@ -163,6 +183,11 @@ public class UserData {
         if (getClass() != obj.getClass())
             return false;
         UserData other = (UserData) obj;
+        if (attributes == null) {
+            if (other.attributes != null)
+                return false;
+        } else if (!attributes.equals(other.attributes))
+            return false;
         if (email == null) {
             if (other.email != null)
                 return false;
@@ -220,6 +245,43 @@ public class UserData {
         }
     }
 
+    public static class MapAdapter extends XmlAdapter<AttributeList, Map<String, String>> {
+
+        public AttributeList marshal(Map<String, String> map) {
+            AttributeList list = new AttributeList();
+            for (Map.Entry<String, String> entry : map.entrySet()) {
+                Attribute attribute = new Attribute();
+                attribute.name = entry.getKey();
+                attribute.value = entry.getValue();
+                list.attributes.add(attribute);
+            }
+            return list;
+        }
+
+        public Map<String, String> unmarshal(AttributeList list) {
+            Map<String, String> map = new LinkedHashMap<String, String>();
+            for (Attribute attribute : list.attributes) {
+                map.put(attribute.name, attribute.value);
+            }
+            return map;
+        }
+    }
+
+    public static class AttributeList {
+        @XmlElement(name="Attribute")
+        public List<Attribute> attributes = new ArrayList<Attribute>();
+    }
+
+    public static class Attribute {
+
+        @XmlAttribute
+        public String name;
+
+        @XmlValue
+        public String value;
+    }
+
+
     public static void main(String args[]) throws Exception {
 
         UserData before = new UserData();
diff --git a/base/common/src/com/netscape/certsrv/user/UserResource.java b/base/common/src/com/netscape/certsrv/user/UserResource.java
index 0789928978ba9ffe069cfc0f31854ab70af414d3..a0f5f1db599c1076fea6710f06253a4f79b63423 100644
--- a/base/common/src/com/netscape/certsrv/user/UserResource.java
+++ b/base/common/src/com/netscape/certsrv/user/UserResource.java
@@ -42,6 +42,9 @@ import com.netscape.certsrv.authentication.AuthMethodMapping;
 @AuthMethodMapping("admin")
 public interface UserResource {
 
+    public static final String ATTR_TPS_PROFILES = "tpsProfiles";
+    public static final String ALL_PROFILES = "All Profiles";
+
     @GET
     @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
     public UserCollection findUsers(
diff --git a/base/common/src/com/netscape/certsrv/usrgrp/IUser.java b/base/common/src/com/netscape/certsrv/usrgrp/IUser.java
index 7c957fd8a1eb9f2104f38e2346b83b28320f4013..af0d38336e994a143cfdedaac4166e043c476fbe 100644
--- a/base/common/src/com/netscape/certsrv/usrgrp/IUser.java
+++ b/base/common/src/com/netscape/certsrv/usrgrp/IUser.java
@@ -18,6 +18,7 @@
 package com.netscape.certsrv.usrgrp;
 
 import java.security.cert.X509Certificate;
+import java.util.List;
 
 import com.netscape.certsrv.base.IAttrSet;
 
@@ -168,4 +169,16 @@ public interface IUser extends IAttrSet, IUserConstants {
      * @return user type.
      */
     public String getUserType();
+
+    /**
+     * Get TPS profiles
+     * @return
+     */
+    public List<String> getTpsProfiles();
+
+    /**
+     * Set TPS profiles
+     * @param tpsProfiles
+     */
+    public void setTpsProfiles(List<String> tpsProfiles);
 }
diff --git a/base/common/src/com/netscape/certsrv/usrgrp/IUserConstants.java b/base/common/src/com/netscape/certsrv/usrgrp/IUserConstants.java
index dbfe9a38b22bdd7b3a165292d17391daa23d74ab..350f7d7fd76fcdbb1be6325d5f2b433231f44a30 100644
--- a/base/common/src/com/netscape/certsrv/usrgrp/IUserConstants.java
+++ b/base/common/src/com/netscape/certsrv/usrgrp/IUserConstants.java
@@ -63,4 +63,9 @@ public interface IUserConstants {
      * Constant for usertype
      */
     public static final String ATTR_USERTYPE = "usertype";
+
+    /**
+     * Constant for usertype
+     */
+    public static final String ATTR_TPS_PROFILES = "tpsProfiles";
 }
diff --git a/base/common/src/com/netscape/cms/servlet/admin/UserService.java b/base/common/src/com/netscape/cms/servlet/admin/UserService.java
index 947d1731e9fac6821e2e330c8821ca3ca85e4585..a098980cd48ecc24ac824ace8b09f4d08f17b243 100644
--- a/base/common/src/com/netscape/cms/servlet/admin/UserService.java
+++ b/base/common/src/com/netscape/cms/servlet/admin/UserService.java
@@ -20,7 +20,9 @@ package com.netscape.cms.servlet.admin;
 
 import java.net.URI;
 import java.net.URLEncoder;
+import java.util.Arrays;
 import java.util.Enumeration;
+import java.util.List;
 import java.util.Map;
 
 import javax.ws.rs.core.MediaType;
@@ -36,6 +38,7 @@ import com.netscape.certsrv.base.BadRequestDataException;
 import com.netscape.certsrv.base.BadRequestException;
 import com.netscape.certsrv.base.EBaseException;
 import com.netscape.certsrv.base.ForbiddenException;
+import com.netscape.certsrv.base.IConfigStore;
 import com.netscape.certsrv.base.PKIException;
 import com.netscape.certsrv.base.UserNotFoundException;
 import com.netscape.certsrv.common.OpDef;
@@ -178,6 +181,19 @@ public class UserService extends PKIService implements UserResource {
             String type = user.getUserType();
             if (!StringUtils.isEmpty(type)) userData.setType(type);
 
+            List<String> profiles = user.getTpsProfiles();
+            if (profiles != null) {
+                StringBuilder sb = new StringBuilder();
+                String prefix = "";
+                for (String profile: profiles) {
+                    sb.append(prefix);
+                    prefix = ",";
+                    sb.append(profile);
+                }
+
+                userData.setAttribute(ATTR_TPS_PROFILES, sb.toString());
+            }
+
             return userData;
 
         } catch (PKIException e) {
@@ -205,6 +221,7 @@ public class UserService extends PKIService implements UserResource {
     @Override
     public Response addUser(UserData userData) {
 
+        IConfigStore cs = CMS.getConfigStore();
         String userID = userData.getID();
 
         // ensure that any low-level exceptions are reported
@@ -279,6 +296,16 @@ public class UserService extends PKIService implements UserResource {
                 user.setState(state);
             }
 
+            String tpsProfiles = userData.getAttribute(ATTR_TPS_PROFILES);
+            String csType = cs.getString("cs.type");
+            if (tpsProfiles != null) {
+                if (!csType.equals("TPS")) {
+                    throw new BadRequestDataException("Cannot set tpsProfiles on a non-TPS subsystem");
+                }
+                String[] profiles = tpsProfiles.split(",");
+                user.setTpsProfiles(Arrays.asList(profiles));
+            }
+
             try {
                 userGroupManager.addUser(user);
 
@@ -339,6 +366,7 @@ public class UserService extends PKIService implements UserResource {
 
         // ensure that any low-level exceptions are reported
         // to the signed audit log and stored as failures
+        IConfigStore cs = CMS.getConfigStore();
         try {
             if (userID == null) {
                 log(ILogger.LL_FAILURE, CMS.getLogMessage("ADMIN_SRVLT_NULL_RS_ID"));
@@ -378,6 +406,16 @@ public class UserService extends PKIService implements UserResource {
                 user.setState(state);
             }
 
+            String tpsProfiles = userData.getAttribute(ATTR_TPS_PROFILES);
+            String csType = cs.getString("cs.type");
+            if (tpsProfiles != null) {
+                if (!csType.equals("TPS")) {
+                    throw new BadRequestDataException("Cannot set tpsProfiles on a non-TPS subsystem");
+                }
+                String[] profiles = tpsProfiles.split(",");
+                user.setTpsProfiles(Arrays.asList(profiles));
+            }
+
             try {
                 userGroupManager.modifyUser(user);
 
diff --git a/base/common/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java b/base/common/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java
index 1ca0476a6cd5196e49b88ba1af989477909cdca0..2371848ec622c6d8afa17981629011e9694a02b9 100644
--- a/base/common/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java
+++ b/base/common/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java
@@ -48,6 +48,7 @@ import java.security.cert.CertificateException;
 import java.security.interfaces.RSAPublicKey;
 import java.util.ArrayList;
 import java.util.Enumeration;
+import java.util.List;
 import java.util.StringTokenizer;
 import java.util.Vector;
 
@@ -155,6 +156,7 @@ import com.netscape.certsrv.usrgrp.EUsrGrpException;
 import com.netscape.certsrv.usrgrp.IGroup;
 import com.netscape.certsrv.usrgrp.IUGSubsystem;
 import com.netscape.certsrv.usrgrp.IUser;
+import com.netscape.cms.servlet.admin.UserService;
 import com.netscape.cmsutil.crypto.CryptoUtil;
 import com.netscape.cmsutil.http.HttpClient;
 import com.netscape.cmsutil.http.HttpRequest;
@@ -3679,6 +3681,18 @@ public class ConfigurationUtils {
         removeOldDBUsers(certs[0].getSubjectDN().toString());
     }
 
+    public static void addProfilesToTPSUser(String adminID) throws EUsrGrpException {
+        CMS.debug("Adding all profiles to TPS admin user");
+        IUGSubsystem system = (IUGSubsystem) CMS.getSubsystem(IUGSubsystem.ID);
+        IUser user = system.getUser(adminID);
+
+        List<String> profiles = new ArrayList<String>();
+        profiles.add(UserService.ALL_PROFILES);
+
+        user.setTpsProfiles(profiles);
+        system.modifyUser(user);
+    }
+
     public static void registerUser(URI secdomainURI, URI targetURI, String targetType) throws Exception {
         IConfigStore cs = CMS.getConfigStore();
         String csType = cs.getString("cs.type");
diff --git a/base/common/src/com/netscape/cms/servlet/csadmin/SystemConfigService.java b/base/common/src/com/netscape/cms/servlet/csadmin/SystemConfigService.java
index ce82c93489d3dbe273ebf7e2dbff57105671f533..c834eef3f17432b1e5e24f494b886a77caf274af 100644
--- a/base/common/src/com/netscape/cms/servlet/csadmin/SystemConfigService.java
+++ b/base/common/src/com/netscape/cms/servlet/csadmin/SystemConfigService.java
@@ -467,13 +467,15 @@ public class SystemConfigService extends PKIService implements SystemConfigResou
 
         if (csType.equals("TPS")) {
             try {
+                ConfigurationUtils.addProfilesToTPSUser(data.getAdminUID());
+
                 URI secdomainURI = new URI(data.getSecurityDomainUri());
 
-                // register tps with ca
+                // register TPS with CA
                 URI caURI = new URI(data.getCaUri());
                 ConfigurationUtils.registerUser(secdomainURI, caURI, "ca");
 
-                // register tps with tks
+                // register TPS with TKS
                 URI tksURI = new URI(data.getTksUri());
                 ConfigurationUtils.registerUser(secdomainURI, tksURI, "tks");
 
diff --git a/base/common/src/com/netscape/cmscore/usrgrp/UGSubsystem.java b/base/common/src/com/netscape/cmscore/usrgrp/UGSubsystem.java
index 034357b6efb727f4d793ac14b8f7545bc28f6aa1..3833c29378b41a4855016017d0e1322e6d67fc89 100644
--- a/base/common/src/com/netscape/cmscore/usrgrp/UGSubsystem.java
+++ b/base/common/src/com/netscape/cmscore/usrgrp/UGSubsystem.java
@@ -19,7 +19,10 @@ package com.netscape.cmscore.usrgrp;
 
 import java.security.cert.CertificateEncodingException;
 import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Enumeration;
+import java.util.List;
 import java.util.Vector;
 
 import netscape.ldap.LDAPAttribute;
@@ -75,6 +78,7 @@ public final class UGSubsystem implements IUGSubsystem {
     protected static final String LDAP_ATTR_USER_CERT_STRING = "description";
     protected static final String LDAP_ATTR_CERTDN = "seeAlso";
     protected static final String LDAP_ATTR_USER_CERT = "userCertificate";
+    protected static final String LDAP_ATTR_PROFILE_ID = "profileID";
 
     protected static final String PROP_BASEDN = "basedn";
 
@@ -624,6 +628,13 @@ public final class UGSubsystem implements IUGSubsystem {
             }
         }
 
+        LDAPAttribute profileAttr = entry.getAttribute(LDAP_ATTR_PROFILE_ID);
+        if (profileAttr != null) {
+            @SuppressWarnings("unchecked")
+            Enumeration<String> profiles = profileAttr.getStringValues();
+            id.setTpsProfiles(Collections.list(profiles));
+        }
+
         return id;
     }
 
@@ -647,10 +658,21 @@ public final class UGSubsystem implements IUGSubsystem {
         }
 
         LDAPAttributeSet attrs = new LDAPAttributeSet();
-        String oc[] = { "top", "person", "organizationalPerson",
-                "inetOrgPerson", "cmsuser" };
+        List<String> oclist = new ArrayList<String>();
+        oclist.add("top");
+        oclist.add("person");
+        oclist.add("organizationalPerson");
+        oclist.add("inetOrgPerson");
+        oclist.add("cmsuser");
 
-        attrs.add(new LDAPAttribute("objectclass", oc));
+        if (id.getTpsProfiles() != null) {
+            oclist.add("tpsProfileID");
+        }
+
+        String oc[] = new String[oclist.size()];
+        oc = oclist.toArray(oc);
+
+        attrs.add(new LDAPAttribute(OBJECTCLASS_ATTR, oc));
         attrs.add(new LDAPAttribute("uid", id.getUserID()));
         attrs.add(new LDAPAttribute("sn", id.getFullName()));
         attrs.add(new LDAPAttribute("cn", id.getFullName()));
@@ -685,6 +707,14 @@ public final class UGSubsystem implements IUGSubsystem {
             }
         }
 
+        // TODO add audit logging for profile
+        if (id.getTpsProfiles() != null) {
+            List<String> profiles = id.getTpsProfiles();
+            for (String profile: profiles) {
+                attrs.add(new LDAPAttribute(LDAP_ATTR_PROFILE_ID, profile));
+            }
+        }
+
         LDAPEntry entry = new LDAPEntry("uid=" + LDAPUtil.escapeRDNValue(id.getUserID()) +
                 "," + getUserBaseDN(), attrs);
         // for audit log
@@ -1074,6 +1104,7 @@ public final class UGSubsystem implements IUGSubsystem {
         }
     }
 
+
     /**
      * modifies user attributes. Certs are handled separately
      */
@@ -1147,6 +1178,55 @@ public final class UGSubsystem implements IUGSubsystem {
                 }
             }
 
+            if (user.getTpsProfiles() != null) {
+                // TODO add audit logging for profile
+
+                // replace the objectclass in case tpsProfile is not present
+                String oc[] = { "top", "person", "organizationalPerson",
+                        "inetOrgPerson", "cmsuser", "tpsProfileID" };
+                attrs.add(LDAPModification.REPLACE,
+                        new LDAPAttribute(OBJECTCLASS_ATTR, oc));
+
+                User ldapUser = (User) getUser(user.getUserID());
+                List<String> oldProfiles = ldapUser.getTpsProfiles();
+                List<String> profiles = user.getTpsProfiles();
+
+                if (oldProfiles == null) {
+                    for (String profile : profiles) {
+                        attrs.add(LDAPModification.ADD,
+                                new LDAPAttribute(LDAP_ATTR_PROFILE_ID, profile));
+                    }
+                } else {
+                    for (String profile : profiles) {
+                        boolean found = false;
+                        for (String oldProfile : oldProfiles) {
+                            if (profile.equals(oldProfile)) {
+                                found = true;
+                                break;
+                            }
+                        }
+                        if (!found) {
+                            attrs.add(LDAPModification.ADD,
+                                    new LDAPAttribute(LDAP_ATTR_PROFILE_ID, profile));
+                        }
+                    }
+
+                    for (String oldProfile : oldProfiles) {
+                        boolean found = false;
+                        for (String profile : profiles) {
+                            if (profile.equals(oldProfile)) {
+                                found = true;
+                                break;
+                            }
+                        }
+                        if (!found) {
+                            attrs.add(LDAPModification.DELETE,
+                                    new LDAPAttribute(LDAP_ATTR_PROFILE_ID, oldProfile));
+                        }
+                    }
+                }
+            }
+
             /**
              * if ((certs = user.getCertificates()) != null) {
              * LDAPAttribute attrCertStr = new
diff --git a/base/common/src/com/netscape/cmscore/usrgrp/User.java b/base/common/src/com/netscape/cmscore/usrgrp/User.java
index 53347750107f871fa448ccb0b546bcabd8f05ff0..ef09a1ab56e07c57ae5445abc32539326acb3938 100644
--- a/base/common/src/com/netscape/cmscore/usrgrp/User.java
+++ b/base/common/src/com/netscape/cmscore/usrgrp/User.java
@@ -18,13 +18,16 @@
 package com.netscape.cmscore.usrgrp;
 
 import java.security.cert.X509Certificate;
+import java.util.ArrayList;
 import java.util.Enumeration;
+import java.util.List;
 import java.util.Vector;
 
 import com.netscape.certsrv.apps.CMS;
 import com.netscape.certsrv.base.EBaseException;
 import com.netscape.certsrv.usrgrp.IUser;
 import com.netscape.certsrv.usrgrp.IUsrGrp;
+import com.netscape.cms.servlet.admin.UserService;
 
 /**
  * A class represents a user.
@@ -51,6 +54,7 @@ public class User implements IUser {
     private String mCertDN = null;
     private String mUserType = null;
     private X509Certificate mx509Certs[] = null;
+    private List<String> tpsProfiles = null;
 
     private static final Vector<String> mNames = new Vector<String>();
     static {
@@ -60,9 +64,31 @@ public class User implements IUser {
         mNames.addElement(ATTR_PASSWORD);
         mNames.addElement(ATTR_STATE);
         mNames.addElement(ATTR_EMAIL);
-        //		mNames.addElement(ATTR_PHONENUMBER);
+        // mNames.addElement(ATTR_PHONENUMBER);
         mNames.addElement(ATTR_X509_CERTIFICATES);
         mNames.addElement(ATTR_USERTYPE);
+        mNames.addElement(ATTR_TPS_PROFILES);
+    }
+
+    public List<String> getTpsProfiles() {
+        return tpsProfiles;
+    }
+
+    public void setTpsProfiles(List<String> tpsProfiles) {
+        boolean setAll = false;
+        for (String profile: tpsProfiles) {
+            if (profile.equals(UserService.ALL_PROFILES)) {
+                setAll = true;
+                break;
+            }
+        }
+        if (!setAll) {
+            this.tpsProfiles = tpsProfiles;
+        } else {
+            List<String> list = new ArrayList<String>();
+            list.add(UserService.ALL_PROFILES);
+            this.tpsProfiles = list;
+        }
     }
 
     /**
@@ -169,6 +195,7 @@ public class User implements IUser {
         mCertDN = dn;
     }
 
+    @SuppressWarnings("unchecked")
     public void set(String name, Object object) throws EBaseException {
         if (name.equals(ATTR_NAME)) {
             throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", name));
@@ -184,6 +211,8 @@ public class User implements IUser {
             setX509Certificates((X509Certificate[]) object);
         } else if (name.equals(ATTR_USERTYPE)) {
             setUserType((String) object);
+        } else if (name.equals(ATTR_TPS_PROFILES)) {
+            setTpsProfiles((List<String>) object);
         } else {
             throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", name));
         }
@@ -204,6 +233,8 @@ public class User implements IUser {
             return getX509Certificates();
         } else if (name.equals(ATTR_USERTYPE)) {
             return getUserType();
+        } else if (name.equals(ATTR_TPS_PROFILES)) {
+            return getTpsProfiles();
         } else {
             throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", name));
         }
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 2343d1989e412b7d06102cbb6773a4dde2a0b319..b111f1558338d07247557015d53b494486fdec0a 100644
--- a/base/java-tools/src/com/netscape/cmstools/user/UserCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/user/UserCLI.java
@@ -27,6 +27,7 @@ import com.netscape.certsrv.user.UserCertData;
 import com.netscape.certsrv.user.UserClient;
 import com.netscape.certsrv.user.UserData;
 import com.netscape.certsrv.user.UserMembershipData;
+import com.netscape.certsrv.user.UserResource;
 import com.netscape.cmstools.cli.CLI;
 import com.netscape.cmstools.cli.MainCLI;
 
@@ -134,6 +135,14 @@ public class UserCLI extends CLI {
         if (verbose && link != null) {
             System.out.println("  Link: " + link.getHref());
         }
+
+        String tpsProfiles = userData.getAttribute(UserResource.ATTR_TPS_PROFILES);
+        if (tpsProfiles != null) {
+            System.out.println("  TPS Profiles:");
+            for (String profile: tpsProfiles.split(",")) {
+                System.out.println("    " + profile);
+            }
+        }
     }
 
     public static void printCert(
-- 
1.8.1.4

