Browse Source

HUE-7407 [useradmin] Added superuser group priv to useradmin

Chris Conner 7 years ago
parent
commit
59482ae
54 changed files with 251 additions and 127 deletions
  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. 7 8
      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.conf import IS_HUE_4
 from desktop.views import commonheader, commonfooter
 from desktop.views import commonheader, commonfooter
 from metadata.conf import OPTIMIZER, has_optimizer
 from metadata.conf import OPTIMIZER, has_optimizer
+
+from desktop.auth.backend import is_admin
 %>
 %>
 
 
 <%namespace name="layout" file="/about_layout.mako" />
 <%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 class="row-fluid" style="margin-bottom: 100px;">
     <div>
     <div>
       <h1 class="margin-top-20 margin-bottom-30">
       <h1 class="margin-top-20 margin-bottom-30">
-        % if user.is_superuser:
+        % if is_admin(user):
           ${ _('Quick Start Wizard') } -
           ${ _('Quick Start Wizard') } -
         % endif
         % 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>
         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>
       </h1>
 
 
-     % if user.is_superuser:
+     % if is_admin(user):
 
 
       <div class="margin-bottom-30">
       <div class="margin-bottom-30">
          <div class="row-fluid">
          <div class="row-fluid">
@@ -238,7 +240,7 @@ ${ layout.menubar(section='quick_start') }
 
 
 </div>
 </div>
 
 
-% if user.is_superuser:
+% if is_admin(user):
 <style type="text/css">
 <style type="text/css">
   .steps {
   .steps {
     min-height: 300px;
     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.models import Settings, hue_version
 from desktop.views import collect_usage
 from desktop.views import collect_usage
 
 
+from desktop.auth.backend import is_admin
+
 
 
 def admin_wizard(request):
 def admin_wizard(request):
-  if request.user.is_superuser:
+  if is_admin(request.user):
     apps = appmanager.get_apps(request.user)
     apps = appmanager.get_apps(request.user)
   else:
   else:
     apps = []
     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.conf import FORCE_HS2_METADATA
 from metastore.views import _get_db, _get_servername
 from metastore.views import _get_db, _get_servername
 
 
+from desktop.auth.backend import is_admin
 
 
 LOG = logging.getLogger(__name__)
 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)
   app_name = None if FORCE_HS2_METADATA.get() else get_app_name(request)
 
 
   do_as = request.user
   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'))
     do_as = User.objects.get(username=request.GET.get('doas'))
 
 
   db = _get_db(user=do_as, source_type=app_name)
   db = _get_db(user=do_as, source_type=app_name)
@@ -845,7 +846,7 @@ def close_session(request, session_id):
 
 
   try:
   try:
     filters = {'id': session_id, 'application': query_server['server_name']}
     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
       filters['owner'] = request.user
     session = Session.objects.get(**filters)
     session = Session.objects.get(**filters)
   except Session.DoesNotExist:
   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 import dbms
 from beeswax.server.dbms import expand_exception, get_query_server_config, QueryServerException
 from beeswax.server.dbms import expand_exception, get_query_server_config, QueryServerException
 
 
+from desktop.auth.backend import is_admin
+
 
 
 LOG = logging.getLogger(__name__)
 LOG = logging.getLogger(__name__)
 
 
@@ -341,7 +343,7 @@ def list_query_history(request):
   DEFAULT_PAGE_SIZE = 100
   DEFAULT_PAGE_SIZE = 100
   prefix = 'q-'
   prefix = 'q-'
 
 
-  share_queries = request.user.is_superuser
+  share_queries = is_admin(request.user)
 
 
   querydict_query = request.GET.copy()
   querydict_query = request.GET.copy()
   if not share_queries:
   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
   # 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 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})
       raise PopupException(_('Permission denied to read QueryHistory %(id)s') % {'id': query_history_id})
   else:
   else:
     query_history.design.doc.get().can_read_or_exception(request.user)
     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
                               TrashPurgeForm, SetReplicationFactorForm
 
 
 
 
+from desktop.auth.backend import is_admin
+
 DEFAULT_CHUNK_SIZE_BYTES = 1024 * 4 # 4KB
 DEFAULT_CHUNK_SIZE_BYTES = 1024 * 4 # 4KB
 MAX_CHUNK_SIZE_BYTES = 1024 * 1024 # 1MB
 MAX_CHUNK_SIZE_BYTES = 1024 * 1024 # 1MB
 DOWNLOAD_CHUNK_SIZE = 1 * 1024 * 1024 # 1MB
 DOWNLOAD_CHUNK_SIZE = 1 * 1024 * 1024 # 1MB
@@ -214,7 +216,7 @@ def view(request, path):
         if "Connection refused" in e.message:
         if "Connection refused" in e.message:
             msg += _(" The HDFS REST service is not available. ")
             msg += _(" The HDFS REST service is not available. ")
         elif request.fs._get_scheme(path).lower() == 'hdfs':
         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".') \
                 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}
                         % {'superuser': request.fs.superuser, 'supergroup': request.fs.supergroup}
 
 
@@ -428,7 +430,7 @@ def listdir_paged(request, path):
     pagenum = int(request.GET.get('pagenum', 1))
     pagenum = int(request.GET.get('pagenum', 1))
     pagesize = int(request.GET.get('pagesize', 30))
     pagesize = int(request.GET.get('pagesize', 30))
     do_as = None
     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)
       do_as = request.GET.get('doas', request.user.username)
     if hasattr(request, 'doas'):
     if hasattr(request, 'doas'):
       do_as = 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:
             except (IOError, WebHdfsException), e:
                 msg = _("Cannot perform operation.")
                 msg = _("Cannot perform operation.")
                 # TODO: Only apply this message for HDFS
                 # 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".') \
                     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}
                            % {'superuser': request.fs.superuser, 'supergroup': request.fs.supergroup}
                 if request.is_ajax():
                 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.management.commands import hbase_setup
 from hbase.server.hbase_lib import get_thrift_type
 from hbase.server.hbase_lib import get_thrift_type
 
 
+from desktop.auth.backend import is_admin
 
 
 LOG = logging.getLogger(__name__)
 LOG = logging.getLogger(__name__)
 
 
 
 
 def has_write_access(user):
 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):
 def app(request):
   return render('app.mako', 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.conf import SHARE_JOBS
 from jobbrowser.yarn_models import Application, OozieYarnJob, Job as YarnJob, KilledJob as KilledYarnJob, Container, SparkJob
 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__)
 LOG = logging.getLogger(__name__)
@@ -123,11 +124,11 @@ class YarnApi(JobBrowserApi):
     return int(elapsed_time.days * 86400 + elapsed_time.seconds) * 1000
     return int(elapsed_time.days * 86400 + elapsed_time.seconds) * 1000
 
 
   def filter_jobs(self, user, jobs, **kwargs):
   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:
     return filter(lambda job:
                   not check_permission or
                   not check_permission or
-                  user.is_superuser or
+                  is_admin(user) or
                   job.user == user.username, jobs)
                   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 desktop.lib.view_util import location_to_url
 
 
 from jobbrowser.conf import DISABLE_KILLING_JOBS
 from jobbrowser.conf import DISABLE_KILLING_JOBS
+from desktop.auth.backend import is_admin
 
 
 
 
 LOG = logging.getLogger(__name__)
 LOG = logging.getLogger(__name__)
@@ -56,7 +57,7 @@ def can_kill_job(self, user):
   if self.status.lower() not in ('running', 'pending', 'accepted'):
   if self.status.lower() not in ('running', 'pending', 'accepted'):
     return False
     return False
 
 
-  if user.is_superuser:
+  if is_admin(user):
     return True
     return True
 
 
   if can_modify_job(user.username, self):
   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 import cluster
 from hadoop.yarn.clients import get_log_client
 from hadoop.yarn.clients import get_log_client
 from hadoop.yarn import resource_manager_api as resource_manager_api
 from hadoop.yarn import resource_manager_api as resource_manager_api
+from desktop.auth.backend import is_admin
 
 
 
 
 LOG = logging.getLogger(__name__)
 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)
       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)
       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):
         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})
       raise PopupException(_("You don't have permission to access job %(id)s.") % {'id': jobid})
     kwargs['job'] = job
     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,\
 from oozie.utils import model_to_dict, format_dict_field_values,\
                         sanitize_node_dict
                         sanitize_node_dict
 
 
+from desktop.auth.backend import is_admin
 
 
 LOG = logging.getLogger(__name__)
 LOG = logging.getLogger(__name__)
 MAX_DESIGNS = 250
 MAX_DESIGNS = 250
@@ -124,7 +125,7 @@ def _get_design(user, design_id):
 def _check_permission(request, owner_name, error_msg, allow_root=False):
 def _check_permission(request, owner_name, error_msg, allow_root=False):
   """Raise PopupException if user doesn't have permission to modify the design"""
   """Raise PopupException if user doesn't have permission to modify the design"""
   if request.user.username != owner_name:
   if request.user.username != owner_name:
-    if allow_root and request.user.is_superuser:
+    if allow_root and is_admin(request.user):
       return
       return
     access_warn(request, error_msg)
     access_warn(request, error_msg)
     raise PopupException(_("Permission denied. You are not the owner."))
     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.forms import LoadDataForm, DbForm
 from metastore.settings import DJANGO_APPS
 from metastore.settings import DJANGO_APPS
 
 
+from desktop.auth.backend import is_admin
 
 
 LOG = logging.getLogger(__name__)
 LOG = logging.getLogger(__name__)
 
 
@@ -656,7 +657,7 @@ def drop_partition(request, database, table):
 
 
 
 
 def has_write_access(user):
 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 oozie.models import Job, Node, Dataset
 
 
+from desktop.auth.backend import is_admin
+
 
 
 LOG = logging.getLogger(__name__)
 LOG = logging.getLogger(__name__)
 
 
@@ -108,7 +110,7 @@ def check_document_modify_permission():
 def check_editor_access_permission(view_func):
 def check_editor_access_permission(view_func):
 
 
   def decorate(request, *args, **kwargs):
   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)
       raise PopupException(_('Missing permission to access the Oozie Editor'), error_code=401)
     return view_func(request, *args, **kwargs)
     return view_func(request, *args, **kwargs)
   return wraps(view_func)(decorate)
   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.utils import utc_datetime_format
 from oozie.timezones import TIMEZONES
 from oozie.timezones import TIMEZONES
 
 
+from desktop.auth.backend import is_admin
+
 
 
 LOG = logging.getLogger(__name__)
 LOG = logging.getLogger(__name__)
 
 
@@ -223,7 +225,7 @@ class Job(models.Model):
       raise e
       raise e
 
 
   def is_editable(self, user):
   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
   @property
   def data_dict(self):
   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.settings import DJANGO_APPS
 from oozie.utils import convert_to_server_timezone
 from oozie.utils import convert_to_server_timezone
 
 
+from desktop.auth.backend import is_admin
 
 
 def get_history():
 def get_history():
   if ENABLE_V2.get():
   if ENABLE_V2.get():
@@ -1172,7 +1173,7 @@ def check_job_access_permission(request, job_id, **kwargs):
       LOG.exception(msg)
       LOG.exception(msg)
       raise PopupException(msg, detail=ex._headers.get('oozie-error-message'))
       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 oozie_job.user == request.user.username \
       or has_dashboard_jobs_access(request.user):
       or has_dashboard_jobs_access(request.user):
     return oozie_job
     return oozie_job
@@ -1193,8 +1194,8 @@ def check_job_edition_permission(oozie_job, user):
 
 
 
 
 def has_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):
 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,\
                         BundleForm, BundledCoordinatorForm, design_form_by_type,\
                         ImportWorkflowForm, ImportCoordinatorForm
                         ImportWorkflowForm, ImportCoordinatorForm
 
 
+from desktop.auth.backend import is_admin
 
 
 LOG = logging.getLogger(__name__)
 LOG = logging.getLogger(__name__)
 
 
@@ -902,7 +903,7 @@ def list_history(request):
   """
   """
   history = History.objects
   history = History.objects
 
 
-  if not request.user.is_superuser:
+  if not is_admin(request.user):
     history = history.filter(submitter=request.user)
     history = history.filter(submitter=request.user)
   history = history.order_by('-submission_date')
   history = history.order_by('-submission_date')
 
 
@@ -918,7 +919,7 @@ def list_history_record(request, record_id):
   """
   """
   history = History.objects
   history = History.objects
 
 
-  if not request.user.is_superuser:
+  if not is_admin(request.user):
     history.filter(submitter=request.user)
     history.filter(submitter=request.user)
   history = history.get(id=record_id)
   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.models import Workflow, Pig
 from oozie.views.api import get_log as get_workflow_logs
 from oozie.views.api import get_log as get_workflow_logs
 from oozie.views.editor import _submit_workflow
 from oozie.views.editor import _submit_workflow
+from desktop.auth.backend import is_admin
 
 
 
 
 LOG = logging.getLogger(__name__)
 LOG = logging.getLogger(__name__)
@@ -240,5 +241,5 @@ def format_time(st_time):
 
 
 
 
 def has_job_edition_permission(oozie_job, user):
 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.lib.exceptions_renderable import PopupException
 from desktop.models import Document as Doc, SAMPLE_USER_ID
 from desktop.models import Document as Doc, SAMPLE_USER_ID
 from hadoop.fs.hadoopfs import Hdfs
 from hadoop.fs.hadoopfs import Hdfs
+from desktop.auth.backend import is_admin
 
 
 
 
 class Document(models.Model):
 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.'))
                                      help_text=_t('If the document is not a submitted job but a real query, script, workflow.'))
 
 
   def is_editable(self, user): # Deprecated
   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
   def can_edit_or_exception(self, user, exception_class=PopupException): # Deprecated
     if self.is_editable(user):
     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 search.management.commands import search_setup
 
 
+from desktop.auth.backend import is_admin
+
 
 
 LOG = logging.getLogger(__name__)
 LOG = logging.getLogger(__name__)
 
 
@@ -31,7 +33,7 @@ LOG = logging.getLogger(__name__)
 def install_examples(request):
 def install_examples(request):
   result = {'status': -1, 'message': ''}
   result = {'status': -1, 'message': ''}
 
 
-  if not request.user.is_superuser:
+  if not is_admin(request.user):
     return PopupException(_("You must be a superuser."))
     return PopupException(_("You must be a superuser."))
 
 
   if request.method != 'POST':
   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 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 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):
 def hive(request):
@@ -67,4 +68,4 @@ def hdfs(request):
 
 
 
 
 def _has_impersonation_perm(user):
 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 import appmanager
 from desktop.lib.exceptions_renderable import PopupException
 from desktop.lib.exceptions_renderable import PopupException
-from desktop.models import SAMPLE_USER_ID, SAMPLE_USER_INSTALL, HueUser
 from hadoop import cluster
 from hadoop import cluster
 
 
 import useradmin.conf
 import useradmin.conf
@@ -276,6 +275,7 @@ def update_app_permissions(**kwargs):
     if default_group:
     if default_group:
       for new_dp in added:
       for new_dp in added:
         if not (new_dp.app == 'useradmin' and new_dp.action == 'access') and \
         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 == 'metastore' and new_dp.action == 'write') and \
            not (new_dp.app == 'hbase' 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 \
            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.
   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
   user = None
 
 
   try:
   try:

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

@@ -22,4 +22,5 @@ MENU_INDEX = 60
 
 
 PERMISSION_ACTIONS = (
 PERMISSION_ACTIONS = (
   ("access_view:useradmin:edit_user", "Access to profile page on User Admin"),
   ("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.hue_password_policy import is_password_policy_enabled, get_password_hint
 from useradmin.views import is_user_locked_out
 from useradmin.views import is_user_locked_out
+from desktop.auth.backend import is_admin
 %>
 %>
 
 
 <%namespace name="layout" file="layout.mako" />
 <%namespace name="layout" file="layout.mako" />
@@ -52,9 +53,9 @@ ${ layout.menubar(section='users') }
           % endif
           % endif
           </a>
           </a>
         </li>
         </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>
         </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>
             <li><a href="javascript:void(0)" class="step" data-step="step3">${ _('Step 3: Advanced') }</a></li>
         % endif
         % endif
       </ul>
       </ul>
@@ -88,11 +89,11 @@ ${ layout.menubar(section='users') }
             ${layout.render_field(form["language"])}
             ${layout.render_field(form["language"])}
           % endif
           % endif
 
 
-          % if user.is_superuser:
+          % if is_admin(user):
             ${layout.render_field(form["groups"])}
             ${layout.render_field(form["groups"])}
           % endif
           % endif
         </div>
         </div>
-      % if user.is_superuser:
+      % if is_admin(user):
         <div id="step3" class="stepDetails hide">
         <div id="step3" class="stepDetails hide">
           ${layout.render_field(form["is_active"])}
           ${layout.render_field(form["is_active"])}
           ${'is_superuser' in form.fields and layout.render_field(form["is_superuser"])}
           ${'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 desktop import conf
 from django.utils.translation import ugettext as _
 from django.utils.translation import ugettext as _
+from desktop.auth.backend import is_admin
 
 
 def is_selected(section, matcher):
 def is_selected(section, matcher):
   if section == matcher:
   if section == matcher:
@@ -55,12 +56,12 @@ def is_selected(section, matcher):
           <div class="nav-collapse">
           <div class="nav-collapse">
             <ul class="nav">
             <ul class="nav">
               <li class="app-header">
               <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') }" />
                   <img src="${ static('useradmin/art/icon_useradmin_48.png') }" class="app-icon" alt="${ _('User admin icon') }" />
                   ${ _('User Admin') }
                   ${ _('User Admin') }
                 </a>
                 </a>
               </li>
               </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, '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, '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>
                 <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 django.utils.translation import ugettext as _
 from useradmin.models import group_permissions
 from useradmin.models import group_permissions
+from desktop.auth.backend import is_admin
 
 
 from desktop.views import commonheader, commonfooter, antixss
 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...')}">
           <input type="text" class="input-xlarge search-query filter-input" placeholder="${_('Search for name, members, etc...')}">
       </%def>
       </%def>
       <%def name="actions()">
       <%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>
             <button class="btn delete-group-btn confirmationModal" title="${_('Delete')}" disabled="disabled"><i class="fa fa-trash-o"></i> ${_('Delete')}</button>
         %endif
         %endif
       </%def>
       </%def>
       <%def name="creation()">
       <%def name="creation()">
-        %if user.is_superuser:
+        %if is_admin(user):
           <a id="addGroupBtn" href="${url('useradmin.views.edit_group')}" class="btn"><i
           <a id="addGroupBtn" href="${url('useradmin.views.edit_group')}" class="btn"><i
               class="fa fa-plus-circle"></i> ${_('Add group')}</a>
               class="fa fa-plus-circle"></i> ${_('Add group')}</a>
           % if is_ldap_setup:
           % if is_ldap_setup:
@@ -62,7 +63,7 @@ ${layout.menubar(section='groups')}
     <table class="table table-condensed datatables">
     <table class="table table-condensed datatables">
       <thead>
       <thead>
       <tr>
       <tr>
-        %if user.is_superuser:
+        %if is_admin(user):
             <th width="1%">
             <th width="1%">
               <div class="select-all hue-checkbox fa"></div>
               <div class="select-all hue-checkbox fa"></div>
             </th>
             </th>
@@ -76,13 +77,13 @@ ${layout.menubar(section='groups')}
           % for group in groups:
           % for group in groups:
           <tr class="tableRow"
           <tr class="tableRow"
               data-search="${group.name}${', '.join([group_user.username for group_user in group.user_set.all()])}">
               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">
             <td data-row-selector-exclude="true">
               <div class="hue-checkbox groupCheck fa" data-name="${group.name}" data-row-selector-exclude="true"></div>
               <div class="hue-checkbox groupCheck fa" data-name="${group.name}" data-row-selector-exclude="true"></div>
             </td>
             </td>
           %endif
           %endif
           <td>
           <td>
-            %if user.is_superuser:
+            %if is_admin(user):
               <strong><a title="${ _('Edit %(groupname)s') % dict(groupname=group.name) }"
               <strong><a title="${ _('Edit %(groupname)s') % dict(groupname=group.name) }"
                          href="${ url('useradmin.views.edit_group', name=group.name) }"
                          href="${ url('useradmin.views.edit_group', name=group.name) }"
                          data-row-selector="true">${group.name}</a></strong>
                          data-row-selector="true">${group.name}</a></strong>
@@ -152,7 +153,7 @@ ${layout.menubar(section='groups')}
       "bFilter": true,
       "bFilter": true,
       "bAutoWidth": false,
       "bAutoWidth": false,
       "aoColumns": [
       "aoColumns": [
-        %if user.is_superuser:
+        %if is_admin(user):
             { "bSortable": false },
             { "bSortable": false },
         %endif
         %endif
         { "sWidth": "20%" },
         { "sWidth": "20%" },

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

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

+ 7 - 8
apps/useradmin/src/useradmin/templates/list_users.mako

@@ -19,8 +19,7 @@ from django.utils.translation import ugettext as _
 
 
 from desktop.lib.django_util import USERNAME_RE_RULE
 from desktop.lib.django_util import USERNAME_RE_RULE
 from desktop.views import commonheader, commonfooter, antixss
 from desktop.views import commonheader, commonfooter, antixss
-
-import re
+from desktop.auth.backend import is_admin
 %>
 %>
 
 
 <%namespace name="actionbar" file="actionbar.mako" />
 <%namespace name="actionbar" file="actionbar.mako" />
@@ -41,12 +40,12 @@ ${layout.menubar(section='users')}
           <input type="text" class="input-xlarge search-query filter-input" placeholder="${_('Search for name, group, etc...')}">
           <input type="text" class="input-xlarge search-query filter-input" placeholder="${_('Search for name, group, etc...')}">
       </%def>
       </%def>
       <%def name="actions()">
       <%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>
             <button class="btn delete-user-btn" title="${_('Delete')}" disabled="disabled"><i class="fa fa-trash-o"></i> ${_('Delete')}</button>
         %endif
         %endif
       </%def>
       </%def>
       <%def name="creation()">
       <%def name="creation()">
-        %if user.is_superuser:
+        %if is_admin(user):
             % if not is_ldap_setup:
             % if not is_ldap_setup:
               <a href="${ url('useradmin.views.edit_user') }" class="btn"><i class="fa fa-user"></i> ${_('Add user')}</a>
               <a href="${ url('useradmin.views.edit_user') }" class="btn"><i class="fa fa-user"></i> ${_('Add user')}</a>
             %endif
             %endif
@@ -70,7 +69,7 @@ ${layout.menubar(section='users')}
     <table class="table table-condensed datatables">
     <table class="table table-condensed datatables">
       <thead>
       <thead>
       <tr>
       <tr>
-        %if user.is_superuser:
+        %if is_admin(user):
             <th width="1%">
             <th width="1%">
               <div class="select-all hue-checkbox fa"></div>
               <div class="select-all hue-checkbox fa"></div>
             </th>
             </th>
@@ -87,13 +86,13 @@ ${layout.menubar(section='users')}
           % for listed_user in users:
           % for listed_user in users:
           <tr class="tableRow"
           <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()])}">
               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">
               <td data-row-selector-exclude="true">
                 <div class="hue-checkbox userCheck fa" data-row-selector-exclude="true" data-id="${ listed_user.id }"></div>
                 <div class="hue-checkbox userCheck fa" data-row-selector-exclude="true" data-id="${ listed_user.id }"></div>
               </td>
               </td>
           %endif
           %endif
           <td>
           <td>
-            %if (user.is_superuser 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:
               <strong><a title="${_('Edit %(username)s') % dict(username=listed_user.username)}"
               <strong><a title="${_('Edit %(username)s') % dict(username=listed_user.username)}"
                          href="${ url('useradmin.views.edit_user', username=listed_user.username) }"
                          href="${ url('useradmin.views.edit_user', username=listed_user.username) }"
                          data-row-selector="true">${listed_user.username}</a></strong>
                          data-row-selector="true">${listed_user.username}</a></strong>
@@ -171,7 +170,7 @@ ${layout.menubar(section='users')}
       "bInfo": false,
       "bInfo": false,
       "bFilter": true,
       "bFilter": true,
       "aoColumns": [
       "aoColumns": [
-        %if user.is_superuser:
+        %if is_admin(user):
             { "bSortable": false },
             { "bSortable": false },
         %endif
         %endif
         null,
         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.models import get_profile, get_default_user_group
 from useradmin.hue_password_policy import reset_password_policy
 from useradmin.hue_password_policy import reset_password_policy
 
 
+from desktop.auth.backend import is_admin
+
 
 
 def reset_all_users():
 def reset_all_users():
   """Reset to a clean state by deleting all users"""
   """Reset to a clean state by deleting all users"""
@@ -272,6 +274,44 @@ class TestUserAdmin(BaseUserAdminTests):
            save="Save"), follow=True)
            save="Save"), follow=True)
     assert_true(len(GroupPermission.objects.all()) == 1)
     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
     # Now test that we have limited access
     c1 = make_logged_in_client(username="nonadmin", is_superuser=False)
     c1 = make_logged_in_client(username="nonadmin", is_superuser=False)
     response = c1.get('/useradmin/users')
     response = c1.get('/useradmin/users')
@@ -282,6 +322,13 @@ class TestUserAdmin(BaseUserAdminTests):
     test_user.groups.add(Group.objects.get(name='test-group'))
     test_user.groups.add(Group.objects.get(name='test-group'))
     test_user.save()
     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
     # Check that we have access now
     response = c1.get('/useradmin/users')
     response = c1.get('/useradmin/users')
     assert_true(get_profile(test_user).has_hue_permission('access','useradmin'))
     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, \
   PermissionsEditForm, GroupEditForm, SuperUserChangeForm, UserChangeForm, validate_username, validate_first_name, \
   validate_last_name, PasswordChangeForm
   validate_last_name, PasswordChangeForm
 
 
+from desktop.auth.backend import is_admin
 
 
 LOG = logging.getLogger(__name__)
 LOG = logging.getLogger(__name__)
 
 
@@ -99,7 +100,7 @@ def list_configurations(request):
 def list_for_autocomplete(request):
 def list_for_autocomplete(request):
   extended_user_object = request.GET.get('extend_user') == 'true'
   extended_user_object = request.GET.get('extend_user') == 'true'
   autocomplete_filter = request.GET.get('filter', "")
   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')
     users = User.objects.filter(username__icontains=autocomplete_filter).order_by('username')
     groups = Group.objects.filter(name__icontains=autocomplete_filter).order_by('name')
     groups = Group.objects.filter(name__icontains=autocomplete_filter).order_by('name')
     if request.GET.get('only_mygroups'):
     if request.GET.get('only_mygroups'):
@@ -166,7 +167,7 @@ def is_user_locked_out(username):
 
 
 
 
 def delete_user(request):
 def delete_user(request):
-  if not request.user.is_superuser:
+  if not is_admin(request.user):
     request.audit = {
     request.audit = {
       'operation': 'DELETE_USER',
       'operation': 'DELETE_USER',
       'operationText': _get_failed_operation_text(request.user.username, 'DELETE_USER'),
       'operationText': _get_failed_operation_text(request.user.username, 'DELETE_USER'),
@@ -206,7 +207,7 @@ def delete_user(request):
 
 
 
 
 def delete_group(request):
 def delete_group(request):
-  if not request.user.is_superuser:
+  if not is_admin(request.user):
     request.audit = {
     request.audit = {
       'operation': 'DELETE_GROUP',
       'operation': 'DELETE_GROUP',
        'operationText': _get_failed_operation_text(request.user.username, '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
   @type username:       string
   @param username:      Default to None, when creating a new user
   @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}
     request.audit = {'allowed': False}
     if username is not None:
     if username is not None:
       request.audit['operation'] = 'EDIT_USER'
       request.audit['operation'] = 'EDIT_USER'
@@ -278,14 +279,14 @@ def edit_user(request, username=None):
 
 
   if require_change_password(userprofile):
   if require_change_password(userprofile):
     form_class = PasswordChangeForm
     form_class = PasswordChangeForm
-  elif request.user.is_superuser:
+  elif is_admin(request.user):
     form_class = SuperUserChangeForm
     form_class = SuperUserChangeForm
   else:
   else:
     form_class = UserChangeForm
     form_class = UserChangeForm
 
 
   if request.method == 'POST':
   if request.method == 'POST':
     form = form_class(request.POST, instance=instance)
     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")
       form.fields.pop("password_old")
     if form.is_valid(): # All validation rules pass
     if form.is_valid(): # All validation rules pass
       if instance is None:
       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:
             if not form.instance.is_superuser or not form.instance.is_active:
               _check_remove_last_super(orig)
               _check_remove_last_super(orig)
           else:
           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)
               raise PopupException(_("You cannot make yourself a superuser."), error_code=401)
 
 
           # All ok
           # All ok
@@ -317,7 +318,7 @@ def edit_user(request, username=None):
 
 
           # Unlock account if selected
           # Unlock account if selected
           if form.cleaned_data.get('unlock_account'):
           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)
               raise PopupException(_('You must be a superuser to reset users.'), error_code=401)
 
 
             try:
             try:
@@ -361,11 +362,11 @@ def edit_user(request, username=None):
         userprofile.first_login = False
         userprofile.first_login = False
         userprofile.save()
         userprofile.save()
 
 
-        if request.user.is_superuser:
+        if is_admin(request.user):
           return redirect(reverse('about:index'))
           return redirect(reverse('about:index'))
         else:
         else:
           return redirect(reverse('desktop_views_home'))
           return redirect(reverse('desktop_views_home'))
-      elif request.user.is_superuser:
+      elif is_admin(request.user):
         if is_embeddable:
         if is_embeddable:
           return JsonResponse({'url': '/hue' + reverse(list_users)})
           return JsonResponse({'url': '/hue' + reverse(list_users)})
         else:
         else:
@@ -385,7 +386,7 @@ def edit_user(request, username=None):
     }
     }
     form = form_class(instance=instance, initial=initial)
     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")
       form.fields.pop("password_old")
 
 
   if require_change_password(userprofile):
   if require_change_password(userprofile):
@@ -416,7 +417,7 @@ def edit_group(request, name=None):
 
 
   Only superusers may create a group
   Only superusers may create a group
   """
   """
-  if not request.user.is_superuser:
+  if not is_admin(request.user):
     request.audit = {'allowed': False}
     request.audit = {'allowed': False}
     if name is not None:
     if name is not None:
       request.audit['operation'] = 'EDIT_GROUP'
       request.audit['operation'] = 'EDIT_GROUP'
@@ -487,7 +488,7 @@ def edit_permission(request, app=None, priv=None):
 
 
   Only superusers may modify permissions
   Only superusers may modify permissions
   """
   """
-  if not request.user.is_superuser:
+  if not is_admin(request.user):
     request.audit = {
     request.audit = {
       'operation': 'EDIT_PERMISSION',
       'operation': 'EDIT_PERMISSION',
       'operationText': _get_failed_operation_text(request.user.username, '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 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 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 = {
     request.audit = {
       'operation': 'ADD_LDAP_USERS',
       'operation': 'ADD_LDAP_USERS',
       'operationText': _get_failed_operation_text(request.user.username, '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
   group with the LDAP server. If --import-members is specified, it will import
   all unimported users.
   all unimported users.
   """
   """
-  if not request.user.is_superuser:
+  if not is_admin(request.user):
     request.audit = {
     request.audit = {
       'operation': 'ADD_LDAP_GROUPS',
       'operation': 'ADD_LDAP_GROUPS',
       'operationText': _get_failed_operation_text(request.user.username, '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
   user information and group memberships will be updated based on the LDAP
   server's current state.
   server's current state.
   """
   """
-  if not request.user.is_superuser:
+  if not is_admin(request.user):
     request.audit = {
     request.audit = {
       'operation': 'SYNC_LDAP_USERS_GROUPS',
       'operation': 'SYNC_LDAP_USERS_GROUPS',
       'operationText': _get_failed_operation_text(request.user.username, 'SYNC_LDAP_USERS_GROUPS'),
       'operationText': _get_failed_operation_text(request.user.username, 'SYNC_LDAP_USERS_GROUPS'),
@@ -873,6 +874,7 @@ def sync_unix_users_and_groups(min_uid, max_uid, min_gid, max_gid, check_shell):
 
 
 def _check_remove_last_super(user_obj):
 def _check_remove_last_super(user_obj):
   """Raise an error if we're removing the last superuser"""
   """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:
   if not user_obj.is_superuser:
     return
     return
 
 

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

@@ -17,6 +17,7 @@
 <%!
 <%!
   from desktop.views import commonheader, commonfooter
   from desktop.views import commonheader, commonfooter
   from django.utils.translation import ugettext as _
   from django.utils.translation import ugettext as _
+  from desktop.auth.backend import is_admin
 %>
 %>
 
 
 <%namespace name="shared" file="shared_components.mako" />
 <%namespace name="shared" file="shared_components.mako" />
@@ -50,7 +51,7 @@ ${ shared.header(_breadcrumbs, clusters, False) }
         % if len(children) == 0:
         % if len(children) == 0:
           <li class="white">${ _('No children available') }</li>
           <li class="white">${ _('No children available') }</li>
         % endif
         % endif
-        % if user.is_superuser:
+        % if is_admin(user):
         <li class="white">
         <li class="white">
           <button class="btn" onclick="location.href='${url('zookeeper:create', id=cluster['id'], path=path)}'">
           <button class="btn" onclick="location.href='${url('zookeeper:create', id=cluster['id'], path=path)}'">
             <i class="fa fa-plus-circle"></i> ${ _('Add') }
             <i class="fa fa-plus-circle"></i> ${ _('Add') }
@@ -77,13 +78,13 @@ ${ shared.header(_breadcrumbs, clusters, False) }
       %if znode.get('dataLength', 0) != 0:
       %if znode.get('dataLength', 0) != 0:
       <div class="tab-pane active" id="text">
       <div class="tab-pane active" id="text">
         <textarea id="textareaText" rows="25" readonly="readonly"></textarea>
         <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>
         <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
         % endif
       </div>      
       </div>      
       <div class="tab-pane" id="base64">
       <div class="tab-pane" id="base64">
         <textarea id="textarea64" rows="25" readonly="readonly">${znode.get('data64', '')}</textarea>
         <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>
         <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
         % endif
       </div>
       </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.rest import ZooKeeper
 from zookeeper.utils import get_cluster_or_404
 from zookeeper.utils import get_cluster_or_404
 
 
+from desktop.auth.backend import is_admin
+
 
 
 def _get_global_overview():
 def _get_global_overview():
   clusters = CLUSTERS.get()
   clusters = CLUSTERS.get()
@@ -120,7 +122,7 @@ def tree(request, id, path):
 
 
 
 
 def delete(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'))
     raise PopupException(_('You are not a superuser'))
   cluster = get_cluster_or_404(id)
   cluster = get_cluster_or_404(id)
 
 
@@ -139,7 +141,7 @@ def delete(request, id, path):
 
 
 
 
 def create(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'))
     raise PopupException(_('You are not a superuser'))
   cluster = get_cluster_or_404(id)
   cluster = get_cluster_or_404(id)
 
 
@@ -164,7 +166,7 @@ def edit_as_base64(request, id, path):
   node = zk.get(path)
   node = zk.get(path)
 
 
   if request.method == 'POST':
   if request.method == 'POST':
-    if not request.user.is_superuser:
+    if not is_admin(request.user):
       raise PopupException(_('You are not a superuser'))
       raise PopupException(_('You are not a superuser'))
     form = EditZNodeForm(request.POST)
     form = EditZNodeForm(request.POST)
     if form.is_valid():
     if form.is_valid():
@@ -187,7 +189,7 @@ def edit_as_text(request, id, path):
   node = zk.get(path)
   node = zk.get(path)
 
 
   if request.method == 'POST':
   if request.method == 'POST':
-    if not request.user.is_superuser:
+    if not is_admin(request.user):
       raise PopupException(_('You are not a superuser'))
       raise PopupException(_('You are not a superuser'))
     form = EditZNodeForm(request.POST)
     form = EditZNodeForm(request.POST)
     if form.is_valid():
     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 mozilla_django_oidc.utils import absolutify, import_from_settings
 
 
 from useradmin import ldap_access
 from useradmin import ldap_access
-from useradmin.forms import validate_username
 from useradmin.models import get_profile, get_default_user_group, UserProfile
 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__)
 LOG = logging.getLogger(__name__)
@@ -100,6 +98,19 @@ def rewrite_user(user):
       setattr(user, attr, getattr(augment, attr))
       setattr(user, attr, getattr(augment, attr))
   return user
   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):
 class DefaultUserAugmentor(object):
   def __init__(self, parent):
   def __init__(self, parent):
     self._parent = parent
     self._parent = parent
@@ -359,6 +370,8 @@ class LdapBackend(object):
         username = force_username_case(username)
         username = force_username_case(username)
 
 
         try:
         try:
+          #Avoid circular import from is_admin
+          from useradmin.forms import validate_username
           validate_username(username)
           validate_username(username)
 
 
           if desktop.conf.LDAP.IGNORE_USERNAME_CASE.get():
           if desktop.conf.LDAP.IGNORE_USERNAME_CASE.get():
@@ -497,6 +510,8 @@ class LdapBackend(object):
     return user
     return user
 
 
   def check_ldap_access_groups(self, server, username):
   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
     allowed_group = False
 
 
     if desktop.conf.LDAP.LOGIN_GROUPS.get() and desktop.conf.LDAP.LOGIN_GROUPS.get() != ['']:
     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):
   def import_groups(self, server, user):
     connection = ldap_access.get_connection_from_server(server)
     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)
     import_ldap_users(connection, user.username, sync_groups=True, import_by_dn=False, server=server)
 
 
   @classmethod
   @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 desktop import conf
 from useradmin.hue_password_policy import hue_get_password_validators
 from useradmin.hue_password_policy import hue_get_password_validators
 
 
+from desktop.auth.backend import is_admin
 
 
 LOG = logging.getLogger(__name__)
 LOG = logging.getLogger(__name__)
 
 
@@ -78,7 +79,7 @@ class AuthenticationForm(AuthAuthenticationForm):
         expires_delta = datetime.timedelta(seconds=conf.AUTH.EXPIRES_AFTER.get())
         expires_delta = datetime.timedelta(seconds=conf.AUTH.EXPIRES_AFTER.get())
         if user.is_active and user.last_login + expires_delta < datetime.datetime.now():
         if user.is_active and user.last_login + expires_delta < datetime.datetime.now():
           INACTIVE_EXPIRATION_DELTA = datetime.timedelta(days=365)
           INACTIVE_EXPIRATION_DELTA = datetime.timedelta(days=365)
-          if user.is_superuser:
+          if is_admin(user):
             if conf.AUTH.EXPIRE_SUPERUSERS.get():
             if conf.AUTH.EXPIRE_SUPERUSERS.get():
               user.is_active = False
               user.is_active = False
               user.last_login = datetime.datetime.now() + INACTIVE_EXPIRATION_DELTA
               user.last_login = datetime.datetime.now() + INACTIVE_EXPIRATION_DELTA

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

@@ -28,6 +28,8 @@ try:
 except ImportError:
 except ImportError:
   from django.utils.functional import wraps
   from django.utils.functional import wraps
 
 
+from desktop.auth.backend import is_admin
+
 
 
 LOG = logging.getLogger(__name__)
 LOG = logging.getLogger(__name__)
 
 
@@ -51,7 +53,7 @@ def hue_permission_required(action, app):
 
 
 def check_superuser_permission(view_func):
 def check_superuser_permission(view_func):
   def decorate(request, *args, **kwargs):
   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)
       raise PopupException(_('You must be a superuser to perform this operation.'), error_code=401)
     return view_func(request, *args, **kwargs)
     return view_func(request, *args, **kwargs)
   return wraps(view_func)(decorate)
   return wraps(view_func)(decorate)
@@ -76,4 +78,4 @@ def check_document_access_permission():
 
 
       return view_func(request, *args, **kwargs)
       return view_func(request, *args, **kwargs)
     return wraps(view_func)(decorate)
     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 urlparse import urlparse
 from django.contrib.auth.models import User
 from django.contrib.auth.models import User
 
 
+from desktop.auth.backend import is_admin
 
 
 LOG = logging.getLogger(__name__)
 LOG = logging.getLogger(__name__)
 
 
@@ -58,7 +59,7 @@ class ProxyFS(object):
       if not filebrowser_action:
       if not filebrowser_action:
         return True
         return True
       user = rewrite_user(User.objects.get(username=self.user))
       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:
     except User.DoesNotExist:
       LOG.exception('proxyfs.has_access()')
       LOG.exception('proxyfs.has_access()')
       return False
       return False

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

@@ -56,7 +56,7 @@ from desktop import appmanager
 from desktop import metrics
 from desktop import metrics
 from hadoop import cluster
 from hadoop import cluster
 
 
-
+from desktop.auth.backend import is_admin
 
 
 LOG = logging.getLogger(__name__)
 LOG = logging.getLogger(__name__)
 
 
@@ -319,7 +319,7 @@ class LoginAndPermissionMiddleware(object):
 
 
       if app_accessed and \
       if app_accessed and \
           app_accessed not in ("desktop", "home", "home2", "about", "hue", "editor", "notebook", "indexer", "404", "500", "403") 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 \
                request.user.has_hue_permission(action=access_view, app=app_accessed)) and \
           not (app_accessed == '__debug__' and desktop.conf.DJANGO_DEBUG_MODE):
           not (app_accessed == '__debug__' and desktop.conf.DJANGO_DEBUG_MODE):
         access_log(request, 'permission denied', level=access_log_level)
         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.lib.paths import get_run_root
 from desktop.redaction import global_redaction_engine
 from desktop.redaction import global_redaction_engine
 from desktop.settings import DOCUMENT2_SEARCH_MAX_LENGTH
 from desktop.settings import DOCUMENT2_SEARCH_MAX_LENGTH
+from desktop.auth.backend import is_admin
 
 
 LOG = logging.getLogger(__name__)
 LOG = logging.getLogger(__name__)
 
 
@@ -609,6 +610,7 @@ class DocumentManager(models.Manager):
 
 
 
 
 class Document(models.Model):
 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')
   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)
   name = models.CharField(default='', max_length=255)
   description = models.TextField(default='')
   description = models.TextField(default='')
@@ -671,11 +673,11 @@ class Document(models.Model):
     DocumentPermission.objects.share_to_default(self, name=name)
     DocumentPermission.objects.share_to_default(self, name=name)
 
 
   def can_read(self, user):
   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):
   def can_write(self, user):
     perm = self.list_permissions('write')
     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):
   def can_read_or_exception(self, user, exception_class=PopupException):
     if self.can_read(user):
     if self.can_read(user):
@@ -1310,7 +1312,7 @@ class Document2(models.Model):
   def can_read(self, user):
   def can_read(self, user):
     perm = self.get_permission('read')
     perm = self.get_permission('read')
     has_read_permissions = perm.user_has_access(user) if perm else False
     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):
   def can_read_or_exception(self, user):
     if self.can_read(user):
     if self.can_read(user):
@@ -1321,7 +1323,7 @@ class Document2(models.Model):
   def can_write(self, user):
   def can_write(self, user):
     perm = self.get_permission('write')
     perm = self.get_permission('write')
     has_write_permissions = perm.user_has_access(user) if perm else False
     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):
   def can_write_or_exception(self, user):
     if self.can_write(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 {
       return {
           'name': 'oozie',
           'name': 'oozie',
           'displayName': _('Scheduler'),
           'displayName': _('Scheduler'),

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

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

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

@@ -16,6 +16,7 @@
 
 
 <%!
 <%!
 from django.utils.translation import ugettext as _
 from django.utils.translation import ugettext as _
+from desktop.auth.backend import is_admin
 
 
 def is_selected(section, matcher):
 def is_selected(section, matcher):
   if section == matcher:
   if section == matcher:
@@ -36,7 +37,7 @@ def is_selected(section, matcher):
                   ${ _('About Hue') }
                   ${ _('About Hue') }
                 </a>
                 </a>
                </li>
                </li>
-              % if user.is_superuser:
+              % if is_admin(user):
                 <li class="${is_selected(section, 'quick_start')}">
                 <li class="${is_selected(section, 'quick_start')}">
                   <a href="${ url('about:admin_wizard') }">${_('Quick start')}</a>
                   <a href="${ url('about:admin_wizard') }">${_('Quick start')}</a>
                 </li>
                 </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 metadata.conf import has_optimizer, OPTIMIZER
 
 
+from desktop.auth.backend import is_admin
+
 home_url = url('desktop_views_home')
 home_url = url('desktop_views_home')
 if USE_NEW_EDITOR.get():
 if USE_NEW_EDITOR.get():
   home_url = url('desktop_views_home2')
   home_url = url('desktop_views_home2')
@@ -332,7 +334,7 @@ ${ hueIcons.symbols() }
       % endif
       % endif
     % 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():
     % if view_profile or conf.IS_HUE_4.get():
     <li class="dropdown">
     <li class="dropdown">
@@ -351,7 +353,7 @@ ${ hueIcons.symbols() }
           % endif
           % endif
         </a>
         </a>
       </li>
       </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>
           <li><a href="${ url('useradmin.views.list_users') }"><i class="fa fa-fw fa-group"></i> ${_('Manage Users')}</a></li>
         % endif
         % endif
       % 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>
                <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>
              </ul>
            </li>
            </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 %>
            <% from oozie.conf import ENABLE_V2 %>
            % if not ENABLE_V2.get():
            % if not ENABLE_V2.get():
            <li class="dropdown-submenu">
            <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.views import commonheader, commonfooter, _ko
   from desktop import conf
   from desktop import conf
+  from desktop.auth.backend import is_admin
 %>
 %>
 
 
 <%namespace name="docBrowser" file="/document_browser.mako" />
 <%namespace name="docBrowser" file="/document_browser.mako" />
@@ -71,7 +72,7 @@
     $(document).ready(function () {
     $(document).ready(function () {
       var options = {
       var options = {
         user: '${ user.username }',
         user: '${ user.username }',
-        superuser: '${ user.is_superuser }' === 'True',
+        superuser: '${ is_admin(user) }' === 'True',
         i18n: {
         i18n: {
           errorFetchingTableDetails: '${_('An error occurred fetching the table details. Please try again.')}',
           errorFetchingTableDetails: '${_('An error occurred fetching the table details. Please try again.')}',
           errorFetchingTableFields: '${_('An error occurred fetching the table fields. 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 desktop.lib.i18n import smart_unicode
 from django.utils.translation import ugettext as _
 from django.utils.translation import ugettext as _
 from desktop import conf
 from desktop import conf
+from desktop.auth.backend import is_admin
 %>
 %>
 
 
 %if not is_embeddable:
 %if not is_embeddable:
@@ -33,7 +34,7 @@ ${ commonheader(_('Error'), app_name, user, request, "40px") | n,unicode }
             <p>
             <p>
               <pre>${ smart_unicode(error) }</pre>
               <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">
                 <textarea style="width: 100%;" rows=80 readonly="readonly">
                 ${ smart_unicode(traceback) }
                 ${ smart_unicode(traceback) }
                 </textarea>
                 </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 dashboard.conf import IS_ENABLED as IS_DASHBOARD_ENABLED
   from indexer.conf import ENABLE_NEW_INDEXER
   from indexer.conf import ENABLE_NEW_INDEXER
   from metadata.conf import has_optimizer, OPTIMIZER
   from metadata.conf import has_optimizer, OPTIMIZER
+
+  from desktop.auth.backend import is_admin
 %>
 %>
 
 
 <%namespace name="koComponents" file="/ko_components.mako" />
 <%namespace name="koComponents" file="/ko_components.mako" />
@@ -247,7 +249,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)
           %>
           %>
           <button class="btn btn-flat" data-toggle="dropdown" data-bind="click: function(){ huePubSub.publish('hide.jobs.panel'); huePubSub.publish('hide.history.panel'); }">
           <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>
             <i class="fa fa-user"></i> ${ user.username } <span class="caret"></span>
@@ -256,7 +258,7 @@ ${ hueIcons.symbols() }
             % if view_profile:
             % 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>
             <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
             % 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>
             <li data-bind="hueLink: '/useradmin/users/'"><a href="javascript: void(0);"><i class="fa fa-fw fa-group"></i> ${_('Manage Users')}</a></li>
             % endif
             % endif
             % if not conf.DISABLE_HUE_3.get():
             % if not conf.DISABLE_HUE_3.get():
@@ -264,7 +266,7 @@ ${ hueIcons.symbols() }
             % endif
             % endif
             <li><a href="http://gethue.com" target="_blank"><span class="dropdown-no-icon">${_('Help')}</span></a></li>
             <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>
             <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>
             <li><a href="/about/"><span class="dropdown-no-icon">${_('Hue Administration')}</span></a></li>
             % endif
             % endif
             <li class="divider"></li>
             <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') {
                 if (app.name === 'editor') {
                   interpreters.push({
                   interpreters.push({
                     displayName: '${ _('Add more...') }',
                     displayName: '${ _('Add more...') }',
@@ -1754,7 +1756,7 @@ ${ smart_unicode(login_modal(request).content) | n,unicode }
       attachTo: '.navbar-default bottom'
       attachTo: '.navbar-default bottom'
     });
     });
 
 
-    %if user.is_superuser:
+    %if is_admin(user):
       tour.addStep('admin', {
       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.') }',
         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'
         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.views import commonheader, commonfooter
 from desktop.lib.i18n import smart_unicode
 from desktop.lib.i18n import smart_unicode
 from django.utils.translation import ugettext as _
 from django.utils.translation import ugettext as _
+from desktop.auth.backend import is_admin
 %>
 %>
 
 
 %if not is_embeddable:
 %if not is_embeddable:
@@ -41,7 +42,7 @@ ${ commonheader(title, "", user, request, "40px") | n,unicode }
             % if traceback:
             % if traceback:
               <a href="javascript:toggleDisplay('#traceback');"><i class="fa fa-share"></i> ${_('More Info')}</a>
               <a href="javascript:toggleDisplay('#traceback');"><i class="fa fa-share"></i> ${_('More Info')}</a>
               &nbsp;
               &nbsp;
-              % if user.is_superuser:
+              % if is_admin(user):
               <a href="/logs" target="_new">${_('View Logs')}</a>
               <a href="/logs" target="_new">${_('View Logs')}</a>
               % endif
               % endif
               <br />
               <br />
@@ -67,7 +68,7 @@ ${ commonheader(title, "", user, request, "40px") | n,unicode }
                 </table>
                 </table>
               </div>
               </div>
             % else:
             % else:
-              % if user.is_superuser:
+              % if is_admin(user):
               <a href="/logs" target="_new">${_('View Logs')}</a>
               <a href="/logs" target="_new">${_('View Logs')}</a>
               % endif
               % endif
               <br />
               <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.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.models import Settings, hue_version, _get_apps, UserPreferences
 
 
-
+from desktop.auth.backend import is_admin
 
 
 LOG = logging.getLogger(__name__)
 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,
   If it is attached to the root logger, this view will display that history,
   otherwise it will report that it can't be found.
   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."))
     return HttpResponse(_("You must be a superuser."))
 
 
   hostname = socket.gethostname()
   hostname = socket.gethostname()
@@ -199,7 +199,7 @@ def download_log_view(request):
   """
   """
   Zip up the log buffer and then return as a file attachment.
   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."))
     return HttpResponse(_("You must be a superuser."))
 
 
   l = logging.getLogger()
   l = logging.getLogger()
@@ -279,7 +279,7 @@ def dump_config(request):
   show_private = False
   show_private = False
   conf_dir = os.path.realpath(os.getenv("HUE_CONF_DIR", get_desktop_root("conf")))
   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."))
     return HttpResponse(_("You must be a superuser."))
 
 
   if request.GET.get("private"):
   if request.GET.get("private"):
@@ -302,7 +302,7 @@ def threads(request):
   out = StringIO.StringIO()
   out = StringIO.StringIO()
   dump_traceback(file=out)
   dump_traceback(file=out)
 
 
-  if not request.user.is_superuser:
+  if not is_admin(request.user):
     return HttpResponse(_("You must be a superuser."))
     return HttpResponse(_("You must be a superuser."))
 
 
   if request.is_ajax():
   if request.is_ajax():
@@ -314,7 +314,7 @@ def threads(request):
 @access_log_level(logging.WARN)
 @access_log_level(logging.WARN)
 def memory(request):
 def memory(request):
   """Dumps out server threads. Useful for debugging."""
   """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."))
     return HttpResponse(_("You must be a superuser."))
 
 
   if not hasattr(settings, 'MEMORY_PROFILER'):
   if not hasattr(settings, 'MEMORY_PROFILER'):
@@ -388,7 +388,7 @@ def index(request):
     except UserPreferences.DoesNotExist:
     except UserPreferences.DoesNotExist:
       pass
       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'))
     return redirect(reverse('about:index'))
   else:
   else:
     if is_hue_4:
     if is_hue_4:
@@ -710,7 +710,7 @@ def collect_validation_messages(conf, error_list):
 
 
 def check_config(request):
 def check_config(request):
   """Check config and view for the list of errors"""
   """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."))
     return HttpResponse(_("You must be a superuser."))
 
 
   context = {
   context = {
@@ -726,7 +726,7 @@ def check_config(request):
 
 
 def check_config_ajax(request):
 def check_config_ajax(request):
   """Alert administrators about configuration problems."""
   """Alert administrators about configuration problems."""
-  if not request.user.is_superuser:
+  if not is_admin(request.user):
     return HttpResponse('')
     return HttpResponse('')
 
 
   error_list = _get_config_errors(request)
   error_list = _get_config_errors(request)
@@ -745,7 +745,7 @@ def get_debug_level(request):
 
 
 @require_POST
 @require_POST
 def set_all_debug(request):
 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.')})
     return JsonResponse({'status': 1, 'message': _('You must be a superuser.')})
 
 
   _set_all_debug()
   _set_all_debug()
@@ -755,7 +755,7 @@ def set_all_debug(request):
 
 
 @require_POST
 @require_POST
 def reset_all_debug(request):
 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.')})
     return JsonResponse({'status': 1, 'message': _('You must be a superuser.')})
 
 
   _reset_all_debug()
   _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 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
 from hadoop.core_site import get_s3a_access_key, get_s3a_secret_key
 
 
-
 LOG = logging.getLogger(__name__)
 LOG = logging.getLogger(__name__)
 
 
 
 
@@ -209,7 +208,8 @@ def has_iam_metadata():
 
 
 
 
 def has_s3_access(user):
 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):
 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 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
 from hadoop.core_site import get_adls_client_id, get_adls_authentication_code, get_adls_refresh_url
 
 
-
 LOG = logging.getLogger(__name__)
 LOG = logging.getLogger(__name__)
 
 
 REFRESH_URL = 'https://login.microsoftonline.com/<tenant_id>/oauth2/token'
 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)
   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):
 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):
 def config_validator(user):
   res = []
   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 dashboard.models import Collection2
 
 
+from desktop.auth.backend import is_admin
 
 
 LOG = logging.getLogger(__name__)
 LOG = logging.getLogger(__name__)
 
 
@@ -50,13 +51,13 @@ class DashboardController(object):
 
 
   def get_owner_search_collections(self):
   def get_owner_search_collections(self):
     if USE_NEW_EDITOR.get():
     if USE_NEW_EDITOR.get():
-      if self.user.is_superuser:
+      if is_admin(self.user):
         docs = Document2.objects.filter(type='search-dashboard')
         docs = Document2.objects.filter(type='search-dashboard')
       else:
       else:
         docs = Document2.objects.filter(type='search-dashboard', owner=self.user)
         docs = Document2.objects.filter(type='search-dashboard', owner=self.user)
       return docs
       return docs
     else:
     else:
-      if self.user.is_superuser:
+      if is_admin(self.user):
         docs = Document.objects.filter(extra='search-dashboard')
         docs = Document.objects.filter(extra='search-dashboard')
       else:
       else:
         docs = Document.objects.filter(extra='search-dashboard', owner=self.user)
         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 django.utils.translation import ugettext as _
 from desktop.views import commonheader, commonfooter
 from desktop.views import commonheader, commonfooter
 from indexer.conf import ENABLE_NEW_INDEXER
 from indexer.conf import ENABLE_NEW_INDEXER
+from desktop.auth.backend import is_admin
 %>
 %>
 
 
 <%namespace name="macros" file="macros.mako" />
 <%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>
       <i class="fa fa-search waiting"></i>
       <h1>${ _('It seems there is nothing to search on ...') }</h1>
       <h1>${ _('It seems there is nothing to search on ...') }</h1>
-      % if user.is_superuser:
+      % if is_admin(user):
       <h1>
       <h1>
         ${ _('What about creating a') }
         ${ _('What about creating a') }
         % if ENABLE_NEW_INDEXER.get():
         % 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.utils.translation import ugettext as _
 from django.urls import reverse
 from django.urls import reverse
 
 
+from desktop.auth.backend import is_admin
+
 LOG = logging.getLogger(__name__)
 LOG = logging.getLogger(__name__)
 
 
 
 
@@ -384,7 +386,7 @@ class Job(object):
 
 
   def check_request_permission(self, request):
   def check_request_permission(self, request):
     """Raise PopupException if request user doesn't have permission to modify workflow"""
     """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.'))
       access_warn(request, _('Insufficient permission.'))
       raise PopupException(_("Permission denied. User %(username)s cannot modify user %(user)s's job.") %
       raise PopupException(_("Permission denied. User %(username)s cannot modify user %(user)s's job.") %
                            dict(username=request.user.username, user=self.user))
                            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
 from metadata.settings import DJANGO_APPS
 
 
-
 OPTIMIZER_AUTH_PASSWORD = None
 OPTIMIZER_AUTH_PASSWORD = None
 NAVIGATOR_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]
   return NAVIGATOR.API_URL.get() and NAVIGATOR.API_URL.get().strip('/')[:-3]
 
 
 def has_navigator(user):
 def has_navigator(user):
+  from desktop.auth.backend import is_admin
   return bool(get_navigator_url() and get_navigator_auth_password()) \
   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():
 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.optimizer_client import OptimizerApi, NavOptException, _get_table_name, _clean_query
 from metadata.conf import OPTIMIZER
 from metadata.conf import OPTIMIZER
 
 
+from desktop.auth.backend import is_admin
 
 
 LOG = logging.getLogger(__name__)
 LOG = logging.getLogger(__name__)
 
 
@@ -325,7 +326,7 @@ def _convert_queries(queries_data):
 def upload_history(request):
 def upload_history(request):
   response = {'status': -1}
   response = {'status': -1}
 
 
-  if request.user.is_superuser:
+  if is_admin(request.user):
     api = OptimizerApi(request.user)
     api = OptimizerApi(request.user)
     histories = []
     histories = []
     upload_stats = {}
     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 metadata.conf import OPTIMIZER, get_optimizer_url
 
 
+from desktop.auth.backend import is_admin
 
 
 LOG = logging.getLogger(__name__)
 LOG = logging.getLogger(__name__)
 
 
@@ -229,7 +230,7 @@ class OptimizerApi(object):
     }
     }
 
 
   def similar_queries(self, source_platform, query, page_size=100, startingToken=None):
   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})
       return self._call('getSimilarQueries', {'tenant' : self._tenant_id, 'sourcePlatform': source_platform, 'query': query, 'pageSize': page_size, 'startingToken': startingToken})
     else:
     else:
       raise PopupException(_('Call not supported'))
       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 notebook.connectors.base import Api, QueryError, QueryExpired, OperationTimeout, OperationNotSupported, _get_snippet_name, Notebook
 
 
+from desktop.auth.backend import is_admin
 
 
 LOG = logging.getLogger(__name__)
 LOG = logging.getLogger(__name__)
 
 
@@ -220,7 +221,7 @@ class HS2Api(Api):
 
 
     try:
     try:
       filters = {'id': session_id, 'application': query_server['server_name']}
       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
         filters['owner'] = self.user
       session = Session.objects.get(**filters)
       session = Session.objects.get(**filters)
     except Session.DoesNotExist:
     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 desktop.conf import IS_EMBEDDED
 from metadata.conf import has_optimizer, OPTIMIZER
 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 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='')">
 <%def name="includes(is_embeddable=False, suffix='')">
@@ -1910,7 +1911,7 @@ ${ sqlSyntaxDropdown.sqlSyntaxDropdown() }
             <i class="fa fa-fw fa-random"></i> ${_('Check compatibility')}
             <i class="fa fa-fw fa-random"></i> ${_('Check compatibility')}
           </a>
           </a>
         </li>
         </li>
-        % if conf.DJANGO_DEBUG_MODE.get() and user.is_superuser:
+        % if conf.DJANGO_DEBUG_MODE.get() and is_admin(user):
         <li>
         <li>
           <a href="javascript:void(0)" data-bind="click: function() { huePubSub.publish('editor.upload.history'); }" title="${ _('Load recent queries in order to improve recommendations') }">
           <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')}
             <i class="fa fa-fw fa-cloud-upload"></i> ${_('Upload history')}