summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEndi S. Dewata <edewata@redhat.com>2015-12-24 17:20:58 +0100
committerEndi S. Dewata <edewata@redhat.com>2016-01-18 16:45:13 +0100
commit2c88b5d9c15487a796f65beea6c102b1ef04016f (patch)
tree45130adc9e1c4cb0bfd3f5d927cfa4a78fd4cdcd
parent77d6c95527f2f7299e3baece465ef9d778815745 (diff)
downloadpki-2c88b5d9c15487a796f65beea6c102b1ef04016f.tar.gz
pki-2c88b5d9c15487a796f65beea6c102b1ef04016f.tar.xz
pki-2c88b5d9c15487a796f65beea6c102b1ef04016f.zip
Added table to manage TPS user profiles.
The TPS UI has been modified to provide a table as an interface to manage the user profiles. When adding a profile, the profile can be selected from a list of available profiles. The UserService and UGSubsystem have been modified to allow adding a user with no assigned profiles. https://fedorahosted.org/pki/ticket/1478
-rw-r--r--base/server/cms/src/org/dogtagpki/server/rest/UserService.java97
-rw-r--r--base/server/cmscore/src/com/netscape/cmscore/usrgrp/UGSubsystem.java86
-rw-r--r--base/server/share/webapps/pki/js/pki-ui.js8
-rw-r--r--base/tps/shared/webapps/tps/js/user.js194
-rw-r--r--base/tps/shared/webapps/tps/ui/user.html78
5 files changed, 357 insertions, 106 deletions
diff --git a/base/server/cms/src/org/dogtagpki/server/rest/UserService.java b/base/server/cms/src/org/dogtagpki/server/rest/UserService.java
index 53ecc2b9e..3de7384ee 100644
--- a/base/server/cms/src/org/dogtagpki/server/rest/UserService.java
+++ b/base/server/cms/src/org/dogtagpki/server/rest/UserService.java
@@ -39,9 +39,6 @@ import javax.ws.rs.core.Request;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
-import netscape.security.pkcs.PKCS7;
-import netscape.security.x509.X509CertImpl;
-
import org.apache.commons.lang.StringUtils;
import org.jboss.resteasy.plugins.providers.atom.Link;
import org.mozilla.jss.CryptoManager;
@@ -79,6 +76,9 @@ import com.netscape.cms.servlet.base.PKIService;
import com.netscape.cmsutil.util.Cert;
import com.netscape.cmsutil.util.Utils;
+import netscape.security.pkcs.PKCS7;
+import netscape.security.x509.X509CertImpl;
+
/**
* @author Endi S. Dewata
*/
@@ -209,6 +209,7 @@ public class UserService extends PKIService implements UserResource {
throw new BadRequestException(getUserMessage("CMS_ADMIN_SRVLT_NULL_RS_ID", headers));
}
+ IConfigStore cs = CMS.getConfigStore();
IUser user;
try {
@@ -237,17 +238,22 @@ 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);
- }
+ // TODO: refactor into TPSUserService
+ String csType = cs.getString("cs.type");
+ if (csType.equals("TPS")) {
- userData.setAttribute(ATTR_TPS_PROFILES, sb.toString());
+ 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;
@@ -363,15 +369,23 @@ public class UserService extends PKIService implements UserResource {
user.setState(state);
}
- String tpsProfiles = userData.getAttribute(ATTR_TPS_PROFILES);
- CMS.debug("TPS profiles: " + tpsProfiles);
+ // TODO: refactor into TPSUserService
String csType = cs.getString("cs.type");
- if (tpsProfiles != null) {
- if (!csType.equals("TPS")) {
- throw new BadRequestException("Cannot set tpsProfiles on a non-TPS subsystem");
+ if (csType.equals("TPS")) {
+
+ String tpsProfiles = userData.getAttribute(ATTR_TPS_PROFILES);
+ CMS.debug("TPS profiles: " + tpsProfiles);
+ if (tpsProfiles != null) { // update profiles if specified
+
+ String[] profiles;
+ if (StringUtils.isEmpty(tpsProfiles)) {
+ profiles = new String[0];
+ } else {
+ profiles = tpsProfiles.split(",");
+ }
+
+ user.setTpsProfiles(Arrays.asList(profiles));
}
- String[] profiles = tpsProfiles.split(",");
- user.setTpsProfiles(Arrays.asList(profiles));
}
userGroupManager.addUser(user);
@@ -443,11 +457,23 @@ public class UserService extends PKIService implements UserResource {
String state = userData.getState();
user.setState(state);
+ // TODO: refactor into TPSUserService
String csType = cs.getString("cs.type");
if (csType.equals("TPS")) {
+
String tpsProfiles = userData.getAttribute(ATTR_TPS_PROFILES);
- String[] profiles = tpsProfiles.split(",");
- user.setTpsProfiles(Arrays.asList(profiles));
+ CMS.debug("TPS Profiles: " + tpsProfiles);
+ if (tpsProfiles != null) { // update profiles if specified
+
+ String[] profiles;
+ if (StringUtils.isEmpty(tpsProfiles)) {
+ profiles = new String[0];
+ } else {
+ profiles = tpsProfiles.split(",");
+ }
+
+ user.setTpsProfiles(Arrays.asList(profiles));
+ }
}
userGroupManager.modifyUser(user);
@@ -485,6 +511,8 @@ public class UserService extends PKIService implements UserResource {
@Override
public Response modifyUser(String userID, UserData userData) {
+ CMS.debug("UserService.modifyUser(" + userID + ")");
+
if (userData == null) throw new BadRequestException("User data is null.");
// ensure that any low-level exceptions are reported
@@ -499,11 +527,13 @@ public class UserService extends PKIService implements UserResource {
IUser user = userGroupManager.createUser(userID);
String fullName = userData.getFullName();
+ CMS.debug("Full name: " + fullName);
if (fullName != null) {
user.setFullName(fullName);
}
String email = userData.getEmail();
+ CMS.debug("Email: " + email);
if (email != null) {
user.setEmail(email);
}
@@ -520,23 +550,34 @@ public class UserService extends PKIService implements UserResource {
}
String phone = userData.getPhone();
+ CMS.debug("Phone: " + phone);
if (phone != null) {
user.setPhone(phone);
}
String state = userData.getState();
+ CMS.debug("State: " + state);
if (state != null) {
user.setState(state);
}
- String tpsProfiles = userData.getAttribute(ATTR_TPS_PROFILES);
+ // TODO: refactor into TPSUserService
String csType = cs.getString("cs.type");
- if (tpsProfiles != null) {
- if (!csType.equals("TPS")) {
- throw new BadRequestException("Cannot set tpsProfiles on a non-TPS subsystem");
+ if (csType.equals("TPS")) {
+
+ String tpsProfiles = userData.getAttribute(ATTR_TPS_PROFILES);
+ CMS.debug("TPS Profiles: " + tpsProfiles);
+ if (tpsProfiles != null) { // update profiles if specified
+
+ String[] profiles;
+ if (StringUtils.isEmpty(tpsProfiles)) {
+ profiles = new String[0];
+ } else {
+ profiles = tpsProfiles.split(",");
+ }
+
+ user.setTpsProfiles(Arrays.asList(profiles));
}
- String[] profiles = tpsProfiles.split(",");
- user.setTpsProfiles(Arrays.asList(profiles));
}
userGroupManager.modifyUser(user);
diff --git a/base/server/cmscore/src/com/netscape/cmscore/usrgrp/UGSubsystem.java b/base/server/cmscore/src/com/netscape/cmscore/usrgrp/UGSubsystem.java
index d1277279e..a11c551e5 100644
--- a/base/server/cmscore/src/com/netscape/cmscore/usrgrp/UGSubsystem.java
+++ b/base/server/cmscore/src/com/netscape/cmscore/usrgrp/UGSubsystem.java
@@ -25,19 +25,6 @@ import java.util.Enumeration;
import java.util.List;
import java.util.Vector;
-import netscape.ldap.LDAPAttribute;
-import netscape.ldap.LDAPAttributeSet;
-import netscape.ldap.LDAPConnection;
-import netscape.ldap.LDAPDN;
-import netscape.ldap.LDAPEntry;
-import netscape.ldap.LDAPException;
-import netscape.ldap.LDAPModification;
-import netscape.ldap.LDAPModificationSet;
-import netscape.ldap.LDAPSearchConstraints;
-import netscape.ldap.LDAPSearchResults;
-import netscape.ldap.LDAPv2;
-import netscape.security.x509.X509CertImpl;
-
import org.apache.commons.lang.StringUtils;
import com.netscape.certsrv.apps.CMS;
@@ -60,6 +47,19 @@ import com.netscape.cmscore.ldapconn.LdapBoundConnFactory;
import com.netscape.cmscore.util.Debug;
import com.netscape.cmsutil.ldap.LDAPUtil;
+import netscape.ldap.LDAPAttribute;
+import netscape.ldap.LDAPAttributeSet;
+import netscape.ldap.LDAPConnection;
+import netscape.ldap.LDAPDN;
+import netscape.ldap.LDAPEntry;
+import netscape.ldap.LDAPException;
+import netscape.ldap.LDAPModification;
+import netscape.ldap.LDAPModificationSet;
+import netscape.ldap.LDAPSearchConstraints;
+import netscape.ldap.LDAPSearchResults;
+import netscape.ldap.LDAPv2;
+import netscape.security.x509.X509CertImpl;
+
/**
* This class defines low-level LDAP usr/grp management
* usr/grp information is located remotely on another
@@ -738,11 +738,15 @@ 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));
+ List<String> profiles = id.getTpsProfiles();
+ if (profiles != null && profiles.size() > 0) {
+ CMS.debug("Adding " + LDAP_ATTR_PROFILE_ID + ":");
+ LDAPAttribute attr = new LDAPAttribute(LDAP_ATTR_PROFILE_ID);
+ for (String profile : profiles) {
+ CMS.debug(" - " + profile);
+ attr.addValue(profile);
}
+ attrs.add(attr);
}
LDAPEntry entry = new LDAPEntry("uid=" + LDAPUtil.escapeRDNValue(id.getUserID()) +
@@ -763,12 +767,14 @@ public final class UGSubsystem implements IUGSubsystem {
ldapconn.add(entry);
} catch (LDAPException e) {
+ CMS.debug(e);
log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_USRGRP_ADD_USER", e.toString()));
throw LDAPExceptionConverter.toPKIException(e);
} catch (ELdapException e) {
+ CMS.debug(e);
log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_USRGRP_ADD_USER", e.toString()));
- throw new EUsrGrpException(CMS.getUserMessage("CMS_USRGRP_ADD_USER_FAIL"));
+ throw new EUsrGrpException(CMS.getUserMessage("CMS_USRGRP_ADD_USER_FAIL"), e);
} finally {
if (ldapconn != null)
@@ -1229,7 +1235,8 @@ public final class UGSubsystem implements IUGSubsystem {
}
}
- if (user.getTpsProfiles() != null) {
+ List<String> profiles = user.getTpsProfiles();
+ if (profiles != null) {
// TODO add audit logging for profile
// replace the objectclass in case tpsProfile is not present
@@ -1238,44 +1245,11 @@ public final class UGSubsystem implements IUGSubsystem {
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));
- }
- }
+ LDAPAttribute attr = new LDAPAttribute(LDAP_ATTR_PROFILE_ID);
+ for (String profile : profiles) {
+ attr.addValue(profile);
}
+ attrs.add(LDAPModification.REPLACE, attr);
}
/**
diff --git a/base/server/share/webapps/pki/js/pki-ui.js b/base/server/share/webapps/pki/js/pki-ui.js
index 2fa47ccc4..cf4b44e24 100644
--- a/base/server/share/webapps/pki/js/pki-ui.js
+++ b/base/server/share/webapps/pki/js/pki-ui.js
@@ -621,7 +621,7 @@ var Table = Backbone.View.extend({
// check filter against all values in the entry
var matches = false;
_(entry).each(function(value, key) {
- if (entry.name.indexOf(filter) >= 0) matches = true;
+ if (value && value.indexOf(filter) >= 0) matches = true;
});
return matches;
@@ -704,7 +704,7 @@ var Table = Backbone.View.extend({
// save new entry
dialog.save();
- self.entries.push(dialog.entry);
+ self.addEntry(dialog.entry);
// redraw table
self.render();
@@ -713,6 +713,10 @@ var Table = Backbone.View.extend({
dialog.open();
},
+ addEntry: function(entry) {
+ var self = this;
+ self.entries.push(entry);
+ },
remove: function(items) {
var self = this;
diff --git a/base/tps/shared/webapps/tps/js/user.js b/base/tps/shared/webapps/tps/js/user.js
index 3a29f1dd1..663b66fc5 100644
--- a/base/tps/shared/webapps/tps/js/user.js
+++ b/base/tps/shared/webapps/tps/js/user.js
@@ -86,41 +86,199 @@ var UserCollection = Collection.extend({
}
});
-var UserPage = EntryPage.extend({
+var UserProfilesTableItem = TableItem.extend({
initialize: function(options) {
var self = this;
- UserPage.__super__.initialize.call(self, options);
+ UserProfilesTableItem.__super__.initialize.call(self, options);
},
- loadField: function(input) {
+ renderColumn: function(td, templateTD) {
var self = this;
- var name = input.attr("name");
- if (name != "tpsProfiles") {
- UserPage.__super__.loadField.call(self, input);
- return;
- }
+ UserProfilesTableItem.__super__.renderColumn.call(self, td, templateTD);
- var attributes = self.entry.attributes;
- if (attributes) {
- var value = attributes.tpsProfiles;
- input.val(value);
+ $("a", td).click(function(e) {
+ e.preventDefault();
+ self.table.open(self);
+ });
+ }
+});
+
+var UserProfilesTable = Table.extend({
+ initialize: function(options) {
+ var self = this;
+ options.tableItem = UserProfilesTableItem;
+ UserProfilesTable.__super__.initialize.call(self, options);
+ },
+ sort: function() {
+ var self = this;
+
+ // sort profiles by id
+ self.filteredEntries = _.sortBy(self.filteredEntries, function(entry) {
+ return entry.id;
+ });
+ },
+ add: function() {
+ var self = this;
+
+ profiles = new ProfileCollection();
+ profiles.fetch({
+ success: function(collection, response, options) {
+
+ var dialog = self.addDialog;
+ var select = dialog.$(".modal-body select").empty();
+
+ $('<option/>', {
+ text: 'All Profiles',
+ selected: true
+ }).appendTo(select);
+
+ profiles.each(function(profile) {
+
+ if (_.find(self.entries, function(e) { return e.id == profile.id; })) {
+ // profile already exists
+
+ } else {
+ // show profile option
+ $('<option/>', {
+ text: profile.id
+ }).appendTo(select);
+ }
+ });
+
+ UserProfilesTable.__super__.add.call(self);
+ }
+ });
+ },
+ addEntry: function(entry) {
+ var self = this;
+
+ if (entry.id == 'All Profiles') {
+ // replace existing profiles
+ self.entries = [];
+ self.entries.push(entry);
+
+ } else if (_.find(self.entries, function(e) { return e.id == entry.id; })) {
+ // profile already exists
+
+ } else {
+ // add new profile
+ self.entries.push(entry);
}
},
- saveField: function(input) {
+ remove: function(items) {
var self = this;
- var name = input.attr("name");
- if (name != "tpsProfiles") {
- UserPage.__super__.saveField.call(self, input);
- return;
+ // remove selected profiles
+ self.entries = _.reject(self.entries, function(entry) {
+ return _.contains(items, entry.id);
+ });
+
+ // redraw table
+ self.render();
+ },
+ renderControls: function() {
+ var self = this;
+
+ UserProfilesTable.__super__.renderControls.call(self);
+
+ if (self.mode == "edit") {
+
+ if (_.find(self.entries, function(e) { return e.id == 'All Profiles'; })) {
+ self.addButton.hide();
+
+ } else {
+ self.addButton.show();
+ }
}
+ }
+});
+
+var UserPage = EntryPage.extend({
+ initialize: function(options) {
+ var self = this;
+ UserPage.__super__.initialize.call(self, options);
+ },
+ setup: function() {
+ var self = this;
+
+ UserPage.__super__.setup.call(self);
+
+ var dialog = self.$("#user-profile-dialog");
+
+ var addDialog = new Dialog({
+ el: dialog,
+ title: "Add Profile",
+ actions: ["cancel", "add"]
+ });
+
+ self.profilesSection = self.$("[name='profiles']");
+ self.profilesList = $("[name='list']", self.profilesSection);
+
+ self.profilesTable = new UserProfilesTable({
+ el: self.profilesList,
+ addDialog: addDialog,
+ pageSize: 10,
+ parent: self
+ });
+
+ },
+ saveFields: function() {
+ var self = this;
+
+ UserPage.__super__.saveFields.call(self);
var attributes = self.entry.attributes;
if (attributes == undefined) {
attributes = {};
self.entry.attributes = attributes;
}
- attributes.tpsProfiles = input.val();
+ attributes.tpsProfiles = self.getProfiles().join();
+ },
+ renderContent: function() {
+ var self = this;
+
+ UserPage.__super__.renderContent.call(self);
+
+ if (self.mode == "add") {
+ self.profilesTable.mode = "edit";
+
+ } else if (self.mode == "edit") {
+ self.profilesTable.mode = "edit";
+
+ } else { // self.mode == "view"
+ self.profilesTable.mode = "view";
+ }
+
+ var profiles = [];
+ var attributes = self.entry.attributes;
+ if (attributes) {
+ var value = attributes.tpsProfiles;
+ if (value) {
+ profiles = value.split(',');
+ }
+ }
+
+ self.setProfiles(profiles);
+ },
+ setProfiles: function(profiles) {
+ var self = this;
+
+ self.profilesTable.entries = [];
+ _.each(profiles, function(profile) {
+ self.profilesTable.entries.push({ id: profile });
+ });
+
+ self.profilesTable.render();
+ },
+ getProfiles: function() {
+ var self = this;
+
+ var profiles = [];
+ _.each(self.profilesTable.entries, function(profile) {
+ profiles.push(profile.id);
+ });
+
+ return profiles;
}
});
diff --git a/base/tps/shared/webapps/tps/ui/user.html b/base/tps/shared/webapps/tps/ui/user.html
index 9a9f9505b..79867f900 100644
--- a/base/tps/shared/webapps/tps/ui/user.html
+++ b/base/tps/shared/webapps/tps/ui/user.html
@@ -51,7 +51,81 @@
<input name="type" readonly="readonly"><br>
<label>State</label>
<input name="state" readonly="readonly"><br>
- <label>TPS Profiles</label>
- <input name="tpsProfiles" readonly="readonly"><br>
</fieldset>
</div>
+
+<div name="profiles">
+
+<h2>Profiles</h2>
+
+<table name="list">
+<thead>
+ <tr>
+ <th class="pki-table-actions" colspan="2">
+ <span name="search">
+ <input name="search" type="text" placeholder="Search...">
+ </span>
+ <span class="pki-table-buttons">
+ <button name="add">Add</button>
+ <button name="remove">Remove</button>
+ </span>
+ </th>
+ </tr>
+ <tr>
+ <th class="pki-select-column"><input id="user-profiles-selectall" type="checkbox"><label for="user-profiles-selectall">&nbsp;</label></th>
+ <th>Profile ID</th>
+ </tr>
+</thead>
+<tbody>
+ <tr>
+ <td class="pki-select-column"><input id="user-profiles-select" type="checkbox"><label for="user-profiles-select">&nbsp;</label></td>
+ <td name="id">${id}</td>
+ </tr>
+</tbody>
+<tfoot>
+ <tr>
+ <th class="pki-table-actions" colspan="2">
+ <div class="pki-table-info">
+ Total: <span name="totalEntries">0</span> entries
+ </div>
+ <div class="pki-page-controls">
+ <ul class="pagination">
+ <li><a href="#" name="first"><span class="i fa fa-angle-double-left"></span></a></li>
+ <li><a href="#" name="prev"><span class="i fa fa-angle-left"></span></a></li>
+ </ul>
+ <span class="pki-page-jump">
+ <input name="page" type="text" value="1"> of <span name="totalPages">1</span>
+ </span>
+ <ul class="pagination">
+ <li><a href="#" name="next"><span class="i fa fa-angle-right"></span></a></li>
+ <li><a href="#" name="last"><span class="i fa fa-angle-double-right"></span></a></li>
+ </ul>
+ </div>
+ </th>
+ </tr>
+</tfoot>
+</table>
+
+</div>
+
+<div id="user-profile-dialog" class="modal">
+ <div class="modal-dialog">
+ <div class="modal-content">
+ <div class="modal-header">
+ <button type="button" class="close" data-dismiss="modal" aria-hidden="true">
+ <span class="pficon pficon-close"></span>
+ </button>
+ <h4 class="modal-title">Add Profile</h4>
+ </div>
+ <div class="modal-body">
+ Profile:
+ <select name="id">
+ </select>
+ </div>
+ <div class="modal-footer">
+ <button name="add" class="btn btn-primary">Add</button>
+ <button name="cancel" class="btn btn-default" data-dismiss="modal">Cancel</button>
+ </div>
+ </div>
+ </div>
+</div>