Jelajahi Sumber

[security] Create a Hive role section

Romain Rigaux 11 tahun lalu
induk
melakukan
45a2bc34e9

+ 41 - 13
apps/security/src/security/api.py

@@ -18,6 +18,8 @@
 import json
 
 from django.http import HttpResponse
+from django.utils.translation import ugettext as _
+
 from libsentry.api import get_api
 
 
@@ -78,19 +80,12 @@ def list_sentry_privileges_by_role(request):
   return HttpResponse(json.dumps(result), mimetype="application/json")
 
 
-def hive_edit_role(request):  
-  result = {'status': -1, 'message': 'Error'}
-
-  try:
-    role = json.loads(request.POST['role'])
-    
+def _hive_add_privileges(role, privileges):  
     api = get_api(request.user)
-    
-    try:
-      api.create_sentry_role(role['name'])
-    except Exception, e:
-      print e
-    for priviledge in role['priviledges']:
+  
+    _priviledges = {}
+  
+    for priviledge in privileges:
       api.alter_sentry_role_grant_privilege(role['name'], {
           'privilegeScope': priviledge['privilegeScope'],
           'serverName': priviledge['serverName'],
@@ -99,8 +94,41 @@ def hive_edit_role(request):
           'URI': priviledge['URI'],
           'action': priviledge['action']
       })
+  
+    
+    return _priviledges
+
+
+def hive_create_role(request):  
+  result = {'status': -1, 'message': 'Error'}
+
+  try:
+    role = json.loads(request.POST['role'])
+    
+    api = get_api(request.user)
+  
+    api.create_sentry_role(role['name'])
+    result['privileges'] = _hive_add_privileges(role, role['privileges'])
     api.alter_sentry_role_add_groups(role['name'], role['groups'])
 
+    result['role'] = {"name": role['name'], "groups": [], "grantorPrincipal": request.user.username}
+
+    result['message'] = ''
+    result['status'] = 0
+  except Exception, e:
+    result['message'] = unicode(str(e), "utf8")
+
+  return HttpResponse(json.dumps(result), mimetype="application/json")
+
+
+def hive_add_privileges(request):  
+  result = {'status': -1, 'message': 'Error'}
+
+  try:
+    role = json.loads(request.POST['role'])
+
+    result['privileges'] = _hive_add_privileges(role, role['newPrivileges'])
+
     result['message'] = ''
     result['status'] = 0
   except Exception, e:
@@ -146,7 +174,7 @@ def drop_sentry_role(request):
     roleName = request.POST['roleName']
 
     get_api(request.user).drop_sentry_role(roleName)
-    result['message'] = ''
+    result['message'] = _('Role and privileges deleted.')
     result['status'] = 0
   except Exception, e:
     result['message'] = unicode(str(e), "utf8")

+ 114 - 50
apps/security/src/security/templates/hive.mako

@@ -19,23 +19,37 @@ from desktop.views import commonheader, commonfooter
 from django.utils.translation import ugettext as _
 %>
 
-
+<%namespace name="actionbar" file="actionbar.mako" />
 <%namespace name="layout" file="layout.mako" />
 
 ${ 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>
+
+
 <div class="container-fluid">
   <div class="row-fluid">
     <div class="span2">
       <div class="sidebar-nav">
         <ul class="nav nav-list">
           <li class="nav-header">${ _('Properties') }</li>
-          <li class="active"><a href="#edit"><i class="fa fa-pencil"></i> ${ _('Edit') }</a></li>
-          <li><a href="#view"><i class="fa fa-eye"></i> ${ _('View') }</a></li>
-          <li><a href="#roles"><i class="fa fa-group"></i> ${ _('Roles') }</a></li>
-          <li><a href="#privileges"><i class="fa fa-cubes"></i> ${ _('Privileges') }</a></li>
+          <li class="active"><a href="#edit"><i class="fa fa-eye"></i> ${ _('View') }</a></li>
+          <li><a href="#roles"><i class="fa fa-cubes"></i> ${ _('Roles') }</a></li>
+          <li class="nav-header"><i class="fa fa-group"></i> ${ _('Groups') }
+            </br>
+            <input type="checkbox" checked></input> All
+            </br>
+            <select data-bind="options: $root.availableHadoopGroups" size="10" multiple="true"></select>            
+          </li>
         </ul>
       </div>
     </div>
@@ -57,63 +71,113 @@ ${ layout.menubar(section='hive') }
             </div>
           </div>
         </div>        
-                      
-        <div class="card-body">               
-          <div data-bind="with: $root.role">
-            Privileges
-            <div>
-              <div data-bind="foreach: priviledges">
-                <select data-bind="options: availablePriviledges, 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>
-                <select data-bind="options: availableActions, value: action"></select>
-                <i class="fa fa-minus"></i>
+      </div>
+
+      <div id="roles" class="mainSection hide card card-small">      
+        <div class="card-heading simple">
+        <h3>${ _('Roles') }</h3>
+		  <%actionbar:render>
+		    <%def name="search()">
+		      <input id="filterInput" type="text" class="input-xlarge search-query" placeholder="${_('Search for name, groups, etc...')}">
+		    </%def>
+		
+		    <%def name="actions()">
+		      <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>
+		    </%def>
+		
+		    <%def name="creation()">
+		      <a href="javascript: void(0)" data-bind="click: function(){ $root.showCreateRole(true); }" class="btn"><i class="fa fa-plus-circle"></i> ${ _('Add') }</a>
+		    </%def>
+		  </%actionbar:render>        
+        </div>
+          
+          
+        <div class="card-body">                       
+          <div data-bind="with: $root.role, visible: showCreateRole">            
+            <div class="span3">
+              Name
+              <input type="text" data-bind="value: $data.name"></input>
+            </div>                      
+            <div class="span5">
+              Privileges
+              <div data-bind="template: { name: 'privilege-template', foreach: privileges}">
               </div>
-              <a href="javascript: void(0)" data-bind='click: addPriviledge'>
+              <a href="javascript: void(0)" data-bind="click: addPrivilege">
                 <i class="fa fa-plus"></i>
               </a>
-            </div>
-            Groups
-            <div>
+            </div>            
+            <div class="span4">
+              Groups
               <select data-bind="options: $root.availableHadoopGroups, selectedOptions: groups" size="5" multiple="true"></select>
             </div>
-            Name
-            <div>
-              <input type="text" data-bind="value: $data.name"></input>
-            </div>
-          </div>
-          <div>
             <button type="button" rel="tooltip" data-placement="bottom" data-original-title="${ _('Cancel') }" class="btn">
-              <i class="fa fa-undo"></i>
+              <i class="fa fa-times"></i>
             </button>
             <button type="button" rel="tooltip" data-placement="bottom" data-loading-text="${ _('Saving...') }" data-original-title="${ _('Save') }" class="btn"
-                data-bind="click: $root.role.edit">
+                data-bind="click: $root.role.create">
               <i class="fa fa-save"></i>
-            </button>
+            </button>            
           </div>          
+          <div>
+          </div>          
+        </div>           
+          
+        </br></br>
+          
+        <div>
+        <table>
+          <theader>
+            <th width="1%"><div class="hueCheckbox selectAll fa"></div></th>
+            <th width="3%"></th>
+            <th>${ _('Name') }</th>
+            <th>${ _('Groups') }</th>
+            <th>${ _('Grantor Principal') }</th>
+          </theader> 
+          <tbody data-bind="foreach: $root.roles">          
+            <tr>
+              <td>
+                <input type="checkbox" data-bind="click: $root.role.remove"></input>
+              </td>
+              <td>                                              
+                <a href="javascript:void(0);"><i class="fa fa-2x" data-bind="click: $root.list_sentry_privileges_by_role, css: {'fa-caret-right' : ! showPrivileges(), 'fa-caret-down': showPrivileges() }""></i></a>
+              </td>
+              <td data-bind="text: name"></td>
+              <td data-bind="text: groups"></td>
+              <td>
+                <a href=""><span data-bind="text: grantorPrincipal"></span></a>
+              </td>
+            </tr>
+            <tr data-bind="foreach: $data.privileges, visible: $data.showPrivileges">
+              <td colspan="2"></td>
+              <td colspan="3">
+                <span data-bind="text: ko.mapping.toJSON($data)"></span> <a href="javascript:void(0);"><i class="fa fa-minus"></i></a>
+              </td>
+            </tr>
+            <tr data-bind="visible: $data.showPrivileges">
+              <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-original-title="${ _('Cancel') }" class="btn">
+		            <i class="fa fa-times"></i>
+		          </button>
+		          <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>
+            </tr>
+          </div>        
+        </tbody>
         </div>
-      </div>
-
-      <div id="view" class="mainSection hide card card-small">
-        <div class="card-heading simple"><h3>${ _('View') }</h3></div>
-      </div>
-
-      <div id="roles" class="mainSection hide card card-small">
-        <div class="card-heading simple"><h3>${ _('Roles') }</h3></div>
-           
-        <div data-bind="foreach: $root.roles">
-          <div data-bind="text: ko.mapping.toJSON($data), click: $root.list_sentry_privileges_by_role"></div><i class="fa fa-minus"></i>
-        </div>
-      </div>
-
-      <div id="privileges" class="mainSection hide card card-small">
-        <div class="card-heading simple"><h3>${ _('Privileges') }</h3></div>      
         
-        <div data-bind="foreach: $root.privileges">
-          <div data-bind="text: ko.mapping.toJSON($data)"></div><i class="fa fa-minus"></i>
-        </div>
       </div>
 
     </div>

+ 2 - 1
apps/security/src/security/urls.py

@@ -35,5 +35,6 @@ urlpatterns += patterns('security.api',
   url(r'^api/hive/list_sentry_privileges_for_provider$', 'list_sentry_privileges_for_provider', name='list_sentry_privileges_for_provider'),  
   url(r'^api/hive/create_sentry_role', 'create_sentry_role', name='create_sentry_role'),
   url(r'^api/hive/drop_sentry_role', 'drop_sentry_role', name='drop_sentry_role'),
-  url(r'^api/hive/edit_role$', 'hive_edit_role', name='hive_edit_role'),
+  url(r'^api/hive/create_role$', 'hive_create_role', name='hive_create_role'),
+  url(r'^api/hive/add_privileges$', 'hive_add_privileges', name='hive_add_privileges'),
 )

+ 92 - 23
apps/security/static/js/hive.ko.js

@@ -15,46 +15,75 @@
 // limitations under the License.
 
 
-// groups, priviledges
+// groups, privileges
 
 
-var Priviledge = function (vm, priviledge) {
+var Privilege = function (vm, privilege) {
   var self = this;
 
-  self.privilegeScope = ko.observable(typeof priviledge.privilegeScope != "undefined" && priviledge.privilegeScope != null ? priviledge.privilegeScope : "");
-  self.serverName = ko.observable(typeof priviledge.serverName != "undefined" && priviledge.serverName != null ? priviledge.serverName : "");
-  self.dbName = ko.observable(typeof priviledge.dbName != "undefined" && priviledge.dbName != null ? priviledge.dbName : "");
-  self.tableName = ko.observable(typeof priviledge.tableName != "undefined" && priviledge.tableName != null ? priviledge.tableName : "");
-  self.URI = ko.observable(typeof priviledge.URI != "undefined" && priviledge.URI != null ? priviledge.URI : "");
-  self.action = ko.observable(typeof priviledge.action != "undefined" && priviledge.action != null ? priviledge.action : "");
+  self.privilegeScope = ko.observable(typeof privilege.privilegeScope != "undefined" && privilege.privilegeScope != null ? privilege.privilegeScope : "");
+  self.serverName = ko.observable(typeof privilege.serverName != "undefined" && privilege.serverName != null ? privilege.serverName : "");
+  self.dbName = ko.observable(typeof privilege.dbName != "undefined" && privilege.dbName != null ? privilege.dbName : "");
+  self.tableName = ko.observable(typeof privilege.tableName != "undefined" && privilege.tableName != null ? privilege.tableName : "");
+  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.availablePriviledges = ko.observableArray(['SERVER', 'DATABASE', 'TABLE']);
-  self.availableActions = ko.observableArray(['SELECT', 'INSERT', 'ALL']);
+  self.availablePrivileges = ko.observableArray(['SERVER', 'DATABASE', 'TABLE']);
+  self.availableActions = ko.observableArray(['SELECT', 'INSERT', 'ALL', '']);
 }
 
-var Role = function(vm, priviledge) {
+var Role = function(vm, privilege) {
   var self = this;
 
-  self.priviledges = ko.observableArray();
-  self.groups = ko.observableArray();
   self.name = ko.observable('');
+  self.groups = ko.observableArray();
+  self.privileges = ko.observableArray();
+
+
+  self.reset = function() {
+	self.name('');
+    self.groups.removeAll();
+    self.privileges.removeAll();
+    self.newPrivileges.removeAll();
+  }
   
   self.addGroup = function() {
     self.groups.push('');
   }
   
-  self.addPriviledge = function() {
-	self.priviledges.push(new Priviledge(vm, {}));
+  self.addPrivilege = function() {
+	self.privileges.push(new Privilege(vm, {}));
   }
   
-  self.edit = function() {
+  self.create = function() {
 	$(".jHueNotify").hide();
-    $.post("/security/api/hive/edit_role", {
+    $.post("/security/api/hive/create_role", {
         role: ko.mapping.toJSON(self)
       }, function (data) {
         if (data.status == 0) {
           $(document).trigger("info", data.message);
-          self.roles.push(self);
+          data.role['privileges'] = ko.observableArray();
+          data.role['showPrivileges'] = ko.observable(false);          
+          vm.roles.unshift(data.role);
+          self.reset();
+          vm.showCreateRole(false);
+        }
+        else {
+          $(document).trigger("error", data.message);
+        }
+    }).fail(function (xhr, textStatus, errorThrown) {
+      $(document).trigger("error", xhr.responseText);
+    });
+  }
+
+  self.remove = function(role) {
+	$(".jHueNotify").hide();
+    $.post("/security/api/hive/drop_sentry_role", {
+    	roleName: role.name
+      }, function (data) {
+        if (data.status == 0) {
+          $(document).trigger("info", data.message);
+          vm.removeRole(role.name);
         }
         else {
           $(document).trigger("error", data.message);
@@ -63,6 +92,31 @@ var Role = function(vm, priviledge) {
       $(document).trigger("error", xhr.responseText);
     });
   }
+  
+  self.addNewPrivilege = function(role) {
+    role['newPrivileges'].push(new Privilege(self, {}));
+  }
+  
+  self.saveNewPrivileges = function(role) {
+	$(".jHueNotify").hide();
+    $.post("/security/api/hive/add_privileges", {
+        role: ko.mapping.toJSON(self)
+      }, function (data) {
+        if (data.status == 0) {
+          $(document).trigger("info", data.message);
+          data.role['privileges'] = ko.observableArray();
+          data.role['showPrivileges'] = ko.observable(false);          
+          vm.roles.unshift(data.role);
+          self.reset();
+          vm.showCreateRole(false);
+        }
+        else {
+          $(document).trigger("error", data.message);
+        }
+    }).fail(function (xhr, textStatus, errorThrown) {
+      $(document).trigger("error", xhr.responseText);
+    });
+  }  
 }
 
 
@@ -102,17 +156,32 @@ var HiveViewModel = function (initial) {
   self.assist = new Assist(self);
   
   // Edition
-  self.role = new Role();
+  self.showCreateRole = ko.observable(false);
+  self.role = new Role(self);
+  self.privilege = new Privilege(self, {});
+  
 
   self.init = function() {
     self.list_sentry_roles_by_group();
     self.assist.fetchDatabases();
   };
 
+  self.removeRole = function(roleName) {
+    $.each(self.roles(), function (index, role) {
+      if (role.name == roleName) {
+        self.roles.remove(role);
+        return false;  
+      }
+    });
+  }; 
+
   self.list_sentry_roles_by_group = function() {
     $.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); 
         });
     }).fail(function (xhr, textStatus, errorThrown) {
@@ -128,11 +197,11 @@ var HiveViewModel = function (initial) {
         'roleName': role.name
       },
       success: function (data) {
-    	self.privileges.removeAll();
-        $.each(data.sentry_privileges, function(index, item) {
-          self.privileges.push(item); 
+    	role.privileges.removeAll();
+        $.each(data.sentry_privileges, function(index, item) {          
+          role.privileges.push(ko.mapping.fromJS(item)); 
         });
-        window.location.hash = "#privileges";
+        role.showPrivileges(true);
       }
     }).fail(function (xhr, textStatus, errorThrown) {
       $(document).trigger("error", xhr.responseText);