Эх сурвалжийг харах

HUE-1859 [core] Add generic middleware support

Abraham Elmahrek 12 жил өмнө
parent
commit
b5fa62a

+ 48 - 0
apps/useradmin/src/useradmin/middleware.py

@@ -0,0 +1,48 @@
+#!/usr/bin/env python
+# Licensed to Cloudera, Inc. under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  Cloudera, Inc. licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import logging
+
+from django.contrib.auth.models import User
+
+from models import UserProfile
+from views import import_ldap_users
+
+
+LOG = logging.getLogger(__name__)
+
+
+class LdapSynchronizationMiddleware(object):
+  """
+  Synchronize against LDAP authority.
+  """
+  USER_CACHE_NAME = 'ldap_use_group_sync_cache'
+
+  def process_request(self, request):
+    user = request.user
+
+    if not user or not user.is_authenticated():
+      return
+
+    if not User.objects.filter(username=user.username, userprofile__creation_method=str(UserProfile.CreationMethod.EXTERNAL)).exists():
+      LOG.warn("User %s is not an Ldap user" % user.username)
+      return
+
+    # Cache should be cleared when user logs out.
+    if self.USER_CACHE_NAME not in request.session:
+      request.session[self.USER_CACHE_NAME] = import_ldap_users(user.username, sync_groups=True, import_by_dn=False)
+      request.session.modified = True

+ 2 - 5
apps/useradmin/src/useradmin/tests.py

@@ -460,8 +460,7 @@ def test_user_admin():
 
 
 def test_useradmin_ldap_user_group_membership_sync():
-  reset = [desktop.conf.AUTH.USER_GROUP_MEMBERSHIP_SYNCHRONIZATION_BACKEND.set_for_testing('desktop.auth.backend.LdapSynchronizationBackend')]
-  settings.MIDDLEWARE_CLASSES.append('desktop.middleware.UserGroupSynchronizationMiddleware')
+  settings.MIDDLEWARE_CLASSES.append('useradmin.middleware.LdapSynchronizationMiddleware')
 
   reset_all_users()
   reset_all_groups()
@@ -504,9 +503,7 @@ def test_useradmin_ldap_user_group_membership_sync():
     # Should have 2 groups now. 1 from LDAP and 1 from 'grant_access' call.
     assert_equal(3, user.groups.all().count(), user.groups.all())
   finally:
-    for finish in reset:
-      finish()
-    settings.MIDDLEWARE_CLASSES.remove('desktop.middleware.UserGroupSynchronizationMiddleware')
+    settings.MIDDLEWARE_CLASSES.remove('useradmin.middleware.LdapSynchronizationMiddleware')
 
 
 def test_useradmin_ldap_group_integration():

+ 4 - 3
desktop/conf.dist/hue.ini

@@ -63,6 +63,10 @@
   # Use Google Analytics to see how many times an application or specific section of an application is used, nothing more.
   ## collect_usage=true
 
+  # Comma-separated list of Django middleware classes to use.
+  # See https://docs.djangoproject.com/en/1.4/ref/middleware/ for more details on middlewares in Django.
+  ## middleware=desktop.auth.backend.LdapSynchronizationBackend
+
   ## Comma-separated list of regular expressions, which match the redirect URL.
   ## For example, to restrict to your local domain and FQDN, the following value can be used:
   ##   ^\/.*$,^http:\/\/www.mydomain.com\/.*$
@@ -99,9 +103,6 @@
     # - libsaml.backend.SAML2Backend
     ## backend=desktop.auth.backend.AllowFirstUserDjangoBackend
 
-    # Backend to synchronize user-group membership with
-    ## user_group_membership_synchronization_backend=desktop.auth.backend.LdapSynchronizationBackend
-
     ## pam_service=login
 
     # When using the desktop.auth.backend.RemoteUserDjangoBackend, this sets

+ 4 - 3
desktop/conf/pseudo-distributed.ini.tmpl

@@ -72,6 +72,10 @@
   # Use Google Analytics to see how many times an application or specific section of an application is used, nothing more.
   ## collect_usage=true
 
+  # Comma-separated list of Django middleware classes to use.
+  # See https://docs.djangoproject.com/en/1.4/ref/middleware/ for more details on middlewares in Django.
+  ## middleware=desktop.auth.backend.LdapSynchronizationBackend
+
   ## Comma-separated list of regular expressions, which match the redirect URL.
   ## For example, to restrict to your local domain and FQDN, the following value can be used:
   ##   ^\/.*$,^http:\/\/www.mydomain.com\/.*$
@@ -108,9 +112,6 @@
     # - libsaml.backend.SAML2Backend
     ## backend=desktop.auth.backend.AllowFirstUserDjangoBackend
 
-    # Backend to synchronize user-group membership with
-    ## user_group_membership_synchronization_backend=desktop.auth.backend.LdapSynchronizationBackend
-
     ## pam_service=login
 
     # When using the desktop.auth.backend.RemoteUserDjangoBackend, this sets

+ 0 - 32
desktop/core/src/desktop/auth/backend.py

@@ -143,16 +143,6 @@ class DesktopBackendBase(object):
     raise NotImplemented("Abstract class - must implement check_auth")
 
 
-class DesktopSynchronizationBackendBase(object):
-  """
-  Abstract base class for providing user-group membership sync'ing.
-
-  Extend this class and implement sync.
-  """
-  def sync(self, user):
-    raise NotImplemented("Abstract class - must implement sync")
-
-
 class AllowFirstUserDjangoBackend(django.contrib.auth.backends.ModelBackend):
   """
   Allows the first user in, but otherwise delegates to Django's
@@ -388,28 +378,6 @@ class LdapBackend(object):
     return True
 
 
-class LdapSynchronizationBackend(DesktopSynchronizationBackendBase):
-  """
-  Synchronize against LDAP authority.
-  """
-  USER_CACHE_NAME = 'ldap_use_group_sync_cache'
-
-  def sync(self, request):
-    user = request.user
-
-    if not user or not user.is_authenticated():
-      return
-
-    if not User.objects.filter(username=user.username, userprofile__creation_method=str(UserProfile.CreationMethod.EXTERNAL)).exists():
-      LOG.warn("User %s is not an Ldap user" % user.username)
-      return
-
-    # Cache should be cleared when user logs out.
-    if self.USER_CACHE_NAME not in request.session:
-      request.session[self.USER_CACHE_NAME] = import_ldap_users(user.username, sync_groups=True, import_by_dn=False)
-      request.session.modified = True
-
-
 class SpnegoDjangoBackend(django.contrib.auth.backends.ModelBackend):
   """
   A note about configuration:

+ 8 - 6
desktop/core/src/desktop/conf.py

@@ -112,6 +112,14 @@ POLL_ENABLED = Config(
   private=True,
   default=True)
 
+MIDDLEWARE = Config(
+  key="middleware",
+  help=_("Comma-separated list of Django middleware classes to use. " +
+         "See https://docs.djangoproject.com/en/1.4/ref/middleware/ for " +
+         "more details on middlewares in Django."),
+  type=coerce_csv,
+  default=[])
+
 REDIRECT_WHITELIST = Config(
   key="redirect_whitelist",
   help=_("Comma-separated list of regular expressions, which match the redirect URL."
@@ -352,12 +360,6 @@ AUTH = ConfigSection(
                         "django.contrib.auth.backends.ModelBackend (fully Django backend), " +
                         "desktop.auth.backend.AllowAllBackend (allows everyone), " +
                         "desktop.auth.backend.AllowFirstUserDjangoBackend (relies on Django and user manager, after the first login). ")),
-    USER_GROUP_MEMBERSHIP_SYNCHRONIZATION_BACKEND = Config(
-      key="user_group_membership_synchronization_backend",
-      help=_("Backend to synchronize user-group membership with."),
-      type=str,
-      default='',
-    ),
     USER_AUGMENTOR=Config("user_augmentor",
                    default="desktop.auth.backend.DefaultUserAugmentor",
                    help=_("Class which defines extra accessor methods for User objects.")),

+ 1 - 26
desktop/core/src/desktop/middleware.py

@@ -27,10 +27,9 @@ from django.contrib.auth import REDIRECT_FIELD_NAME, BACKEND_SESSION_KEY, authen
 from django.contrib.auth.middleware import RemoteUserMiddleware
 from django.core import exceptions, urlresolvers
 import django.db
-from django.http import HttpResponseNotAllowed, HttpResponseForbidden
+from django.http import HttpResponseNotAllowed
 from django.core.urlresolvers import resolve
 from django.http import HttpResponseRedirect, HttpResponse
-from django.utils.importlib import import_module
 from django.utils.translation import ugettext as _
 from django.utils.http import urlquote
 from django.utils.encoding import iri_to_uri
@@ -59,30 +58,6 @@ DJANGO_VIEW_AUTH_WHITELIST = [
   django.views.generic.simple.redirect_to,
 ]
 
-class UserGroupSynchronizationMiddleware(object):
-  """
-  Middleware that synchronizes users and groups
-  """
-  def load_backend(self, path):
-    i = path.rfind('.')
-    module, attr = path[:i], path[i+1:]
-    try:
-      mod = import_module(module)
-    except ImportError, e:
-      raise ImproperlyConfigured('Error importing synchronization backend %s: "%s"' % (module, e))
-    try:
-        cls = getattr(mod, attr)
-    except AttributeError:
-      raise ImproperlyConfigured('Module "%s" does not define a "%s" synchronization backend' % (module, attr))
-    return cls()
-
-  def get_backend(self):
-    return self.load_backend(desktop.conf.AUTH.USER_GROUP_MEMBERSHIP_SYNCHRONIZATION_BACKEND.get())
-
-  def process_request(self, request):
-    backend = self.get_backend()
-    backend.sync(request)
-
 class AjaxMiddleware(object):
   """
   Middleware that augments request to set request.ajax

+ 4 - 4
desktop/core/src/desktop/settings.py

@@ -311,6 +311,10 @@ if SAML_AUTHENTICATION:
   LOGIN_URL = '/saml2/login/'
   SESSION_EXPIRE_AT_BROWSER_CLOSE = True
 
+# Middleware classes.
+for middleware in desktop.conf.MIDDLEWARE.get():
+  MIDDLEWARE_CLASSES.append(middleware)
+
 # URL Redirection white list.
 if desktop.conf.REDIRECT_WHITELIST.get():
   MIDDLEWARE_CLASSES.append('desktop.middleware.EnsureSafeRedirectURLMiddleware')
@@ -323,7 +327,3 @@ SKIP_SOUTH_TESTS = True
 # Set up environment variable so Kerberos libraries look at our private
 # ticket cache
 os.environ['KRB5CCNAME'] = desktop.conf.KERBEROS.CCACHE_PATH.get()
-
-#######
-if desktop.conf.AUTH.USER_GROUP_MEMBERSHIP_SYNCHRONIZATION_BACKEND.get():
-  MIDDLEWARE_CLASSES.append('desktop.middleware.UserGroupSynchronizationMiddleware')