Przeglądaj źródła

[security] Display and edition template for Sentry privileges

Romain Rigaux 11 lat temu
rodzic
commit
d0cce56

+ 36 - 31
apps/security/src/security/api/hive.py

@@ -28,25 +28,7 @@ def list_sentry_roles_by_group(request):
 
   try:
     roles = get_api(request.user).list_sentry_roles_by_group()
-    result['roles'] = roles
-    result['message'] = ''
-    result['status'] = 0
-  except Exception, e:
-    result['message'] = unicode(str(e), "utf8")
-
-  return HttpResponse(json.dumps(result), mimetype="application/json")
-
-
-def list_sentry_privileges_for_provider(request):
-  result = {'status': -1, 'message': 'Error'}
-
-  try:
-    groups = json.loads(request.POST['groups'])
-    roleSet = json.loads(request.POST['roleSet'])
-    authorizableHierarchy = json.loads(request.POST['authorizableHierarchy'])
-
-    sentry_privileges = get_api(request.user).list_sentry_privileges_for_provider(groups=groups, roleSet=roleSet, authorizableHierarchy=authorizableHierarchy)
-    result['sentry_privileges'] = sentry_privileges
+    result['roles'] = sorted(roles, key= lambda role: role['name'])
     result['message'] = ''
     result['status'] = 0
   except Exception, e:
@@ -76,14 +58,15 @@ def _hive_add_privileges(user, role, privileges):
     _priviledges = {}
 
     for priviledge in privileges:
-      api.alter_sentry_role_grant_privilege(role['name'], {
-          'privilegeScope': priviledge['privilegeScope'],
-          'serverName': priviledge['serverName'],
-          'dbName': priviledge['dbName'],
-          'tableName': priviledge['tableName'],
-          'URI': priviledge['URI'],
-          'action': priviledge['action']
-      })
+      if priviledge['status'] not in ('deleted'):
+        api.alter_sentry_role_grant_privilege(role['name'], {
+            'privilegeScope': priviledge['privilegeScope'],
+            'serverName': priviledge['serverName'],
+            'dbName': priviledge['dbName'],
+            'tableName': priviledge['tableName'],
+            'URI': priviledge['URI'],
+            'action': priviledge['action']
+        })
 
     return _priviledges
 
@@ -165,11 +148,15 @@ def list_sentry_privileges_by_authorizable(request):
     roleSet = json.loads(request.POST['roleSet'])
     authorizableHierarchy = json.loads(request.POST['authorizableHierarchy'])
 
-    from collections import defaultdict
-    d = defaultdict(int)
-    d.update(authorizableHierarchy)
+    privileges = []
+    roles = get_api(request.user).list_sentry_roles_by_group()
 
-    result['privileges'] = json.loads('{"status": 0, "sentry_privileges": [{"name": "serverA+databaseA+tableA+INSERT", "timestamp": 1404171968718, "database": "databaseA", "action": "INSERT", "scope": "TABLE", "table": "tableA", "URI": "", "grantor": null, "server": "serverA"},{"name": "%(server)s+%(database)s+%(table)s+INSERT", "timestamp": 1404171968718, "database": "%(database)s", "action": "INSERT", "scope": "TABLE", "table": "%(table)s", "URI": "", "grantor": null, "server": "%(server)s"}], "message": ""}' % d)
+    for role in roles:
+      for privilege in get_api(request.user).list_sentry_privileges_by_role(role['name']): # authorizableHierarchy not working here?
+        if privilege['database'] == authorizableHierarchy['db'] and ('table' not in authorizableHierarchy or privilege['table'] == authorizableHierarchy['table']): 
+          privileges.append(privilege)
+    
+    result['privileges'] = privileges
 
     result['message'] = ''
     result['status'] = 0
@@ -177,3 +164,21 @@ def list_sentry_privileges_by_authorizable(request):
     result['message'] = unicode(str(e), "utf8")
 
   return HttpResponse(json.dumps(result), mimetype="application/json")
+
+
+def list_sentry_privileges_for_provider(request):
+  result = {'status': -1, 'message': 'Error'}
+
+  try:
+    groups = json.loads(request.POST['groups'])
+    roleSet = json.loads(request.POST['roleSet'])
+    authorizableHierarchy = json.loads(request.POST['authorizableHierarchy'])
+
+    sentry_privileges = get_api(request.user).list_sentry_privileges_for_provider(groups=groups, roleSet=roleSet, authorizableHierarchy=authorizableHierarchy)
+    result['sentry_privileges'] = sentry_privileges
+    result['message'] = ''
+    result['status'] = 0
+  except Exception, e:
+    result['message'] = unicode(str(e), "utf8")
+
+  return HttpResponse(json.dumps(result), mimetype="application/json")

+ 1 - 0
apps/security/src/security/templates/hdfs.mako

@@ -118,6 +118,7 @@ ${ layout.menubar(section='hdfs') }
             <i class="fa fa-refresh"></i>
             ${ _('View as') }
             <input type="text" class="user-list input-small" data-bind="value: $root.doAs">
+            <i class="fa fa-group"></i>
           </div>
           ${ _('HDFS ACLs') }
         </h1>

+ 64 - 35
apps/security/src/security/templates/hive.mako

@@ -26,13 +26,43 @@ ${ commonheader(_('Hadoop Security'), "security", user) | n,unicode }
 ${ layout.menubar(section='hive') }
 
 
-<script type="text/html" id="privilege-template">
-  <select data-bind="options: availablePrivileges, value: privilegeScope"></select>
-  <input type="text" data-bind="value: $data.serverName" placeholder="serverName"></input>
-  <input type="text" data-bind="value: $data.dbName" placeholder="dbName"></input>
-  <input type="text" data-bind="value: $data.tableName" placeholder="tableName"></input>
-  <input type="text" data-bind="value: $data.URI" placeholder="URI"></input>
-  <i class="fa fa-minus"></i>
+<script type="text/html" id="privilege">
+  <!-- ko if: edition() -->
+    <div data-bind="template: { name: 'edit-privilege'}"></div>
+  <!-- /ko -->
+  
+  <!-- ko ifnot: edition() -->
+    <div data-bind="template: { name: 'display-privilege'}"></div>
+  <!-- /ko -->  
+</script>
+
+
+<script type="text/html" id="edit-privilege">
+  <div data-bind="visible: status() != 'deleted'">
+    <select data-bind="options: availablePrivileges, value: privilegeScope"></select>
+    <input type="text" data-bind="value: $data.serverName" placeholder="serverName"></input>
+    <input type="text" data-bind="value: $data.dbName" placeholder="dbName"></input>
+    <input type="text" data-bind="value: $data.tableName" placeholder="tableName"></input>
+    <input type="text" data-bind="value: $data.URI" placeholder="URI"></input>
+    <input type="text" data-bind="value: $data.action" placeholder="action"></input>
+    <a href="javascript:void(0)"><i class="fa fa-minus" data-bind="click: remove"></i></a>
+  </div>
+</script>
+
+
+<script type="text/html" id="display-privilege">
+  <div data-bind="visible: status() != 'deleted', with: $data.properties">
+    <span data-bind="text: name"></span>
+    <span data-bind="text: timestamp"></span>
+    <a data-bind="attr: { href: '/metastore/' + database() }" target="_blank"><span data-bind="text: database"></span></a>
+    <span data-bind="text: action"></span>
+    <span data-bind="text: scope"></span>
+    <span data-bind="text: table"></span>
+    <span data-bind="text: URI"></span>
+    <span data-bind="text: grantor"></span>
+    <span data-bind="text: server"></span>
+    <span data-bind="text: ko.mapping.toJSON($data)"></span> <a href="javascript:void(0);"><i class="fa fa-minus"></i></a>
+  </div>
 </script>
 
 
@@ -101,9 +131,12 @@ ${ layout.menubar(section='hive') }
 		    </%def>
 		
 		    <%def name="actions()">
+              <div class="btn-toolbar" style="display: inline; vertical-align: middle">
+                <button class="btn toolbarBtn"><i class="fa fa-pencil"></i> ${ _('Edit') }</button>
+              </div>
 		      <div class="btn-toolbar" style="display: inline; vertical-align: middle">
-		        <button class="btn toolbarBtn" id="submit-btn" disabled="disabled"><i class="fa fa-times"></i> ${ _('Delete') }</button>
-		      </div>
+		        <button class="btn toolbarBtn"><i class="fa fa-times"></i> ${ _('Delete') }</button>
+		      </div>		      
 		    </%def>
 		
 		    <%def name="creation()">
@@ -117,11 +150,11 @@ ${ layout.menubar(section='hive') }
           <div data-bind="with: $root.role, visible: showCreateRole">
             <div class="span3">
               Name
-              <input type="text" data-bind="value: $data.name"></input>
+              <input type="text" class="input-small" data-bind="value: $data.name"></input>
             </div>
             <div class="span5">
               Privileges
-              <div data-bind="template: { name: 'privilege-template', foreach: privileges}">
+              <div data-bind="template: { name: 'edit-privilege', foreach: privileges}">
               </div>
               <a href="javascript: void(0)" data-bind="click: addPrivilege">
                 <i class="fa fa-plus"></i>
@@ -171,35 +204,31 @@ ${ layout.menubar(section='hive') }
                 <a href=""><span data-bind="text: grantorPrincipal"></span></a>
               </td>
             </tr>
-            <tr data-bind="foreach: $data.privileges, visible: $data.showPrivileges">
+            
+            <!-- ko if: $data.showPrivileges -->
+            <!-- ko foreach: $data.privileges -->
+            <tr>
               <td colspan="2"></td>
               <td colspan="3">
-                <span data-bind="text: name"></span>
-                <span data-bind="text: timestamp"></span>
-                <a data-bind="attr: { href: '/metastore/' + database() }" target="_blank"><span data-bind="text: database"></span></a>
-                <span data-bind="text: action"></span>
-                <span data-bind="text: scope"></span>
-                <span data-bind="text: table"></span>
-                <span data-bind="text: URI"></span>
-                <span data-bind="text: grantor"></span>
-                <span data-bind="text: server"></span>
-                <span data-bind="text: ko.mapping.toJSON($data)"></span> <a href="javascript:void(0);"><i class="fa fa-minus"></i></a>
+                <div data-bind="template: { name: 'privilege'}"></div>
               </td>
             </tr>
-            <tr data-bind="visible: $data.showPrivileges">
+            <!-- /ko -->
+            <!-- /ko -->
+            <tr>
               <td colspan="2"></td>
-              <td>
-                <div data-bind="template: { name: 'privilege-template', foreach: newPrivileges }">
-                </div>
-                <div data-bind="visible: newPrivileges().length > 0">
-		          <button type="button" rel="tooltip" data-placement="bottom" data-loading-text="${ _('Saving...') }" data-original-title="${ _('Save') }" class="btn"
-		              data-bind="click: $root.role.saveNewPrivileges">
-		            <i class="fa fa-save"></i>
-		          </button>
-                </div>
-                <a href="javascript:void(0)" data-bind="click: $root.role.addNewPrivilege">
-                  <i class="fa fa-plus"></i>
-                </a>
+              <td colspan="3">
+              <a href="javascript: void(0)" data-bind="click: addPrivilege, visible: $data.showPrivileges">
+                <i class="fa fa-plus"></i>
+              </a>
+              </td>
+            </tr>
+            <tr data-bind="visible: privilegesChanged().length">
+              <td colspan="5">
+                <button type="button" rel="tooltip" data-placement="bottom" data-loading-text="${ _('Saving...') }" data-original-title="${ _('Save') }" class="btn"
+                  data-bind="click: $root.role.create">
+                  <i class="fa fa-save"></i>
+                </button>
               </td>
             </tr>
           </div>

+ 1 - 0
apps/security/src/security/templates/layout.mako

@@ -51,6 +51,7 @@ def is_selected(section, matcher):
         <div class="container-fluid">
           <div class="nav-collapse">
 			<div class="pull-right" style="padding-right:50px; padding-top:10px">
+              <button type="button" title="${ _('Edit') }" rel="tooltip" data-placement="bottom" data-bind="css: {'btn': true, 'btn-inverse': true}"><i class="fa fa-pencil"></i></button>
 			</div>
             <ul class="nav">
               <li class="currentApp">

+ 1 - 1
apps/security/static/js/hdfs.ko.js

@@ -106,7 +106,7 @@ var Assist = function (vm, assist) {
   self.originalAcls = ko.observableArray();
   self.regularAcls = ko.computed(function () {
     return $.grep(self.acls(), function (acl) {
-      return !acl.isDefault();
+      return ! acl.isDefault();
     });
   });
   self.defaultAcls = ko.computed(function () {

+ 36 - 17
apps/security/static/js/hive.ko.js

@@ -15,9 +15,6 @@
 // limitations under the License.
 
 
-// groups, privileges
-
-
 var Privilege = function (vm, privilege) {
   var self = this;
 
@@ -28,17 +25,34 @@ var Privilege = function (vm, privilege) {
   self.URI = ko.observable(typeof privilege.URI != "undefined" && privilege.URI != null ? privilege.URI : "");
   self.action = ko.observable(typeof privilege.action != "undefined" && privilege.action != null ? privilege.action : "");
 
+  self.status = ko.observable(typeof privilege.status != "undefined" && privilege.status != null ? privilege.status : "");
+  self.edition = ko.observable(typeof privilege.edition != "undefined" && privilege.edition != null ? privilege.edition : false);
+
   self.availablePrivileges = ko.observableArray(['SERVER', 'DATABASE', 'TABLE']);
   self.availableActions = ko.observableArray(['SELECT', 'INSERT', 'ALL', '']);
+  
+  self.remove = function(privilege) {
+	privilege.status('deleted');
+  }
 }
 
-var Role = function(vm, privilege) {
+var Role = function(vm, role) {
   var self = this;
 
-  self.name = ko.observable('');
+  self.name = ko.observable(typeof role.name != "undefined" && role.name != null ? role.name : "");
+  self.grantorPrincipal = ko.observable(typeof role.grantorPrincipal != "undefined" && role.grantorPrincipal != null ? role.grantorPrincipal : "");
   self.groups = ko.observableArray();
-  self.privileges = ko.observableArray();
+  $.each(typeof role.groups != "undefined" && role.groups != null ? role.groups : [], function(index, group) {
+	self.groups.push(group);
+  });
+  self.privileges = ko.observableArray(); // Not included in the API
+  self.showPrivileges = ko.observable(false);
 
+  self.privilegesChanged = ko.computed(function () {
+    return $.grep(self.privileges(), function (privilege) {
+      return ['new', 'deleted', 'modified'].indexOf(privilege.status()) != -1;
+    });
+  });  
 
   self.reset = function() {
 	self.name('');
@@ -51,7 +65,7 @@ var Role = function(vm, privilege) {
   }
 
   self.addPrivilege = function() {
-	self.privileges.push(new Privilege(vm, {}));
+	self.privileges.push(new Privilege(vm, {'serverName': vm.assist.server(), 'status': 'new', 'edition': true}));
   }
 
   self.create = function() {
@@ -62,7 +76,6 @@ var Role = function(vm, privilege) {
         if (data.status == 0) {
           $(document).trigger("info", data.message);
           data.role['privileges'] = ko.observableArray();
-          data.role['newPrivileges'] = ko.observableArray();
           data.role['showPrivileges'] = ko.observable(false);
           vm.roles.unshift(data.role);
           self.reset();
@@ -93,9 +106,9 @@ var Role = function(vm, privilege) {
     });
   }
 
-  self.addNewPrivilege = function(role) {
-    role['newPrivileges'].push(new Privilege(self, {}));
-  }
+  /**self.addNewPrivilege = function(role) {
+    role['newPrivileges'].push(new Privilege(vm, {'serverName': vm.assist.server()}));
+  }*/
 
   self.saveNewPrivileges = function(role) {
 	$(".jHueNotify").hide();
@@ -171,7 +184,7 @@ var HiveViewModel = function (initial) {
 
   // Edition
   self.showCreateRole = ko.observable(false);
-  self.role = new Role(self);
+  self.role = new Role(self, {});
   self.privilege = new Privilege(self, {});
 
   self.doAs = ko.observable('');
@@ -200,10 +213,7 @@ var HiveViewModel = function (initial) {
     $.getJSON('/security/api/hive/list_sentry_roles_by_group', {    	
       }, function (data) {
         $.each(data.roles, function(index, item) {
-          item['privileges'] = ko.observableArray();
-          item['showPrivileges'] = ko.observable(false);
-          item['newPrivileges'] = ko.observableArray();
-    	  self.roles.push(item);
+    	  self.roles.push(new Role(self, item));
         });
     }).fail(function (xhr, textStatus, errorThrown) {
       $(document).trigger("error", xhr.responseText);
@@ -220,7 +230,16 @@ var HiveViewModel = function (initial) {
       success: function (data) {
     	role.privileges.removeAll();
         $.each(data.sentry_privileges, function(index, item) {
-          role.privileges.push(ko.mapping.fromJS(item));
+          var privilege = new Privilege(self, {
+        	  'privilegeScope': item.scope,
+               'serverName': item.server,
+               'dbName': item.database,
+               'tableName': item.table,
+               'URI': item.URI,
+               'action': item.action
+          });
+          privilege.properties = ko.mapping.fromJS(item);
+          role.privileges.push(privilege);
         });
         role.showPrivileges(true);
       }

+ 14 - 14
desktop/libs/libsentry/src/libsentry/api.py

@@ -98,13 +98,13 @@ class SentryApi(object):
     response = self.client.list_sentry_roles_by_group()
     
     if response.status.value == 0:
-      roles = {}
+      roles = []
       for role in response.roles:
-        roles[role.roleName] = {
+        roles.append({
           'name': role.roleName,
           'grantorPrincipal': role.grantorPrincipal,
           'groups': [group.groupName for group in role.groups]
-        }
+        })
       return roles
     else:
       raise SentryException(response)  
@@ -114,7 +114,7 @@ class SentryApi(object):
     response = self.client.list_sentry_privileges_by_role(roleName, authorizableHierarchy)
     
     if response.status.value == 0:
-      return [self._massage_priviledges(privilige) for privilige in response.privileges]
+      return [self._massage_priviledges(privilege) for privilege in response.privileges]
     else:
       raise SentryException(response)
     
@@ -128,15 +128,15 @@ class SentryApi(object):
       raise SentryException(response)
     
     
-  def _massage_priviledges(self, privilige):
+  def _massage_priviledges(self, privilege):
     return {
-        'scope': privilige.privilegeScope,
-        'name': privilige.privilegeName,
-        'server': privilige.serverName,
-        'database': privilige.dbName,
-        'table': privilige.tableName,
-        'URI': privilige.URI,
-        'action': privilige.action,
-        'timestamp': privilige.createTime,
-        'grantor': privilige.grantorPrincipal
+        'scope': privilege.privilegeScope,
+        'name': privilege.privilegeName,
+        'server': privilege.serverName,
+        'database': privilege.dbName,
+        'table': privilege.tableName,
+        'URI': privilege.URI,
+        'action': privilege.action,
+        'timestamp': privilege.createTime,
+        'grantor': privilege.grantorPrincipal
     }