浏览代码

[useradmin] Added superuser group priv to useradmin

Chris Conner 7 年之前
父节点
当前提交
4cc00a45f2
共有 54 个文件被更改,包括 259 次插入125 次删除
  1. 5 3
      apps/about/src/about/templates/admin_wizard.mako
  2. 3 1
      apps/about/src/about/views.py
  3. 3 2
      apps/beeswax/src/beeswax/api.py
  4. 4 2
      apps/beeswax/src/beeswax/views.py
  5. 5 3
      apps/filebrowser/src/filebrowser/views.py
  6. 2 1
      apps/hbase/src/hbase/views.py
  7. 3 2
      apps/jobbrowser/src/jobbrowser/api.py
  8. 2 1
      apps/jobbrowser/src/jobbrowser/models.py
  9. 2 1
      apps/jobbrowser/src/jobbrowser/views.py
  10. 2 1
      apps/jobsub/src/jobsub/views.py
  11. 2 1
      apps/metastore/src/metastore/views.py
  12. 3 1
      apps/oozie/src/oozie/decorators.py
  13. 3 1
      apps/oozie/src/oozie/models.py
  14. 4 3
      apps/oozie/src/oozie/views/dashboard.py
  15. 3 2
      apps/oozie/src/oozie/views/editor.py
  16. 2 1
      apps/pig/src/pig/api.py
  17. 2 1
      apps/pig/src/pig/models.py
  18. 3 1
      apps/search/src/search/views.py
  19. 2 1
      apps/security/src/security/views.py
  20. 3 1
      apps/useradmin/src/useradmin/models.py
  21. 1 0
      apps/useradmin/src/useradmin/settings.py
  22. 5 4
      apps/useradmin/src/useradmin/templates/edit_user.mako
  23. 3 2
      apps/useradmin/src/useradmin/templates/layout.mako
  24. 7 6
      apps/useradmin/src/useradmin/templates/list_groups.mako
  25. 2 1
      apps/useradmin/src/useradmin/templates/list_permissions.mako
  26. 15 6
      apps/useradmin/src/useradmin/templates/list_users.mako
  27. 47 0
      apps/useradmin/src/useradmin/tests.py
  28. 18 16
      apps/useradmin/src/useradmin/views.py
  29. 4 3
      apps/zookeeper/src/zookeeper/templates/tree.mako
  30. 6 4
      apps/zookeeper/src/zookeeper/views.py
  31. 19 2
      desktop/core/src/desktop/auth/backend.py
  32. 2 1
      desktop/core/src/desktop/auth/forms.py
  33. 4 2
      desktop/core/src/desktop/decorators.py
  34. 2 1
      desktop/core/src/desktop/lib/fs/proxyfs.py
  35. 2 2
      desktop/core/src/desktop/middleware.py
  36. 7 5
      desktop/core/src/desktop/models.py
  37. 3 2
      desktop/core/src/desktop/templates/500.mako
  38. 2 1
      desktop/core/src/desktop/templates/about_layout.mako
  39. 5 3
      desktop/core/src/desktop/templates/common_header.mako
  40. 2 1
      desktop/core/src/desktop/templates/common_home.mako
  41. 2 1
      desktop/core/src/desktop/templates/error.mako
  42. 7 5
      desktop/core/src/desktop/templates/hue.mako
  43. 3 2
      desktop/core/src/desktop/templates/popup_error.mako
  44. 11 11
      desktop/core/src/desktop/views.py
  45. 2 2
      desktop/libs/aws/src/aws/conf.py
  46. 2 2
      desktop/libs/azure/src/azure/conf.py
  47. 3 2
      desktop/libs/dashboard/src/dashboard/controller.py
  48. 2 1
      desktop/libs/dashboard/src/dashboard/templates/no_collections.mako
  49. 3 1
      desktop/libs/liboozie/src/liboozie/types.py
  50. 2 2
      desktop/libs/metadata/src/metadata/conf.py
  51. 2 1
      desktop/libs/metadata/src/metadata/optimizer_api.py
  52. 2 1
      desktop/libs/metadata/src/metadata/optimizer_client.py
  53. 2 1
      desktop/libs/notebook/src/notebook/connectors/hiveserver2.py
  54. 2 1
      desktop/libs/notebook/src/notebook/templates/editor_components.mako

+ 5 - 3
apps/about/src/about/templates/admin_wizard.mako

@@ -22,6 +22,8 @@ from django.utils.translation import ugettext as _
 from desktop.conf import IS_HUE_4
 from desktop.views import commonheader, commonfooter
 from metadata.conf import OPTIMIZER, has_optimizer
+
+from desktop.auth.backend import is_admin
 %>
 
 <%namespace name="layout" file="/about_layout.mako" />
@@ -36,13 +38,13 @@ ${ layout.menubar(section='quick_start') }
   <div class="row-fluid" style="margin-bottom: 100px;">
     <div>
       <h1 class="margin-top-20 margin-bottom-30">
-        % if user.is_superuser:
+        % if is_admin(user):
           ${ _('Quick Start Wizard') } -
         % endif
         Hue&trade; ${version} - <a href="http://gethue.com" target="_blank" style="color:#777" title="${ _('Open gethue.com in a new window.') }">${ _("Query. Explore. Repeat.") }</a>
       </h1>
 
-     % if user.is_superuser:
+     % if is_admin(user):
 
       <div class="margin-bottom-30">
          <div class="row-fluid">
@@ -238,7 +240,7 @@ ${ layout.menubar(section='quick_start') }
 
 </div>
 
-% if user.is_superuser:
+% if is_admin(user):
 <style type="text/css">
   .steps {
     min-height: 300px;

+ 3 - 1
apps/about/src/about/views.py

@@ -26,9 +26,11 @@ from desktop.log.access import access_log_level
 from desktop.models import Settings, hue_version
 from desktop.views import collect_usage
 
+from desktop.auth.backend import is_admin
+
 
 def admin_wizard(request):
-  if request.user.is_superuser:
+  if is_admin(request.user):
     apps = appmanager.get_apps(request.user)
   else:
     apps = []

+ 3 - 2
apps/beeswax/src/beeswax/api.py

@@ -51,6 +51,7 @@ from beeswax.views import authorized_get_design, authorized_get_query_history, m
 from metastore.conf import FORCE_HS2_METADATA
 from metastore.views import _get_db, _get_servername
 
+from desktop.auth.backend import is_admin
 
 LOG = logging.getLogger(__name__)
 
@@ -93,7 +94,7 @@ def autocomplete(request, database=None, table=None, column=None, nested=None):
   app_name = None if FORCE_HS2_METADATA.get() else get_app_name(request)
 
   do_as = request.user
-  if (request.user.is_superuser or request.user.has_hue_permission(action="impersonate", app="security")) and 'doas' in request.GET:
+  if (is_admin(request.user) or request.user.has_hue_permission(action="impersonate", app="security")) and 'doas' in request.GET:
     do_as = User.objects.get(username=request.GET.get('doas'))
 
   db = _get_db(user=do_as, source_type=app_name)
@@ -845,7 +846,7 @@ def close_session(request, session_id):
 
   try:
     filters = {'id': session_id, 'application': query_server['server_name']}
-    if not request.user.is_superuser:
+    if not is_admin(request.user):
       filters['owner'] = request.user
     session = Session.objects.get(**filters)
   except Session.DoesNotExist:

+ 4 - 2
apps/beeswax/src/beeswax/views.py

@@ -54,6 +54,8 @@ from beeswax.models import QueryHistory, SavedQuery, Session
 from beeswax.server import dbms
 from beeswax.server.dbms import expand_exception, get_query_server_config, QueryServerException
 
+from desktop.auth.backend import is_admin
+
 
 LOG = logging.getLogger(__name__)
 
@@ -341,7 +343,7 @@ def list_query_history(request):
   DEFAULT_PAGE_SIZE = 100
   prefix = 'q-'
 
-  share_queries = request.user.is_superuser
+  share_queries = is_admin(request.user)
 
   querydict_query = request.GET.copy()
   if not share_queries:
@@ -708,7 +710,7 @@ def authorized_get_query_history(request, query_history_id, owner_only=False, mu
 
   # Some queries don't have a design so are not linked to Document Model permission
   if query_history.design is None or not query_history.design.doc.exists():
-    if not request.user.is_superuser and request.user != query_history.owner:
+    if not is_admin(request.user) and request.user != query_history.owner:
       raise PopupException(_('Permission denied to read QueryHistory %(id)s') % {'id': query_history_id})
   else:
     query_history.design.doc.get().can_read_or_exception(request.user)

+ 5 - 3
apps/filebrowser/src/filebrowser/views.py

@@ -74,6 +74,8 @@ from filebrowser.forms import RenameForm, UploadFileForm, UploadArchiveForm, MkD
                               TrashPurgeForm, SetReplicationFactorForm
 
 
+from desktop.auth.backend import is_admin
+
 DEFAULT_CHUNK_SIZE_BYTES = 1024 * 4 # 4KB
 MAX_CHUNK_SIZE_BYTES = 1024 * 1024 # 1MB
 DOWNLOAD_CHUNK_SIZE = 1 * 1024 * 1024 # 1MB
@@ -214,7 +216,7 @@ def view(request, path):
         if "Connection refused" in e.message:
             msg += _(" The HDFS REST service is not available. ")
         elif request.fs._get_scheme(path).lower() == 'hdfs':
-            if request.user.is_superuser and not _is_hdfs_superuser(request):
+            if is_admin(request.user) and not _is_hdfs_superuser(request):
                 msg += _(' Note: you are a Hue admin but not a HDFS superuser, "%(superuser)s" or part of HDFS supergroup, "%(supergroup)s".') \
                         % {'superuser': request.fs.superuser, 'supergroup': request.fs.supergroup}
 
@@ -428,7 +430,7 @@ def listdir_paged(request, path):
     pagenum = int(request.GET.get('pagenum', 1))
     pagesize = int(request.GET.get('pagesize', 30))
     do_as = None
-    if request.user.is_superuser or request.user.has_hue_permission(action="impersonate", app="security"):
+    if is_admin(request.user) or request.user.has_hue_permission(action="impersonate", app="security"):
       do_as = request.GET.get('doas', request.user.username)
     if hasattr(request, 'doas'):
       do_as = request.doas
@@ -1060,7 +1062,7 @@ def generic_op(form_class, request, op, parameter_names, piggyback=None, templat
             except (IOError, WebHdfsException), e:
                 msg = _("Cannot perform operation.")
                 # TODO: Only apply this message for HDFS
-                if request.user.is_superuser and not _is_hdfs_superuser(request):
+                if is_admin(request.user) and not _is_hdfs_superuser(request):
                     msg += _(' Note: you are a Hue admin but not a HDFS superuser, "%(superuser)s" or part of HDFS supergroup, "%(supergroup)s".') \
                            % {'superuser': request.fs.superuser, 'supergroup': request.fs.supergroup}
                 if request.is_ajax():

+ 2 - 1
apps/hbase/src/hbase/views.py

@@ -35,12 +35,13 @@ from hbase.api import HbaseApi
 from hbase.management.commands import hbase_setup
 from hbase.server.hbase_lib import get_thrift_type
 
+from desktop.auth.backend import is_admin
 
 LOG = logging.getLogger(__name__)
 
 
 def has_write_access(user):
-  return user.is_superuser or user.has_hue_permission(action="write", app=DJANGO_APPS[0]) or is_impersonation_enabled()
+  return is_admin(user) or user.has_hue_permission(action="write", app=DJANGO_APPS[0]) or is_impersonation_enabled()
 
 def app(request):
   return render('app.mako', request, {

+ 3 - 2
apps/jobbrowser/src/jobbrowser/api.py

@@ -34,6 +34,7 @@ import hadoop.yarn.spark_history_server_api as spark_history_server_api
 
 from jobbrowser.conf import SHARE_JOBS
 from jobbrowser.yarn_models import Application, OozieYarnJob, Job as YarnJob, KilledJob as KilledYarnJob, Container, SparkJob
+from desktop.auth.backend import is_admin
 
 
 LOG = logging.getLogger(__name__)
@@ -123,11 +124,11 @@ class YarnApi(JobBrowserApi):
     return int(elapsed_time.days * 86400 + elapsed_time.seconds) * 1000
 
   def filter_jobs(self, user, jobs, **kwargs):
-    check_permission = not SHARE_JOBS.get() and not user.is_superuser
+    check_permission = not SHARE_JOBS.get() and not is_admin(user)
 
     return filter(lambda job:
                   not check_permission or
-                  user.is_superuser or
+                  is_admin(user) or
                   job.user == user.username, jobs)
 
 

+ 2 - 1
apps/jobbrowser/src/jobbrowser/models.py

@@ -30,6 +30,7 @@ from django.utils.translation import ugettext as _
 from desktop.lib.view_util import location_to_url
 
 from jobbrowser.conf import DISABLE_KILLING_JOBS
+from desktop.auth.backend import is_admin
 
 
 LOG = logging.getLogger(__name__)
@@ -56,7 +57,7 @@ def can_kill_job(self, user):
   if self.status.lower() not in ('running', 'pending', 'accepted'):
     return False
 
-  if user.is_superuser:
+  if is_admin(user):
     return True
 
   if can_modify_job(user.username, self):

+ 2 - 1
apps/jobbrowser/src/jobbrowser/views.py

@@ -42,6 +42,7 @@ from desktop.views import register_status_bar_view
 from hadoop import cluster
 from hadoop.yarn.clients import get_log_client
 from hadoop.yarn import resource_manager_api as resource_manager_api
+from desktop.auth.backend import is_admin
 
 
 LOG = logging.getLogger(__name__)
@@ -75,7 +76,7 @@ def check_job_permission(view_func):
       LOG.warn('Job %s has not yet been accepted by the RM, will poll for status.' % jobid)
       return job_not_assigned(request, jobid, request.path)
 
-    if not SHARE_JOBS.get() and not request.user.is_superuser \
+    if not SHARE_JOBS.get() and not is_admin(request.user) \
         and job.user != request.user.username and not can_view_job(request.user.username, job):
       raise PopupException(_("You don't have permission to access job %(id)s.") % {'id': jobid})
     kwargs['job'] = job

+ 2 - 1
apps/jobsub/src/jobsub/views.py

@@ -43,6 +43,7 @@ from oozie.forms import design_form_by_type
 from oozie.utils import model_to_dict, format_dict_field_values,\
                         sanitize_node_dict
 
+from desktop.auth.backend import is_admin
 
 LOG = logging.getLogger(__name__)
 MAX_DESIGNS = 250
@@ -124,7 +125,7 @@ def _get_design(user, design_id):
 def _check_permission(request, owner_name, error_msg, allow_root=False):
   """Raise PopupException if user doesn't have permission to modify the design"""
   if request.user.username != owner_name:
-    if allow_root and request.user.is_superuser:
+    if allow_root and is_admin(request.user):
       return
     access_warn(request, error_msg)
     raise PopupException(_("Permission denied. You are not the owner."))

+ 2 - 1
apps/metastore/src/metastore/views.py

@@ -44,6 +44,7 @@ from metastore.conf import FORCE_HS2_METADATA
 from metastore.forms import LoadDataForm, DbForm
 from metastore.settings import DJANGO_APPS
 
+from desktop.auth.backend import is_admin
 
 LOG = logging.getLogger(__name__)
 
@@ -656,7 +657,7 @@ def drop_partition(request, database, table):
 
 
 def has_write_access(user):
-  return user.is_superuser or user.has_hue_permission(action="write", app=DJANGO_APPS[0])
+  return is_admin(user) or user.has_hue_permission(action="write", app=DJANGO_APPS[0])
 
 
 

+ 3 - 1
apps/oozie/src/oozie/decorators.py

@@ -27,6 +27,8 @@ from desktop.models import Document, Document2
 
 from oozie.models import Job, Node, Dataset
 
+from desktop.auth.backend import is_admin
+
 
 LOG = logging.getLogger(__name__)
 
@@ -108,7 +110,7 @@ def check_document_modify_permission():
 def check_editor_access_permission(view_func):
 
   def decorate(request, *args, **kwargs):
-    if not request.user.is_superuser and request.user.has_hue_permission(action="disable_editor_access", app="oozie"):
+    if not is_admin(request.user) and request.user.has_hue_permission(action="disable_editor_access", app="oozie"):
       raise PopupException(_('Missing permission to access the Oozie Editor'), error_code=401)
     return view_func(request, *args, **kwargs)
   return wraps(view_func)(decorate)

+ 3 - 1
apps/oozie/src/oozie/models.py

@@ -54,6 +54,8 @@ from oozie.conf import REMOTE_SAMPLE_DIR
 from oozie.utils import utc_datetime_format
 from oozie.timezones import TIMEZONES
 
+from desktop.auth.backend import is_admin
+
 
 LOG = logging.getLogger(__name__)
 
@@ -223,7 +225,7 @@ class Job(models.Model):
       raise e
 
   def is_editable(self, user):
-    return user.is_superuser or self.owner == user or self.doc.get().can_write(user)
+    return is_admin(user) or self.owner == user or self.doc.get().can_write(user)
 
   @property
   def data_dict(self):

+ 4 - 3
apps/oozie/src/oozie/views/dashboard.py

@@ -52,6 +52,7 @@ from oozie.models2 import History, Workflow, WORKFLOW_NODE_PROPERTIES
 from oozie.settings import DJANGO_APPS
 from oozie.utils import convert_to_server_timezone
 
+from desktop.auth.backend import is_admin
 
 def get_history():
   if ENABLE_V2.get():
@@ -1172,7 +1173,7 @@ def check_job_access_permission(request, job_id, **kwargs):
       LOG.exception(msg)
       raise PopupException(msg, detail=ex._headers.get('oozie-error-message'))
 
-  if request.user.is_superuser \
+  if is_admin(request.user) \
       or oozie_job.user == request.user.username \
       or has_dashboard_jobs_access(request.user):
     return oozie_job
@@ -1193,8 +1194,8 @@ def check_job_edition_permission(oozie_job, user):
 
 
 def has_job_edition_permission(oozie_job, user):
-  return user.is_superuser or oozie_job.user == user.username or (oozie_job.group and user.groups.filter(name=oozie_job.group).exists()) or (oozie_job.acl and user.username in oozie_job.acl.split(','))
+  return is_admin(user) or oozie_job.user == user.username or (oozie_job.group and user.groups.filter(name=oozie_job.group).exists()) or (oozie_job.acl and user.username in oozie_job.acl.split(','))
 
 
 def has_dashboard_jobs_access(user):
-  return user.is_superuser or user.has_hue_permission(action="dashboard_jobs_access", app=DJANGO_APPS[0])
+  return is_admin(user) or user.has_hue_permission(action="dashboard_jobs_access", app=DJANGO_APPS[0])

+ 3 - 2
apps/oozie/src/oozie/views/editor.py

@@ -57,6 +57,7 @@ from oozie.forms import WorkflowForm, CoordinatorForm, DatasetForm,\
                         BundleForm, BundledCoordinatorForm, design_form_by_type,\
                         ImportWorkflowForm, ImportCoordinatorForm
 
+from desktop.auth.backend import is_admin
 
 LOG = logging.getLogger(__name__)
 
@@ -902,7 +903,7 @@ def list_history(request):
   """
   history = History.objects
 
-  if not request.user.is_superuser:
+  if not is_admin(request.user):
     history = history.filter(submitter=request.user)
   history = history.order_by('-submission_date')
 
@@ -918,7 +919,7 @@ def list_history_record(request, record_id):
   """
   history = History.objects
 
-  if not request.user.is_superuser:
+  if not is_admin(request.user):
     history.filter(submitter=request.user)
   history = history.get(id=record_id)
 

+ 2 - 1
apps/pig/src/pig/api.py

@@ -28,6 +28,7 @@ from liboozie.oozie_api import get_oozie
 from oozie.models import Workflow, Pig
 from oozie.views.api import get_log as get_workflow_logs
 from oozie.views.editor import _submit_workflow
+from desktop.auth.backend import is_admin
 
 
 LOG = logging.getLogger(__name__)
@@ -240,5 +241,5 @@ def format_time(st_time):
 
 
 def has_job_edition_permission(oozie_job, user):
-  return user.is_superuser or oozie_job.user == user.username
+  return is_admin(user) or oozie_job.user == user.username
 

+ 2 - 1
apps/pig/src/pig/models.py

@@ -27,6 +27,7 @@ from django.utils.translation import ugettext as _, ugettext_lazy as _t
 from desktop.lib.exceptions_renderable import PopupException
 from desktop.models import Document as Doc, SAMPLE_USER_ID
 from hadoop.fs.hadoopfs import Hdfs
+from desktop.auth.backend import is_admin
 
 
 class Document(models.Model):
@@ -35,7 +36,7 @@ class Document(models.Model):
                                      help_text=_t('If the document is not a submitted job but a real query, script, workflow.'))
 
   def is_editable(self, user): # Deprecated
-    return user.is_superuser or self.owner == user
+    return is_admin(user) or self.owner == user
 
   def can_edit_or_exception(self, user, exception_class=PopupException): # Deprecated
     if self.is_editable(user):

+ 3 - 1
apps/search/src/search/views.py

@@ -24,6 +24,8 @@ from indexer.management.commands import indexer_setup
 
 from search.management.commands import search_setup
 
+from desktop.auth.backend import is_admin
+
 
 LOG = logging.getLogger(__name__)
 
@@ -31,7 +33,7 @@ LOG = logging.getLogger(__name__)
 def install_examples(request):
   result = {'status': -1, 'message': ''}
 
-  if not request.user.is_superuser:
+  if not is_admin(request.user):
     return PopupException(_("You must be a superuser."))
 
   if request.method != 'POST':

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

@@ -20,6 +20,7 @@ import json
 from desktop.lib.django_util import render
 
 from libsentry.sentry_site import get_hive_sentry_provider, get_sentry_server_admin_groups, get_solr_sentry_provider
+from desktop.auth.backend import is_admin
 
 
 def hive(request):
@@ -67,4 +68,4 @@ def hdfs(request):
 
 
 def _has_impersonation_perm(user):
-  return user.is_superuser or user.has_hue_permission(action="impersonate", app="security")
+  return is_admin(user) or user.has_hue_permission(action="impersonate", app="security")

+ 3 - 1
apps/useradmin/src/useradmin/models.py

@@ -61,7 +61,6 @@ import django.utils.timezone as dtz
 
 from desktop import appmanager
 from desktop.lib.exceptions_renderable import PopupException
-from desktop.models import SAMPLE_USER_ID, SAMPLE_USER_INSTALL, HueUser
 from hadoop import cluster
 
 import useradmin.conf
@@ -276,6 +275,7 @@ def update_app_permissions(**kwargs):
     if default_group:
       for new_dp in added:
         if not (new_dp.app == 'useradmin' and new_dp.action == 'access') and \
+           not (new_dp.app == 'useradmin' and new_dp.action == 'superuser') and \
            not (new_dp.app == 'metastore' and new_dp.action == 'write') and \
            not (new_dp.app == 'hbase' and new_dp.action == 'write') and \
            not (new_dp.app == 'security' and new_dp.action == 'impersonate') and \
@@ -300,6 +300,8 @@ def install_sample_user():
   """
   Setup the de-activated sample user with a certain id. Do not create a user profile.
   """
+  #Moved to avoid circular import with is_admin
+  from desktop.models import SAMPLE_USER_ID, SAMPLE_USER_INSTALL
   user = None
 
   try:

+ 1 - 0
apps/useradmin/src/useradmin/settings.py

@@ -22,4 +22,5 @@ MENU_INDEX = 60
 
 PERMISSION_ACTIONS = (
   ("access_view:useradmin:edit_user", "Access to profile page on User Admin"),
+  ("superuser", "Give superuser access to members of group")
 )

+ 5 - 4
apps/useradmin/src/useradmin/templates/edit_user.mako

@@ -20,6 +20,7 @@ from desktop.views import commonheader, commonfooter
 
 from useradmin.hue_password_policy import is_password_policy_enabled, get_password_hint
 from useradmin.views import is_user_locked_out
+from desktop.auth.backend import is_admin
 %>
 
 <%namespace name="layout" file="layout.mako" />
@@ -52,9 +53,9 @@ ${ layout.menubar(section='users') }
           % endif
           </a>
         </li>
-        <li><a href="javascript:void(0)" class="step" data-step="step2">${ user.is_superuser and _('Step 2: Profile and Groups') or _('Step 2: Profile') }</a>
+        <li><a href="javascript:void(0)" class="step" data-step="step2">${ is_admin(user) and _('Step 2: Profile and Groups') or _('Step 2: Profile') }</a>
         </li>
-        % if user.is_superuser:
+        % if is_admin(user):
             <li><a href="javascript:void(0)" class="step" data-step="step3">${ _('Step 3: Advanced') }</a></li>
         % endif
       </ul>
@@ -88,11 +89,11 @@ ${ layout.menubar(section='users') }
             ${layout.render_field(form["language"])}
           % endif
 
-          % if user.is_superuser:
+          % if is_admin(user):
             ${layout.render_field(form["groups"])}
           % endif
         </div>
-      % if user.is_superuser:
+      % if is_admin(user):
         <div id="step3" class="stepDetails hide">
           ${layout.render_field(form["is_active"])}
           ${'is_superuser' in form.fields and layout.render_field(form["is_superuser"])}

+ 3 - 2
apps/useradmin/src/useradmin/templates/layout.mako

@@ -17,6 +17,7 @@
 <%!
 from desktop import conf
 from django.utils.translation import ugettext as _
+from desktop.auth.backend import is_admin
 
 def is_selected(section, matcher):
   if section == matcher:
@@ -55,12 +56,12 @@ def is_selected(section, matcher):
           <div class="nav-collapse">
             <ul class="nav">
               <li class="app-header">
-                <a href="${ ('/' + app_name) if user.is_superuser else '' }">
+                <a href="${ ('/' + app_name) if is_admin(user) else '' }">
                   <img src="${ static('useradmin/art/icon_useradmin_48.png') }" class="app-icon" alt="${ _('User admin icon') }" />
                   ${ _('User Admin') }
                 </a>
               </li>
-              %if user.is_superuser:
+              %if is_admin(user):
                 <li class="${is_selected(section, 'users')}"><a href="${ url('useradmin.views.list_users') }">${_('Users')}</a></li>
                 <li class="${is_selected(section, 'groups')}"><a href="${ url('useradmin.views.list_groups') }">${_('Groups')}</a></li>
                 <li class="${is_selected(section, 'permissions')}"><a href="${ url('useradmin.views.list_permissions') }">${_('Permissions')}</a></li>

+ 7 - 6
apps/useradmin/src/useradmin/templates/list_groups.mako

@@ -16,6 +16,7 @@
 <%!
 from django.utils.translation import ugettext as _
 from useradmin.models import group_permissions
+from desktop.auth.backend import is_admin
 
 from desktop.views import commonheader, commonfooter, antixss
 %>
@@ -39,12 +40,12 @@ ${layout.menubar(section='groups')}
           <input type="text" class="input-xlarge search-query filter-input" placeholder="${_('Search for name, members, etc...')}">
       </%def>
       <%def name="actions()">
-        %if user.is_superuser:
+        %if is_admin(user):
             <button class="btn delete-group-btn confirmationModal" title="${_('Delete')}" disabled="disabled"><i class="fa fa-trash-o"></i> ${_('Delete')}</button>
         %endif
       </%def>
       <%def name="creation()">
-        %if user.is_superuser:
+        %if is_admin(user):
           <a id="addGroupBtn" href="${url('useradmin.views.edit_group')}" class="btn"><i
               class="fa fa-plus-circle"></i> ${_('Add group')}</a>
           % if is_ldap_setup:
@@ -62,7 +63,7 @@ ${layout.menubar(section='groups')}
     <table class="table table-condensed datatables">
       <thead>
       <tr>
-        %if user.is_superuser:
+        %if is_admin(user):
             <th width="1%">
               <div class="select-all hue-checkbox fa"></div>
             </th>
@@ -76,13 +77,13 @@ ${layout.menubar(section='groups')}
           % for group in groups:
           <tr class="tableRow"
               data-search="${group.name}${', '.join([group_user.username for group_user in group.user_set.all()])}">
-          %if user.is_superuser:
+          %if is_admin(user):
             <td data-row-selector-exclude="true">
               <div class="hue-checkbox groupCheck fa" data-name="${group.name}" data-row-selector-exclude="true"></div>
             </td>
           %endif
           <td>
-            %if user.is_superuser:
+            %if is_admin(user):
               <strong><a title="${ _('Edit %(groupname)s') % dict(groupname=group.name) }"
                          href="${ url('useradmin.views.edit_group', name=group.name) }"
                          data-row-selector="true">${group.name}</a></strong>
@@ -152,7 +153,7 @@ ${layout.menubar(section='groups')}
       "bFilter": true,
       "bAutoWidth": false,
       "aoColumns": [
-        %if user.is_superuser:
+        %if is_admin(user):
             { "bSortable": false },
         %endif
         { "sWidth": "20%" },

+ 2 - 1
apps/useradmin/src/useradmin/templates/list_permissions.mako

@@ -17,6 +17,7 @@
 from desktop.views import commonheader, commonfooter
 from django.utils.translation import ugettext as _
 from useradmin.models import group_permissions
+from desktop.auth.backend import is_admin
 from django.contrib.auth.models import Group
 %>
 
@@ -49,7 +50,7 @@ ${layout.menubar(section='permissions')}
           <tr class="tableRow"
               data-search="${perm.app}${perm.description}${', '.join([group.name for group in Group.objects.filter(grouppermission__hue_permission=perm).order_by('name')])}">
           <td>
-            %if user.is_superuser:
+            %if is_admin(user):
               <strong><a title="${_('Edit permission')}"
                          href="${ url('useradmin.views.edit_permission', app=perm.app, priv=perm.action) }"
                          data-name="${perm.app}" data-row-selector="true">${perm.app}</a></strong>

+ 15 - 6
apps/useradmin/src/useradmin/templates/list_users.mako

@@ -19,8 +19,13 @@ from django.utils.translation import ugettext as _
 
 from desktop.lib.django_util import USERNAME_RE_RULE
 from desktop.views import commonheader, commonfooter, antixss
+from desktop.auth.backend import is_admin
+<<<<<<< HEAD
 
 import re
+=======
+from desktop.auth.backend import is_admin
+>>>>>>> [useradmin] Added superuser group priv to useradmin
 %>
 
 <%namespace name="actionbar" file="actionbar.mako" />
@@ -41,12 +46,12 @@ ${layout.menubar(section='users')}
           <input type="text" class="input-xlarge search-query filter-input" placeholder="${_('Search for name, group, etc...')}">
       </%def>
       <%def name="actions()">
-        %if user.is_superuser:
+        %if is_admin(user):
             <button class="btn delete-user-btn" title="${_('Delete')}" disabled="disabled"><i class="fa fa-trash-o"></i> ${_('Delete')}</button>
         %endif
       </%def>
       <%def name="creation()">
-        %if user.is_superuser:
+        %if is_admin(user):
             % if not is_ldap_setup:
               <a href="${ url('useradmin.views.edit_user') }" class="btn"><i class="fa fa-user"></i> ${_('Add user')}</a>
             %endif
@@ -70,7 +75,7 @@ ${layout.menubar(section='users')}
     <table class="table table-condensed datatables">
       <thead>
       <tr>
-        %if user.is_superuser:
+        %if is_admin(user):
             <th width="1%">
               <div class="select-all hue-checkbox fa"></div>
             </th>
@@ -87,13 +92,17 @@ ${layout.menubar(section='users')}
           % for listed_user in users:
           <tr class="tableRow"
               data-search="${listed_user.username}${listed_user.first_name}${listed_user.last_name}${listed_user.email}${', '.join([group.name for group in listed_user.groups.all()])}">
-          %if user.is_superuser:
+          %if is_admin(user):
               <td data-row-selector-exclude="true">
                 <div class="hue-checkbox userCheck fa" data-row-selector-exclude="true" data-id="${ listed_user.id }"></div>
               </td>
           %endif
           <td>
-            %if (user.is_superuser or user.username == listed_user.username) and re.match(USERNAME_RE_RULE, listed_user.username):
+<<<<<<< HEAD
+            %if (is_admin(user) or user.username == listed_user.username) and re.match(USERNAME_RE_RULE, listed_user.username):
+=======
+            %if is_admin(user) or user.username == listed_user.username:
+>>>>>>> [useradmin] Added superuser group priv to useradmin
               <strong><a title="${_('Edit %(username)s') % dict(username=listed_user.username)}"
                          href="${ url('useradmin.views.edit_user', username=listed_user.username) }"
                          data-row-selector="true">${listed_user.username}</a></strong>
@@ -171,7 +180,7 @@ ${layout.menubar(section='users')}
       "bInfo": false,
       "bFilter": true,
       "aoColumns": [
-        %if user.is_superuser:
+        %if is_admin(user):
             { "bSortable": false },
         %endif
         null,

+ 47 - 0
apps/useradmin/src/useradmin/tests.py

@@ -48,6 +48,8 @@ from useradmin.models import HuePermission, GroupPermission, UserProfile
 from useradmin.models import get_profile, get_default_user_group
 from useradmin.hue_password_policy import reset_password_policy
 
+from desktop.auth.backend import is_admin
+
 
 def reset_all_users():
   """Reset to a clean state by deleting all users"""
@@ -272,6 +274,44 @@ class TestUserAdmin(BaseUserAdminTests):
            save="Save"), follow=True)
     assert_true(len(GroupPermission.objects.all()) == 1)
 
+    # Get ourselves set up with a user and a group with superuser group priv
+    cadmin = make_logged_in_client(username="supertest", is_superuser=True)
+    Group.objects.create(name="super-test-group")
+    cadmin.post('/useradmin/groups/edit/super-test-group',
+                dict(name="super-test-group",
+                     members=[User.objects.get(username="supertest").pk],
+                     permissions=[HuePermission.objects.get(app='useradmin', action='superuser').pk],
+                     save="Save"), follow=True)
+    assert_equal(len(GroupPermission.objects.all()), 2)
+
+    supertest = User.objects.get(username="supertest")
+    supertest.groups.add(Group.objects.get(name="super-test-group"))
+    supertest.is_superuser = False
+    supertest.save()
+    # Validate user is not a checked superuser
+    assert_false(supertest.is_superuser)
+    # Validate user is superuser by group
+    assert_equal(UserProfile.objects.get(user__username='supertest').has_hue_permission(action="superuser",
+                                                                                       app="useradmin"), 1)
+
+    # Make sure that a user of supergroup can access /useradmin/users
+    # Create user to try to edit
+    notused = User.objects.get_or_create(username="notused", is_superuser=False)
+    response = cadmin.get('/useradmin/users/edit/notused?is_embeddable=true')
+    assert_true('Hue Users - Edit user: notused' in response.content)
+
+    # Make sure we can modify permissions
+    response = cadmin.get('/useradmin/permissions/edit/useradmin/access/?is_embeddable=true')
+    assert_true('Hue Permissions - Edit app: useradmin' in response.content)
+
+    # Revoke superuser privilege from groups
+    c.post('/useradmin/permissions/edit/useradmin/superuser',
+           dict(app='useradmin',
+           priv='superuser',
+           groups=[],
+           save="Save"), follow=True)
+    assert_equal(len(GroupPermission.objects.all()), 1)
+
     # Now test that we have limited access
     c1 = make_logged_in_client(username="nonadmin", is_superuser=False)
     response = c1.get('/useradmin/users')
@@ -282,6 +322,13 @@ class TestUserAdmin(BaseUserAdminTests):
     test_user.groups.add(Group.objects.get(name='test-group'))
     test_user.save()
 
+    # Make sure that a user of nonadmin fails where supertest succeeds
+    response = c1.get("/useradmin/users/edit/notused?is_embeddable=true")
+    assert_true('You must be a superuser to add or edit another user' in response.content)
+
+    response = c1.get("/useradmin/permissions/edit/useradmin/access/?is_embeddable=true")
+    assert_true('You must be a superuser to change permissions' in response.content)
+
     # Check that we have access now
     response = c1.get('/useradmin/users')
     assert_true(get_profile(test_user).has_hue_permission('access','useradmin'))

+ 18 - 16
apps/useradmin/src/useradmin/views.py

@@ -52,6 +52,7 @@ from useradmin.forms import SyncLdapUsersGroupsForm, AddLdapGroupsForm, AddLdapU
   PermissionsEditForm, GroupEditForm, SuperUserChangeForm, UserChangeForm, validate_username, validate_first_name, \
   validate_last_name, PasswordChangeForm
 
+from desktop.auth.backend import is_admin
 
 LOG = logging.getLogger(__name__)
 
@@ -99,7 +100,7 @@ def list_configurations(request):
 def list_for_autocomplete(request):
   extended_user_object = request.GET.get('extend_user') == 'true'
   autocomplete_filter = request.GET.get('filter', "")
-  if request.user.is_superuser:
+  if is_admin(request.user):
     users = User.objects.filter(username__icontains=autocomplete_filter).order_by('username')
     groups = Group.objects.filter(name__icontains=autocomplete_filter).order_by('name')
     if request.GET.get('only_mygroups'):
@@ -166,7 +167,7 @@ def is_user_locked_out(username):
 
 
 def delete_user(request):
-  if not request.user.is_superuser:
+  if not is_admin(request.user):
     request.audit = {
       'operation': 'DELETE_USER',
       'operationText': _get_failed_operation_text(request.user.username, 'DELETE_USER'),
@@ -206,7 +207,7 @@ def delete_user(request):
 
 
 def delete_group(request):
-  if not request.user.is_superuser:
+  if not is_admin(request.user):
     request.audit = {
       'operation': 'DELETE_GROUP',
        'operationText': _get_failed_operation_text(request.user.username, 'DELETE_GROUP'),
@@ -257,7 +258,7 @@ def edit_user(request, username=None):
   @type username:       string
   @param username:      Default to None, when creating a new user
   """
-  if request.user.username != username and not request.user.is_superuser:
+  if request.user.username != username and not is_admin(request.user):
     request.audit = {'allowed': False}
     if username is not None:
       request.audit['operation'] = 'EDIT_USER'
@@ -278,14 +279,14 @@ def edit_user(request, username=None):
 
   if require_change_password(userprofile):
     form_class = PasswordChangeForm
-  elif request.user.is_superuser:
+  elif is_admin(request.user):
     form_class = SuperUserChangeForm
   else:
     form_class = UserChangeForm
 
   if request.method == 'POST':
     form = form_class(request.POST, instance=instance)
-    if request.user.is_superuser and request.user.username != username:
+    if is_admin(request.user) and request.user.username != username:
       form.fields.pop("password_old")
     if form.is_valid(): # All validation rules pass
       if instance is None:
@@ -309,7 +310,7 @@ def edit_user(request, username=None):
             if not form.instance.is_superuser or not form.instance.is_active:
               _check_remove_last_super(orig)
           else:
-            if form.instance.is_superuser and not request.user.is_superuser:
+            if form.instance.is_superuser and not is_admin(request.user):
               raise PopupException(_("You cannot make yourself a superuser."), error_code=401)
 
           # All ok
@@ -317,7 +318,7 @@ def edit_user(request, username=None):
 
           # Unlock account if selected
           if form.cleaned_data.get('unlock_account'):
-            if not request.user.is_superuser:
+            if not is_admin(request.user):
               raise PopupException(_('You must be a superuser to reset users.'), error_code=401)
 
             try:
@@ -361,11 +362,11 @@ def edit_user(request, username=None):
         userprofile.first_login = False
         userprofile.save()
 
-        if request.user.is_superuser:
+        if is_admin(request.user):
           return redirect(reverse('about:index'))
         else:
           return redirect(reverse('desktop_views_home'))
-      elif request.user.is_superuser:
+      elif is_admin(request.user):
         if is_embeddable:
           return JsonResponse({'url': '/hue' + reverse(list_users)})
         else:
@@ -385,7 +386,7 @@ def edit_user(request, username=None):
     }
     form = form_class(instance=instance, initial=initial)
 
-    if request.user.is_superuser and request.user.username != username:
+    if is_admin(request.user) and request.user.username != username:
       form.fields.pop("password_old")
 
   if require_change_password(userprofile):
@@ -416,7 +417,7 @@ def edit_group(request, name=None):
 
   Only superusers may create a group
   """
-  if not request.user.is_superuser:
+  if not is_admin(request.user):
     request.audit = {'allowed': False}
     if name is not None:
       request.audit['operation'] = 'EDIT_GROUP'
@@ -487,7 +488,7 @@ def edit_permission(request, app=None, priv=None):
 
   Only superusers may modify permissions
   """
-  if not request.user.is_superuser:
+  if not is_admin(request.user):
     request.audit = {
       'operation': 'EDIT_PERMISSION',
       'operationText': _get_failed_operation_text(request.user.username, 'EDIT_PERMISSION'),
@@ -536,7 +537,7 @@ def add_ldap_users(request):
   If a user has been previously imported, this will sync their user information.
   If the LDAP request failed, the error message is generic right now.
   """
-  if not request.user.is_superuser:
+  if not is_admin(request.user):
     request.audit = {
       'operation': 'ADD_LDAP_USERS',
       'operationText': _get_failed_operation_text(request.user.username, 'ADD_LDAP_USERS'),
@@ -606,7 +607,7 @@ def add_ldap_groups(request):
   group with the LDAP server. If --import-members is specified, it will import
   all unimported users.
   """
-  if not request.user.is_superuser:
+  if not is_admin(request.user):
     request.audit = {
       'operation': 'ADD_LDAP_GROUPS',
       'operationText': _get_failed_operation_text(request.user.username, 'ADD_LDAP_GROUPS'),
@@ -686,7 +687,7 @@ def sync_ldap_users_groups(request):
   user information and group memberships will be updated based on the LDAP
   server's current state.
   """
-  if not request.user.is_superuser:
+  if not is_admin(request.user):
     request.audit = {
       'operation': 'SYNC_LDAP_USERS_GROUPS',
       'operationText': _get_failed_operation_text(request.user.username, 'SYNC_LDAP_USERS_GROUPS'),
@@ -871,6 +872,7 @@ def sync_unix_users_and_groups(min_uid, max_uid, min_gid, max_gid, check_shell):
 
 def _check_remove_last_super(user_obj):
   """Raise an error if we're removing the last superuser"""
+  """We could actually check the entire super group as well"""
   if not user_obj.is_superuser:
     return
 

+ 4 - 3
apps/zookeeper/src/zookeeper/templates/tree.mako

@@ -17,6 +17,7 @@
 <%!
   from desktop.views import commonheader, commonfooter
   from django.utils.translation import ugettext as _
+  from desktop.auth.backend import is_admin
 %>
 
 <%namespace name="shared" file="shared_components.mako" />
@@ -50,7 +51,7 @@ ${ shared.header(_breadcrumbs, clusters, False) }
         % if len(children) == 0:
           <li class="white">${ _('No children available') }</li>
         % endif
-        % if user.is_superuser:
+        % if is_admin(user):
         <li class="white">
           <button class="btn" onclick="location.href='${url('zookeeper:create', id=cluster['id'], path=path)}'">
             <i class="fa fa-plus-circle"></i> ${ _('Add') }
@@ -77,13 +78,13 @@ ${ shared.header(_breadcrumbs, clusters, False) }
       %if znode.get('dataLength', 0) != 0:
       <div class="tab-pane active" id="text">
         <textarea id="textareaText" rows="25" readonly="readonly"></textarea>
-        % if user.is_superuser:
+        % if is_admin(user):
         <a href="${url('zookeeper:edit_as_text', id=cluster['id'], path=path)}" class="btn"><i class="fa fa-pencil"></i> ${_('Edit as Text')}</a>
         % endif
       </div>      
       <div class="tab-pane" id="base64">
         <textarea id="textarea64" rows="25" readonly="readonly">${znode.get('data64', '')}</textarea>
-        % if user.is_superuser:
+        % if is_admin(user):
         <a href="${url('zookeeper:edit_as_base64', id=cluster['id'], path=path)}" class="btn"><i class="fa fa-pencil"></i> ${_('Edit as Base64')}</a>
         % endif
       </div>

+ 6 - 4
apps/zookeeper/src/zookeeper/views.py

@@ -33,6 +33,8 @@ from zookeeper.forms import CreateZNodeForm, EditZNodeForm
 from zookeeper.rest import ZooKeeper
 from zookeeper.utils import get_cluster_or_404
 
+from desktop.auth.backend import is_admin
+
 
 def _get_global_overview():
   clusters = CLUSTERS.get()
@@ -120,7 +122,7 @@ def tree(request, id, path):
 
 
 def delete(request, id, path):
-  if not request.user.is_superuser:
+  if not is_admin(request.user):
     raise PopupException(_('You are not a superuser'))
   cluster = get_cluster_or_404(id)
 
@@ -139,7 +141,7 @@ def delete(request, id, path):
 
 
 def create(request, id, path):
-  if not request.user.is_superuser:
+  if not is_admin(request.user):
     raise PopupException(_('You are not a superuser'))
   cluster = get_cluster_or_404(id)
 
@@ -164,7 +166,7 @@ def edit_as_base64(request, id, path):
   node = zk.get(path)
 
   if request.method == 'POST':
-    if not request.user.is_superuser:
+    if not is_admin(request.user):
       raise PopupException(_('You are not a superuser'))
     form = EditZNodeForm(request.POST)
     if form.is_valid():
@@ -187,7 +189,7 @@ def edit_as_text(request, id, path):
   node = zk.get(path)
 
   if request.method == 'POST':
-    if not request.user.is_superuser:
+    if not is_admin(request.user):
       raise PopupException(_('You are not a superuser'))
     form = EditZNodeForm(request.POST)
     if form.is_valid():

+ 19 - 2
desktop/core/src/desktop/auth/backend.py

@@ -53,9 +53,7 @@ from mozilla_django_oidc.auth import OIDCAuthenticationBackend, default_username
 from mozilla_django_oidc.utils import absolutify, import_from_settings
 
 from useradmin import ldap_access
-from useradmin.forms import validate_username
 from useradmin.models import get_profile, get_default_user_group, UserProfile
-from useradmin.views import import_ldap_users, get_find_groups_filter
 
 
 LOG = logging.getLogger(__name__)
@@ -100,6 +98,19 @@ def rewrite_user(user):
       setattr(user, attr, getattr(augment, attr))
   return user
 
+def is_admin(user):
+  is_admin = False
+  if hasattr(user, 'is_superuser'):
+    is_admin = user.is_superuser
+  if not is_admin:
+    try:
+      user = rewrite_user(user)
+      is_admin = user.has_hue_permission(action="superuser", app="useradmin")
+    except Exception, e:
+      LOG.exception("Could not validate if %s is a superuser assuming False." % user)
+      is_admin = False
+  return is_admin
+
 class DefaultUserAugmentor(object):
   def __init__(self, parent):
     self._parent = parent
@@ -359,6 +370,8 @@ class LdapBackend(object):
         username = force_username_case(username)
 
         try:
+          #Avoid circular import from is_admin
+          from useradmin.forms import validate_username
           validate_username(username)
 
           if desktop.conf.LDAP.IGNORE_USERNAME_CASE.get():
@@ -497,6 +510,8 @@ class LdapBackend(object):
     return user
 
   def check_ldap_access_groups(self, server, username):
+    #Avoid circular import from is_admin
+    from useradmin.views import get_find_groups_filter
     allowed_group = False
 
     if desktop.conf.LDAP.LOGIN_GROUPS.get() and desktop.conf.LDAP.LOGIN_GROUPS.get() != ['']:
@@ -525,6 +540,8 @@ class LdapBackend(object):
 
   def import_groups(self, server, user):
     connection = ldap_access.get_connection_from_server(server)
+    #Avoid circular import from is_admin
+    from useradmin.views import import_ldap_users
     import_ldap_users(connection, user.username, sync_groups=True, import_by_dn=False, server=server)
 
   @classmethod

+ 2 - 1
desktop/core/src/desktop/auth/forms.py

@@ -29,6 +29,7 @@ from django.utils.translation import ugettext_lazy as _t, ugettext as _
 from desktop import conf
 from useradmin.hue_password_policy import hue_get_password_validators
 
+from desktop.auth.backend import is_admin
 
 LOG = logging.getLogger(__name__)
 
@@ -78,7 +79,7 @@ class AuthenticationForm(AuthAuthenticationForm):
         expires_delta = datetime.timedelta(seconds=conf.AUTH.EXPIRES_AFTER.get())
         if user.is_active and user.last_login + expires_delta < datetime.datetime.now():
           INACTIVE_EXPIRATION_DELTA = datetime.timedelta(days=365)
-          if user.is_superuser:
+          if is_admin(user):
             if conf.AUTH.EXPIRE_SUPERUSERS.get():
               user.is_active = False
               user.last_login = datetime.datetime.now() + INACTIVE_EXPIRATION_DELTA

+ 4 - 2
desktop/core/src/desktop/decorators.py

@@ -28,6 +28,8 @@ try:
 except ImportError:
   from django.utils.functional import wraps
 
+from desktop.auth.backend import is_admin
+
 
 LOG = logging.getLogger(__name__)
 
@@ -51,7 +53,7 @@ def hue_permission_required(action, app):
 
 def check_superuser_permission(view_func):
   def decorate(request, *args, **kwargs):
-    if not request.user.is_superuser:
+    if not is_admin(request.user):
       raise PopupException(_('You must be a superuser to perform this operation.'), error_code=401)
     return view_func(request, *args, **kwargs)
   return wraps(view_func)(decorate)
@@ -76,4 +78,4 @@ def check_document_access_permission():
 
       return view_func(request, *args, **kwargs)
     return wraps(view_func)(decorate)
-  return inner
+  return inner

+ 2 - 1
desktop/core/src/desktop/lib/fs/proxyfs.py

@@ -21,6 +21,7 @@ import logging
 from urlparse import urlparse
 from django.contrib.auth.models import User
 
+from desktop.auth.backend import is_admin
 
 LOG = logging.getLogger(__name__)
 
@@ -58,7 +59,7 @@ class ProxyFS(object):
       if not filebrowser_action:
         return True
       user = rewrite_user(User.objects.get(username=self.user))
-      return user.is_authenticated() and user.is_active and (user.is_superuser or not filebrowser_action or user.has_hue_permission(action=filebrowser_action, app="filebrowser"))
+      return user.is_authenticated() and user.is_active and (is_admin(user) or not filebrowser_action or user.has_hue_permission(action=filebrowser_action, app="filebrowser"))
     except User.DoesNotExist:
       LOG.exception('proxyfs.has_access()')
       return False

+ 2 - 2
desktop/core/src/desktop/middleware.py

@@ -56,7 +56,7 @@ from desktop import appmanager
 from desktop import metrics
 from hadoop import cluster
 
-
+from desktop.auth.backend import is_admin
 
 LOG = logging.getLogger(__name__)
 
@@ -319,7 +319,7 @@ class LoginAndPermissionMiddleware(object):
 
       if app_accessed and \
           app_accessed not in ("desktop", "home", "home2", "about", "hue", "editor", "notebook", "indexer", "404", "500", "403") and \
-          not (request.user.has_hue_permission(action="access", app=app_accessed) or
+          not (is_admin(request.user) or request.user.has_hue_permission(action="access", app=app_accessed) or
                request.user.has_hue_permission(action=access_view, app=app_accessed)) and \
           not (app_accessed == '__debug__' and desktop.conf.DJANGO_DEBUG_MODE):
         access_log(request, 'permission denied', level=access_log_level)

+ 7 - 5
desktop/core/src/desktop/models.py

@@ -55,6 +55,7 @@ from desktop.lib.exceptions_renderable import PopupException
 from desktop.lib.paths import get_run_root
 from desktop.redaction import global_redaction_engine
 from desktop.settings import DOCUMENT2_SEARCH_MAX_LENGTH
+from desktop.auth.backend import is_admin
 
 LOG = logging.getLogger(__name__)
 
@@ -609,6 +610,7 @@ class DocumentManager(models.Manager):
 
 
 class Document(models.Model):
+
   owner = models.ForeignKey(auth_models.User, db_index=True, verbose_name=_t('Owner'), help_text=_t('User who can own the job.'), related_name='doc_owner')
   name = models.CharField(default='', max_length=255)
   description = models.TextField(default='')
@@ -671,11 +673,11 @@ class Document(models.Model):
     DocumentPermission.objects.share_to_default(self, name=name)
 
   def can_read(self, user):
-    return user.is_superuser or self.owner == user or Document.objects.get_docs(user).filter(id=self.id).exists()
+    return is_admin(user) or self.owner == user or Document.objects.get_docs(user).filter(id=self.id).exists()
 
   def can_write(self, user):
     perm = self.list_permissions('write')
-    return user.is_superuser or self.owner == user or perm.groups.filter(id__in=user.groups.all()).exists() or user in perm.users.all()
+    return is_admin(user) or self.owner == user or perm.groups.filter(id__in=user.groups.all()).exists() or user in perm.users.all()
 
   def can_read_or_exception(self, user, exception_class=PopupException):
     if self.can_read(user):
@@ -1310,7 +1312,7 @@ class Document2(models.Model):
   def can_read(self, user):
     perm = self.get_permission('read')
     has_read_permissions = perm.user_has_access(user) if perm else False
-    return user.is_superuser or self.owner == user or self.can_write(user) or has_read_permissions
+    return is_admin(user) or self.owner == user or self.can_write(user) or has_read_permissions
 
   def can_read_or_exception(self, user):
     if self.can_read(user):
@@ -1321,7 +1323,7 @@ class Document2(models.Model):
   def can_write(self, user):
     perm = self.get_permission('write')
     has_write_permissions = perm.user_has_access(user) if perm else False
-    return user.is_superuser or self.owner == user or has_write_permissions or (self.parent_directory and self.parent_directory.can_write(user))
+    return is_admin(user) or self.owner == user or has_write_permissions or (self.parent_directory and self.parent_directory.can_write(user))
 
   def can_write_or_exception(self, user):
     if self.can_write(user):
@@ -1871,7 +1873,7 @@ class ClusterConfig():
       }
     ]
 
-    if 'oozie' in self.apps and not (self.user.has_hue_permission(action="disable_editor_access", app="oozie") and not self.user.is_superuser) and self.cluster_type != ANALYTIC_DB:
+    if 'oozie' in self.apps and not (self.user.has_hue_permission(action="disable_editor_access", app="oozie") and not is_admin(self.user)) and self.cluster_type != ANALYTIC_DB:
       return {
           'name': 'oozie',
           'displayName': _('Scheduler'),

+ 3 - 2
desktop/core/src/desktop/templates/500.mako

@@ -18,6 +18,7 @@
 from desktop.lib.i18n import smart_unicode
 from desktop.views import commonheader, commonfooter
 from django.utils.translation import ugettext as _
+from desktop.auth.backend import is_admin
 %>
 
 %if not is_embeddable:
@@ -45,7 +46,7 @@ ${ commonheader(_('500 - Server error'), "", user, request) | n,unicode }
       <p>${_("Sorry, there's been an error. An email was sent to your administrators. Thank you for your patience.")}</p>
       <br/>
 
-      % if traceback and user.is_superuser:
+      % if traceback and is_admin(user):
         <a href="javascript:toggleDisplay('#traceback');" title="${ _('See the stacktrace') }">${_('More info...')}</a>
           &nbsp;|&nbsp;
         <a href="/logs" target="_new" title="${ _('View server logs') }">${_('View logs')}</a>
@@ -70,7 +71,7 @@ ${ commonheader(_('500 - Server error'), "", user, request) | n,unicode }
           </table>
         </div>
       % else:
-        % if user.is_superuser:
+        % if is_admin(user):
           <a href="/logs" ${ not is_embeddable and 'target="_blank"'  or '' } title="${ _('View server logs') }">${_('View logs')}</a>
         % endif
       % endif

+ 2 - 1
desktop/core/src/desktop/templates/about_layout.mako

@@ -16,6 +16,7 @@
 
 <%!
 from django.utils.translation import ugettext as _
+from desktop.auth.backend import is_admin
 
 def is_selected(section, matcher):
   if section == matcher:
@@ -36,7 +37,7 @@ def is_selected(section, matcher):
                   ${ _('About Hue') }
                 </a>
                </li>
-              % if user.is_superuser:
+              % if is_admin(user):
                 <li class="${is_selected(section, 'quick_start')}">
                   <a href="${ url('about:admin_wizard') }">${_('Quick start')}</a>
                 </li>

+ 5 - 3
desktop/core/src/desktop/templates/common_header.mako

@@ -22,6 +22,8 @@ from desktop.lib.i18n import smart_unicode
 
 from metadata.conf import has_optimizer, OPTIMIZER
 
+from desktop.auth.backend import is_admin
+
 home_url = url('desktop_views_home')
 if USE_NEW_EDITOR.get():
   home_url = url('desktop_views_home2')
@@ -332,7 +334,7 @@ ${ hueIcons.symbols() }
       % endif
     % endif
     <%
-      view_profile = user.has_hue_permission(action="access_view:useradmin:edit_user", app="useradmin") or user.is_superuser
+      view_profile = user.has_hue_permission(action="access_view:useradmin:edit_user", app="useradmin") or is_admin(user)
     %>
     % if view_profile or conf.IS_HUE_4.get():
     <li class="dropdown">
@@ -351,7 +353,7 @@ ${ hueIcons.symbols() }
           % endif
         </a>
       </li>
-        % if user.is_superuser:
+        % if is_admin(user):
           <li><a href="${ url('useradmin.views.list_users') }"><i class="fa fa-fw fa-group"></i> ${_('Manage Users')}</a></li>
         % endif
       % endif
@@ -504,7 +506,7 @@ ${ hueIcons.symbols() }
                <li><a href="${url('oozie:list_oozie_bundles')}"><img src="${ static('oozie/art/icon_oozie_bundle_48.png') }" class="app-icon" alt="${ _('Oozie bundles icon') }" /> ${_('Bundles')}</a></li>
              </ul>
            </li>
-           % if not user.has_hue_permission(action="disable_editor_access", app="oozie") or user.is_superuser:
+           % if not user.has_hue_permission(action="disable_editor_access", app="oozie") or is_admin(user):
            <% from oozie.conf import ENABLE_V2 %>
            % if not ENABLE_V2.get():
            <li class="dropdown-submenu">

+ 2 - 1
desktop/core/src/desktop/templates/common_home.mako

@@ -18,6 +18,7 @@
 
   from desktop.views import commonheader, commonfooter, _ko
   from desktop import conf
+  from desktop.auth.backend import is_admin
 %>
 
 <%namespace name="docBrowser" file="/document_browser.mako" />
@@ -71,7 +72,7 @@
     $(document).ready(function () {
       var options = {
         user: '${ user.username }',
-        superuser: '${ user.is_superuser }' === 'True',
+        superuser: '${ is_admin(user) }' === 'True',
         i18n: {
           errorFetchingTableDetails: '${_('An error occurred fetching the table details. Please try again.')}',
           errorFetchingTableFields: '${_('An error occurred fetching the table fields. Please try again.')}',

+ 2 - 1
desktop/core/src/desktop/templates/error.mako

@@ -18,6 +18,7 @@ from desktop.views import commonheader, commonfooter
 from desktop.lib.i18n import smart_unicode
 from django.utils.translation import ugettext as _
 from desktop import conf
+from desktop.auth.backend import is_admin
 %>
 
 %if not is_embeddable:
@@ -33,7 +34,7 @@ ${ commonheader(_('Error'), app_name, user, request, "40px") | n,unicode }
             <p>
               <pre>${ smart_unicode(error) }</pre>
 
-              %if traceback and user.is_superuser:
+              %if traceback and is_admin(user):
                 <textarea style="width: 100%;" rows=80 readonly="readonly">
                 ${ smart_unicode(traceback) }
                 </textarea>

+ 7 - 5
desktop/core/src/desktop/templates/hue.mako

@@ -26,6 +26,8 @@
   from dashboard.conf import IS_ENABLED as IS_DASHBOARD_ENABLED
   from indexer.conf import ENABLE_NEW_INDEXER
   from metadata.conf import has_optimizer, OPTIMIZER
+
+  from desktop.auth.backend import is_admin
 %>
 
 <%namespace name="koComponents" file="/ko_components.mako" />
@@ -247,7 +249,7 @@ ${ hueIcons.symbols() }
           % endif
 
           <%
-            view_profile = user.has_hue_permission(action="access_view:useradmin:edit_user", app="useradmin") or user.is_superuser
+            view_profile = user.has_hue_permission(action="access_view:useradmin:edit_user", app="useradmin") or is_admin(user)
           %>
           <button class="btn btn-flat" data-toggle="dropdown" data-bind="click: function(){ huePubSub.publish('hide.jobs.panel'); huePubSub.publish('hide.history.panel'); }">
             <i class="fa fa-user"></i> ${ user.username } <span class="caret"></span>
@@ -256,7 +258,7 @@ ${ hueIcons.symbols() }
             % if view_profile:
             <li><a href="javascript:void(0)" data-bind="hueLink: '/useradmin/users/edit/${ user.username }'" title="${ _('View Profile') if is_ldap_setup else _('Edit Profile') }"><i class="fa fa-fw fa-user"></i> ${_('My Profile')}</a></li>
             % endif
-            % if user.is_superuser:
+            % if is_admin(user):
             <li data-bind="hueLink: '/useradmin/users/'"><a href="javascript: void(0);"><i class="fa fa-fw fa-group"></i> ${_('Manage Users')}</a></li>
             % endif
             % if not conf.DISABLE_HUE_3.get():
@@ -264,7 +266,7 @@ ${ hueIcons.symbols() }
             % endif
             <li><a href="http://gethue.com" target="_blank"><span class="dropdown-no-icon">${_('Help')}</span></a></li>
             <li><a href="javascript:void(0)" onclick="huePubSub.publish('show.welcome.tour')"><span class="dropdown-no-icon">${_('Welcome Tour')}</span></a></li>
-            % if user.is_superuser:
+            % if is_admin(user):
             <li><a href="/about/"><span class="dropdown-no-icon">${_('Hue Administration')}</span></a></li>
             % endif
             <li class="divider"></li>
@@ -1527,7 +1529,7 @@ ${ smart_unicode(login_modal(request).content) | n,unicode }
                 }
               });
 
-              % if user.is_superuser and cluster != ANALYTIC_DB:
+              % if is_admin(user) and cluster != ANALYTIC_DB:
                 if (app.name === 'editor') {
                   interpreters.push({
                     displayName: '${ _('Add more...') }',
@@ -1754,7 +1756,7 @@ ${ smart_unicode(login_modal(request).content) | n,unicode }
       attachTo: '.navbar-default bottom'
     });
 
-    %if user.is_superuser:
+    %if is_admin(user):
       tour.addStep('admin', {
         text: '${ _ko('As a superuser, you can check system configuration from the username drop down and install sample data and jobs for your users.') }',
         attachTo: '.top-nav-right .dropdown bottom'

+ 3 - 2
desktop/core/src/desktop/templates/popup_error.mako

@@ -18,6 +18,7 @@
 from desktop.views import commonheader, commonfooter
 from desktop.lib.i18n import smart_unicode
 from django.utils.translation import ugettext as _
+from desktop.auth.backend import is_admin
 %>
 
 %if not is_embeddable:
@@ -41,7 +42,7 @@ ${ commonheader(title, "", user, request, "40px") | n,unicode }
             % if traceback:
               <a href="javascript:toggleDisplay('#traceback');"><i class="fa fa-share"></i> ${_('More Info')}</a>
               &nbsp;
-              % if user.is_superuser:
+              % if is_admin(user):
               <a href="/logs" target="_new">${_('View Logs')}</a>
               % endif
               <br />
@@ -67,7 +68,7 @@ ${ commonheader(title, "", user, request, "40px") | n,unicode }
                 </table>
               </div>
             % else:
-              % if user.is_superuser:
+              % if is_admin(user):
               <a href="/logs" target="_new">${_('View Logs')}</a>
               % endif
               <br />

+ 11 - 11
desktop/core/src/desktop/views.py

@@ -61,7 +61,7 @@ from desktop.log.access import access_log_level, access_warn, AccessInfo
 from desktop.log import set_all_debug as _set_all_debug, reset_all_debug as _reset_all_debug, get_all_debug as _get_all_debug
 from desktop.models import Settings, hue_version, _get_apps, UserPreferences
 
-
+from desktop.auth.backend import is_admin
 
 LOG = logging.getLogger(__name__)
 
@@ -182,7 +182,7 @@ def log_view(request):
   If it is attached to the root logger, this view will display that history,
   otherwise it will report that it can't be found.
   """
-  if not request.user.is_superuser:
+  if not is_admin(request.user):
     return HttpResponse(_("You must be a superuser."))
 
   hostname = socket.gethostname()
@@ -199,7 +199,7 @@ def download_log_view(request):
   """
   Zip up the log buffer and then return as a file attachment.
   """
-  if not request.user.is_superuser:
+  if not is_admin(request.user):
     return HttpResponse(_("You must be a superuser."))
 
   l = logging.getLogger()
@@ -279,7 +279,7 @@ def dump_config(request):
   show_private = False
   conf_dir = os.path.realpath(os.getenv("HUE_CONF_DIR", get_desktop_root("conf")))
 
-  if not request.user.is_superuser:
+  if not is_admin(request.user):
     return HttpResponse(_("You must be a superuser."))
 
   if request.GET.get("private"):
@@ -302,7 +302,7 @@ def threads(request):
   out = StringIO.StringIO()
   dump_traceback(file=out)
 
-  if not request.user.is_superuser:
+  if not is_admin(request.user):
     return HttpResponse(_("You must be a superuser."))
 
   if request.is_ajax():
@@ -314,7 +314,7 @@ def threads(request):
 @access_log_level(logging.WARN)
 def memory(request):
   """Dumps out server threads. Useful for debugging."""
-  if not request.user.is_superuser:
+  if not is_admin(request.user):
     return HttpResponse(_("You must be a superuser."))
 
   if not hasattr(settings, 'MEMORY_PROFILER'):
@@ -388,7 +388,7 @@ def index(request):
     except UserPreferences.DoesNotExist:
       pass
 
-  if request.user.is_superuser and request.COOKIES.get('hueLandingPage') != 'home' and not IS_HUE_4.get():
+  if is_admin(request.user) and request.COOKIES.get('hueLandingPage') != 'home' and not IS_HUE_4.get():
     return redirect(reverse('about:index'))
   else:
     if is_hue_4:
@@ -710,7 +710,7 @@ def collect_validation_messages(conf, error_list):
 
 def check_config(request):
   """Check config and view for the list of errors"""
-  if not request.user.is_superuser:
+  if not is_admin(request.user):
     return HttpResponse(_("You must be a superuser."))
 
   context = {
@@ -726,7 +726,7 @@ def check_config(request):
 
 def check_config_ajax(request):
   """Alert administrators about configuration problems."""
-  if not request.user.is_superuser:
+  if not is_admin(request.user):
     return HttpResponse('')
 
   error_list = _get_config_errors(request)
@@ -745,7 +745,7 @@ def get_debug_level(request):
 
 @require_POST
 def set_all_debug(request):
-  if not request.user.is_superuser:
+  if not is_admin(request.user):
     return JsonResponse({'status': 1, 'message': _('You must be a superuser.')})
 
   _set_all_debug()
@@ -755,7 +755,7 @@ def set_all_debug(request):
 
 @require_POST
 def reset_all_debug(request):
-  if not request.user.is_superuser:
+  if not is_admin(request.user):
     return JsonResponse({'status': 1, 'message': _('You must be a superuser.')})
 
   _reset_all_debug()

+ 2 - 2
desktop/libs/aws/src/aws/conf.py

@@ -28,7 +28,6 @@ import aws
 from desktop.lib.conf import Config, UnspecifiedConfigSection, ConfigSection, coerce_bool, coerce_password_from_script
 from hadoop.core_site import get_s3a_access_key, get_s3a_secret_key
 
-
 LOG = logging.getLogger(__name__)
 
 
@@ -209,7 +208,8 @@ def has_iam_metadata():
 
 
 def has_s3_access(user):
-  return user.is_authenticated() and user.is_active and (user.is_superuser or user.has_hue_permission(action="s3_access", app="filebrowser"))
+  from desktop.auth.backend import is_admin
+  return user.is_authenticated() and user.is_active and (is_admin(user) or user.has_hue_permission(action="s3_access", app="filebrowser"))
 
 
 def config_validator(user):

+ 2 - 2
desktop/libs/azure/src/azure/conf.py

@@ -23,7 +23,6 @@ from django.utils.translation import ugettext_lazy as _, ugettext as _t
 from desktop.lib.conf import Config, UnspecifiedConfigSection, ConfigSection, coerce_password_from_script
 from hadoop.core_site import get_adls_client_id, get_adls_authentication_code, get_adls_refresh_url
 
-
 LOG = logging.getLogger(__name__)
 
 REFRESH_URL = 'https://login.microsoftonline.com/<tenant_id>/oauth2/token'
@@ -127,7 +126,8 @@ def is_adls_enabled():
   return ('default' in AZURE_ACCOUNTS.keys() and AZURE_ACCOUNTS['default'].get_raw() and AZURE_ACCOUNTS['default'].CLIENT_ID.get() is not None)
 
 def has_adls_access(user):
-  return user.is_authenticated() and user.is_active and (user.is_superuser or user.has_hue_permission(action="adls_access", app="filebrowser"))
+  from desktop.auth.backend import is_admin
+  return user.is_authenticated() and user.is_active and (is_admin(user) or user.has_hue_permission(action="adls_access", app="filebrowser"))
 
 def config_validator(user):
   res = []

+ 3 - 2
desktop/libs/dashboard/src/dashboard/controller.py

@@ -25,6 +25,7 @@ from desktop.models import Document2, Document, SAMPLE_USER_OWNERS
 
 from dashboard.models import Collection2
 
+from desktop.auth.backend import is_admin
 
 LOG = logging.getLogger(__name__)
 
@@ -50,13 +51,13 @@ class DashboardController(object):
 
   def get_owner_search_collections(self):
     if USE_NEW_EDITOR.get():
-      if self.user.is_superuser:
+      if is_admin(self.user):
         docs = Document2.objects.filter(type='search-dashboard')
       else:
         docs = Document2.objects.filter(type='search-dashboard', owner=self.user)
       return docs
     else:
-      if self.user.is_superuser:
+      if is_admin(self.user):
         docs = Document.objects.filter(extra='search-dashboard')
       else:
         docs = Document.objects.filter(extra='search-dashboard', owner=self.user)

+ 2 - 1
desktop/libs/dashboard/src/dashboard/templates/no_collections.mako

@@ -18,6 +18,7 @@
 from django.utils.translation import ugettext as _
 from desktop.views import commonheader, commonfooter
 from indexer.conf import ENABLE_NEW_INDEXER
+from desktop.auth.backend import is_admin
 %>
 
 <%namespace name="macros" file="macros.mako" />
@@ -45,7 +46,7 @@ ${ commonheader(_('Dashboard'), "dashboard", user, request, "120px") | n,unicode
 
       <i class="fa fa-search waiting"></i>
       <h1>${ _('It seems there is nothing to search on ...') }</h1>
-      % if user.is_superuser:
+      % if is_admin(user):
       <h1>
         ${ _('What about creating a') }
         % if ENABLE_NEW_INDEXER.get():

+ 3 - 1
desktop/libs/liboozie/src/liboozie/types.py

@@ -39,6 +39,8 @@ from liboozie.utils import parse_timestamp, format_time, catch_unicode_time
 from django.utils.translation import ugettext as _
 from django.urls import reverse
 
+from desktop.auth.backend import is_admin
+
 LOG = logging.getLogger(__name__)
 
 
@@ -384,7 +386,7 @@ class Job(object):
 
   def check_request_permission(self, request):
     """Raise PopupException if request user doesn't have permission to modify workflow"""
-    if not request.user.is_superuser and request.user.username != self.user:
+    if not is_admin(request.user) and request.user.username != self.user:
       access_warn(request, _('Insufficient permission.'))
       raise PopupException(_("Permission denied. User %(username)s cannot modify user %(user)s's job.") %
                            dict(username=request.user.username, user=self.user))

+ 2 - 2
desktop/libs/metadata/src/metadata/conf.py

@@ -27,7 +27,6 @@ from desktop.lib.paths import get_config_root
 
 from metadata.settings import DJANGO_APPS
 
-
 OPTIMIZER_AUTH_PASSWORD = None
 NAVIGATOR_AUTH_PASSWORD = None
 
@@ -64,8 +63,9 @@ def get_navigator_url():
   return NAVIGATOR.API_URL.get() and NAVIGATOR.API_URL.get().strip('/')[:-3]
 
 def has_navigator(user):
+  from desktop.auth.backend import is_admin
   return bool(get_navigator_url() and get_navigator_auth_password()) \
-      and (user.is_superuser or user.has_hue_permission(action="access", app=DJANGO_APPS[0]))
+      and (is_admin(user) or user.has_hue_permission(action="access", app=DJANGO_APPS[0]))
 
 
 def get_security_default():

+ 2 - 1
desktop/libs/metadata/src/metadata/optimizer_api.py

@@ -34,6 +34,7 @@ from notebook.models import Notebook
 from metadata.optimizer_client import OptimizerApi, NavOptException, _get_table_name, _clean_query
 from metadata.conf import OPTIMIZER
 
+from desktop.auth.backend import is_admin
 
 LOG = logging.getLogger(__name__)
 
@@ -325,7 +326,7 @@ def _convert_queries(queries_data):
 def upload_history(request):
   response = {'status': -1}
 
-  if request.user.is_superuser:
+  if is_admin(request.user):
     api = OptimizerApi(request.user)
     histories = []
     upload_stats = {}

+ 2 - 1
desktop/libs/metadata/src/metadata/optimizer_client.py

@@ -38,6 +38,7 @@ from navoptapi.api_lib import ApiLib
 
 from metadata.conf import OPTIMIZER, get_optimizer_url
 
+from desktop.auth.backend import is_admin
 
 LOG = logging.getLogger(__name__)
 
@@ -229,7 +230,7 @@ class OptimizerApi(object):
     }
 
   def similar_queries(self, source_platform, query, page_size=100, startingToken=None):
-    if self.user.is_superuser:
+    if is_admin(self.user):
       return self._call('getSimilarQueries', {'tenant' : self._tenant_id, 'sourcePlatform': source_platform, 'query': query, 'pageSize': page_size, 'startingToken': startingToken})
     else:
       raise PopupException(_('Call not supported'))

+ 2 - 1
desktop/libs/notebook/src/notebook/connectors/hiveserver2.py

@@ -39,6 +39,7 @@ from metadata.optimizer_client import OptimizerApi
 
 from notebook.connectors.base import Api, QueryError, QueryExpired, OperationTimeout, OperationNotSupported, _get_snippet_name, Notebook
 
+from desktop.auth.backend import is_admin
 
 LOG = logging.getLogger(__name__)
 
@@ -212,7 +213,7 @@ class HS2Api(Api):
 
     try:
       filters = {'id': session_id, 'application': query_server['server_name']}
-      if not self.user.is_superuser:
+      if not is_admin(self.user):
         filters['owner'] = self.user
       session = Session.objects.get(**filters)
     except Session.DoesNotExist:

+ 2 - 1
desktop/libs/notebook/src/notebook/templates/editor_components.mako

@@ -24,6 +24,7 @@ from desktop.views import _ko, antixss
 from desktop.conf import IS_EMBEDDED
 from metadata.conf import has_optimizer, OPTIMIZER
 from notebook.conf import ENABLE_QUERY_BUILDER, ENABLE_QUERY_SCHEDULING, ENABLE_BATCH_EXECUTE, ENABLE_EXTERNAL_STATEMENT, ENABLE_PRESENTATION
+from desktop.auth.backend import is_admin
 %>
 
 <%def name="includes(is_embeddable=False, suffix='')">
@@ -1910,7 +1911,7 @@ ${ sqlSyntaxDropdown.sqlSyntaxDropdown() }
             <i class="fa fa-fw fa-random"></i> ${_('Check compatibility')}
           </a>
         </li>
-        % if conf.DJANGO_DEBUG_MODE.get() and user.is_superuser:
+        % if conf.DJANGO_DEBUG_MODE.get() and is_admin(user):
         <li>
           <a href="javascript:void(0)" data-bind="click: function() { huePubSub.publish('editor.upload.history'); }" title="${ _('Load recent queries in order to improve recommendations') }">
             <i class="fa fa-fw fa-cloud-upload"></i> ${_('Upload history')}