From e4842986dac5f91b02f9702a28ea068298a0dec0 Mon Sep 17 00:00:00 2001
From: "Endi S. Dewata" <edewata@redhat.com>
Date: Mon, 14 Apr 2014 13:32:17 -0400
Subject: [PATCH] Fixed user's name in TPS UI.

Previously the user's name displayed in the top right corner of the
TPS UI was hardcoded to Administrator. It has been fixed to display
the full name of the authenticated user obtained from the server.

The login() method in the account REST service has been modified to
return the account information about the user and the roles in which
the user belongs. This information can later be used to further
customize the behavior of the UI based on the authorization data.

The PKIRealm has been modified to store the authenticated user info
in the PKI principal.

Ticket #654
---
 .../netscape/certsrv/account/AccountClient.java    |  14 +-
 .../com/netscape/certsrv/account/AccountInfo.java  | 207 +++++++++++++++++++++
 .../netscape/certsrv/account/AccountResource.java  |   2 +-
 .../src/com/netscape/cms/realm/PKIPrincipal.java   |  11 +-
 .../cms/src/com/netscape/cms/realm/PKIRealm.java   |   2 +-
 .../org/dogtagpki/server/rest/AccountService.java  |  26 ++-
 base/tps-tomcat/shared/webapps/tps/js/account.js   |   2 +-
 base/tps-tomcat/shared/webapps/tps/ui/index.html   |  14 +-
 8 files changed, 266 insertions(+), 12 deletions(-)
 create mode 100644 base/common/src/com/netscape/certsrv/account/AccountInfo.java

diff --git a/base/common/src/com/netscape/certsrv/account/AccountClient.java b/base/common/src/com/netscape/certsrv/account/AccountClient.java
index cec8bd8470a40be3a3d2580681a83c7551c394c8..ab7081b7bb98fd6a69224939104044cc6d36e93e 100644
--- a/base/common/src/com/netscape/certsrv/account/AccountClient.java
+++ b/base/common/src/com/netscape/certsrv/account/AccountClient.java
@@ -41,10 +41,20 @@ public class AccountClient extends Client {
         resource = createProxy(AccountResource.class);
     }
 
-    public void login() {
+    public AccountInfo login() {
         Response response = resource.login();
-        client.getEntity(response, Void.class);
+        AccountInfo info = client.getEntity(response, AccountInfo.class);
         loggedIn = true;
+
+        if (client.verbose) {
+            System.out.println("Account:");
+            System.out.println(" - User ID: " + info.getID());
+            System.out.println(" - Full Name: " + info.getFullName());
+            System.out.println(" - Email: " + info.getEmail());
+            System.out.println(" - Roles: " + info.getRoles());
+        }
+
+        return info;
     }
 
     public void logout() {
diff --git a/base/common/src/com/netscape/certsrv/account/AccountInfo.java b/base/common/src/com/netscape/certsrv/account/AccountInfo.java
new file mode 100644
index 0000000000000000000000000000000000000000..02e40746a41c1f42b174567c0c73e88138a2fbdc
--- /dev/null
+++ b/base/common/src/com/netscape/certsrv/account/AccountInfo.java
@@ -0,0 +1,207 @@
+// --- 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.certsrv.account;
+
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.Marshaller;
+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;
+
+/**
+ * @author Endi S. Dewata
+ */
+@XmlRootElement(name="Account")
+public class AccountInfo {
+
+    public static Marshaller marshaller;
+    public static Unmarshaller unmarshaller;
+
+    static {
+        try {
+            marshaller = JAXBContext.newInstance(AccountInfo.class).createMarshaller();
+            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
+            unmarshaller = JAXBContext.newInstance(AccountInfo.class).createUnmarshaller();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    String id;
+    String fullName;
+    String email;
+    List<String> roles;
+
+    @XmlAttribute(name="id")
+    public String getID() {
+        return id;
+    }
+
+    public void setID(String id) {
+        this.id = id;
+    }
+
+    @XmlElement(name="FullName")
+    public String getFullName() {
+        return fullName;
+    }
+
+    public void setFullName(String fullName) {
+        this.fullName = fullName;
+    }
+
+    @XmlElement(name="Email")
+    public String getEmail() {
+        return email;
+    }
+
+    public void setEmail(String email) {
+        this.email = email;
+    }
+
+    @XmlElement(name="Roles")
+    @XmlJavaTypeAdapter(RolesAdapter.class)
+    public List<String> getRoles() {
+        return roles;
+    }
+
+    public void setRoles(List<String> roles) {
+        this.roles = roles;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((email == null) ? 0 : email.hashCode());
+        result = prime * result + ((fullName == null) ? 0 : fullName.hashCode());
+        result = prime * result + ((id == null) ? 0 : id.hashCode());
+        result = prime * result + ((roles == null) ? 0 : roles.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        AccountInfo other = (AccountInfo) obj;
+        if (email == null) {
+            if (other.email != null)
+                return false;
+        } else if (!email.equals(other.email))
+            return false;
+        if (fullName == null) {
+            if (other.fullName != null)
+                return false;
+        } else if (!fullName.equals(other.fullName))
+            return false;
+        if (id == null) {
+            if (other.id != null)
+                return false;
+        } else if (!id.equals(other.id))
+            return false;
+        if (roles == null) {
+            if (other.roles != null)
+                return false;
+        } else if (!roles.equals(other.roles))
+            return false;
+        return true;
+    }
+
+    public String toString() {
+        try {
+            StringWriter sw = new StringWriter();
+            marshaller.marshal(this, sw);
+            return sw.toString();
+
+        } catch (Exception e) {
+            return super.toString();
+        }
+    }
+
+    public static AccountInfo valueOf(String string) throws Exception {
+        try {
+            return (AccountInfo)unmarshaller.unmarshal(new StringReader(string));
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    public static class RolesAdapter extends XmlAdapter<RoleList, List<String>> {
+
+        public RoleList marshal(List<String> roles) {
+            RoleList list = new RoleList();
+            for (String value : roles) {
+                Role role = new Role();
+                role.value = value;
+                list.entries.add(role);
+            }
+            return list;
+        }
+
+        public List<String> unmarshal(RoleList list) {
+            List<String> roles = new ArrayList<String>();
+            for (Role role : list.entries) {
+                roles.add(role.value);
+            }
+            return roles;
+        }
+    }
+
+    public static class RoleList {
+        public List<Role> entries = new ArrayList<Role>();
+    }
+
+    @XmlRootElement(name="Role")
+    public static class Role {
+
+        @XmlValue
+        public String value;
+    }
+
+
+    public static void main(String args[]) throws Exception {
+
+        AccountInfo before = new AccountInfo();
+        before.setID("testuser");
+        before.setFullName("Test User");
+        before.setEmail("testuser@example.com");
+        before.setRoles(Arrays.asList("admin", "agent"));
+
+        String string = before.toString();
+        System.out.println(string);
+
+        AccountInfo after = AccountInfo.valueOf(string);
+        System.out.println(before.equals(after));
+    }
+}
diff --git a/base/common/src/com/netscape/certsrv/account/AccountResource.java b/base/common/src/com/netscape/certsrv/account/AccountResource.java
index be6437515a80f07a973aa9b853e0f389ca9ae203..95440cf10d9078278a55bdfc610110e084a00474 100644
--- a/base/common/src/com/netscape/certsrv/account/AccountResource.java
+++ b/base/common/src/com/netscape/certsrv/account/AccountResource.java
@@ -36,7 +36,7 @@ public interface AccountResource {
 
     @GET
     @Path("login")
-    @ClientResponseType(entityType=Void.class)
+    @ClientResponseType(entityType=AccountInfo.class)
     @ACLMapping("account.login")
     public Response login();
 
diff --git a/base/server/cms/src/com/netscape/cms/realm/PKIPrincipal.java b/base/server/cms/src/com/netscape/cms/realm/PKIPrincipal.java
index c39ab4157504e1f6b38c7b170e77829f5f403502..5d83660bcd8222bfd84068226cb6d0bd0c78b308 100644
--- a/base/server/cms/src/com/netscape/cms/realm/PKIPrincipal.java
+++ b/base/server/cms/src/com/netscape/cms/realm/PKIPrincipal.java
@@ -5,6 +5,7 @@ import java.util.List;
 import org.apache.catalina.realm.GenericPrincipal;
 
 import com.netscape.certsrv.authentication.IAuthToken;
+import com.netscape.certsrv.usrgrp.IUser;
 
 /**
  * @author Endi S. Dewata
@@ -12,15 +13,17 @@ import com.netscape.certsrv.authentication.IAuthToken;
 
 public class PKIPrincipal extends GenericPrincipal {
 
+    IUser user;
     IAuthToken authToken;
 
-    public PKIPrincipal(String name, String password, List<String> roles, IAuthToken authToken) {
-        super(name, password, roles);
+    public PKIPrincipal(IUser user, String password, List<String> roles, IAuthToken authToken) {
+        super(user.getUserID(), password, roles);
+        this.user = user;
         this.authToken = authToken;
     }
 
-    public PKIPrincipal(String name, String password, List<String> roles) {
-        this(name, password, roles, null);
+    public IUser getUser() {
+        return user;
     }
 
     public IAuthToken getAuthToken() {
diff --git a/base/server/cms/src/com/netscape/cms/realm/PKIRealm.java b/base/server/cms/src/com/netscape/cms/realm/PKIRealm.java
index b035f53f66a4b05eaa4b7d3edfcfed5c9b22169a..5ad956157eafca30aeb6772953d898a47fad8425 100644
--- a/base/server/cms/src/com/netscape/cms/realm/PKIRealm.java
+++ b/base/server/cms/src/com/netscape/cms/realm/PKIRealm.java
@@ -113,7 +113,7 @@ public class PKIRealm extends RealmBase {
 
     protected Principal getPrincipal(IUser user, IAuthToken authToken) throws EUsrGrpException {
         List<String> roles = getRoles(user);
-        return new PKIPrincipal(user.getUserID(), null, roles, authToken);
+        return new PKIPrincipal(user, null, roles, authToken);
     }
 
     protected IUser getUser(String username) throws EUsrGrpException {
diff --git a/base/server/cms/src/org/dogtagpki/server/rest/AccountService.java b/base/server/cms/src/org/dogtagpki/server/rest/AccountService.java
index a016bda69ce5de03d69b5c6b21913e879a99c400..4e8e6e6f89fc065e2ad0c5fa616165de929142db 100644
--- a/base/server/cms/src/org/dogtagpki/server/rest/AccountService.java
+++ b/base/server/cms/src/org/dogtagpki/server/rest/AccountService.java
@@ -19,6 +19,7 @@
 package org.dogtagpki.server.rest;
 
 import java.security.Principal;
+import java.util.Arrays;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpSession;
@@ -28,7 +29,12 @@ import javax.ws.rs.core.Request;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 
+import org.apache.commons.lang.StringUtils;
+
+import com.netscape.certsrv.account.AccountInfo;
 import com.netscape.certsrv.account.AccountResource;
+import com.netscape.certsrv.usrgrp.IUser;
+import com.netscape.cms.realm.PKIPrincipal;
 import com.netscape.cms.servlet.base.PKIService;
 
 /**
@@ -56,7 +62,25 @@ public class AccountService extends PKIService implements AccountResource {
         Principal principal = servletRequest.getUserPrincipal();
         System.out.println("Principal: "+principal);
 
-        return createNoContentResponse();
+        AccountInfo response = new AccountInfo();
+        String name = principal.getName();
+        response.setID(name);
+
+        if (principal instanceof PKIPrincipal) {
+            PKIPrincipal pkiPrincipal = (PKIPrincipal)principal;
+            IUser user = pkiPrincipal.getUser();
+
+            String fullName = user.getFullName();
+            if (!StringUtils.isEmpty(fullName)) response.setFullName(fullName);
+
+            String email = user.getEmail();
+            if (!StringUtils.isEmpty(email)) response.setEmail(email);
+
+            String[] roles = pkiPrincipal.getRoles();
+            response.setRoles(Arrays.asList(roles));
+        }
+
+        return createOKResponse(response);
     }
 
     @Override
diff --git a/base/tps-tomcat/shared/webapps/tps/js/account.js b/base/tps-tomcat/shared/webapps/tps/js/account.js
index 50a8cab70f446139947f6eeaf181b8155d560853..97b222aaa07b42056395ddb9baaec4d85381a252 100644
--- a/base/tps-tomcat/shared/webapps/tps/js/account.js
+++ b/base/tps-tomcat/shared/webapps/tps/js/account.js
@@ -24,7 +24,7 @@ function Account() {
     this.url = "/tps/rest/account";
 
     this.login = function(options) {
-        var jqxhr = $.get(this.url + "/login");
+        var jqxhr = $.get(this.url + "/login", null, null, "json");
         jqxhr.done(options.success);
         jqxhr.fail(options.error);
     };
diff --git a/base/tps-tomcat/shared/webapps/tps/ui/index.html b/base/tps-tomcat/shared/webapps/tps/ui/index.html
index 77145dfb00c648af31de1d2a865c3df0f817f1ad..6969e786a68ff3b25078917e8c5eef122650b2a4 100644
--- a/base/tps-tomcat/shared/webapps/tps/ui/index.html
+++ b/base/tps-tomcat/shared/webapps/tps/ui/index.html
@@ -42,6 +42,17 @@
     <script>
 $(function() {
 
+    var account = new Account();
+    account.login({
+        success: function(data, textStatus, jqXHR) {
+            var user = $("#user");
+            user.text(data.FullName);
+        },
+        error: function() {
+            window.location.href = "/tps";
+        }
+    });
+
     var content = $("#content");
 
     var router = new Backbone.Router();
@@ -305,7 +316,6 @@ $(function() {
     });
 
     router.route("logout", "logout", function() {
-        var account = new Account();
         account.logout({
             success: function() {
                 if (window.crypto) window.crypto.logout();
@@ -341,7 +351,7 @@ $(function() {
     <li class="dropdown">
         <a href="#" class="dropdown-toggle" data-toggle="dropdown">
         <span class="rcueicon rcueicon-user"></span>
-        Administrator<b class="caret"></b>
+        <span id="user"></span><b class="caret"></b>
         </a>
         <ul class="dropdown-menu">
         <li><a href="#logout">Logout</a></li>
-- 
1.8.4.2

