Browse Source

HUE-7624 [core] Support multi-authentication with AllowFirstUserDjangoBackend and LdapBackend

Ying Chen 8 years ago
parent
commit
eb50610947

+ 18 - 3
desktop/core/src/desktop/auth/forms.py

@@ -18,7 +18,7 @@
 import datetime
 import datetime
 
 
 from django.conf import settings
 from django.conf import settings
-from django.contrib.auth import authenticate
+from django.contrib.auth import authenticate, get_backends
 from django.contrib.auth.models import User
 from django.contrib.auth.models import User
 from django.contrib.auth.forms import AuthenticationForm as AuthAuthenticationForm, UserCreationForm as AuthUserCreationForm
 from django.contrib.auth.forms import AuthenticationForm as AuthAuthenticationForm, UserCreationForm as AuthUserCreationForm
 from django.forms import CharField, TextInput, PasswordInput, ChoiceField, ValidationError
 from django.forms import CharField, TextInput, PasswordInput, ChoiceField, ValidationError
@@ -29,11 +29,26 @@ from desktop import conf
 from useradmin.password_policy import get_password_validators
 from useradmin.password_policy import get_password_validators
 
 
 
 
+def get_backend_names():
+  return get_backends and [backend.__class__.__name__ for backend in get_backends()]
+
+def is_active_directory():
+  return 'LdapBackend' in get_backend_names() and \
+                          (bool(conf.LDAP.NT_DOMAIN.get()) or bool(conf.LDAP.LDAP_SERVERS.get()) or conf.LDAP.LDAP_URL.get() is not None)
+
+def get_ldap_server_keys():
+  return [(ldap_server_record_key) for ldap_server_record_key in conf.LDAP.LDAP_SERVERS.get()]
+
 def get_server_choices():
 def get_server_choices():
   if conf.LDAP.LDAP_SERVERS.get():
   if conf.LDAP.LDAP_SERVERS.get():
-    return [(ldap_server_record_key, ldap_server_record_key) for ldap_server_record_key in conf.LDAP.LDAP_SERVERS.get()]
+    auth_choices = [(ldap_server_record_key, ldap_server_record_key) for ldap_server_record_key in conf.LDAP.LDAP_SERVERS.get()]
   else:
   else:
-    return [('LDAP', 'LDAP')]
+    auth_choices = [('LDAP', 'LDAP')]
+
+  if is_active_directory() and 'AllowFirstUserDjangoBackend' in get_backend_names():
+    auth_choices.append(('Local', _('Local')))
+
+  return auth_choices
 
 
 
 
 class AuthenticationForm(AuthAuthenticationForm):
 class AuthenticationForm(AuthAuthenticationForm):

+ 5 - 7
desktop/core/src/desktop/auth/views.py

@@ -80,19 +80,17 @@ def first_login_ever():
   return False
   return False
 
 
 
 
-def get_backend_names():
-  return get_backends and [backend.__class__.__name__ for backend in get_backends()]
-
-
 @login_notrequired
 @login_notrequired
 @watch_login
 @watch_login
 def dt_login(request, from_modal=False):
 def dt_login(request, from_modal=False):
   redirect_to = request.REQUEST.get('next', '/')
   redirect_to = request.REQUEST.get('next', '/')
   is_first_login_ever = first_login_ever()
   is_first_login_ever = first_login_ever()
-  backend_names = get_backend_names()
-  is_active_directory = 'LdapBackend' in backend_names and ( bool(LDAP.NT_DOMAIN.get()) or bool(LDAP.LDAP_SERVERS.get()) )
+  backend_names = auth_forms.get_backend_names()
+  is_active_directory = auth_forms.is_active_directory()
+  is_ldap_option_selected = 'server' not in request.POST or request.POST['server'] == 'LDAP' \
+                            or request.POST['server'] in auth_forms.get_ldap_server_keys()
 
 
-  if is_active_directory:
+  if is_active_directory and is_ldap_option_selected:
     UserCreationForm = auth_forms.LdapUserCreationForm
     UserCreationForm = auth_forms.LdapUserCreationForm
     AuthenticationForm = auth_forms.LdapAuthenticationForm
     AuthenticationForm = auth_forms.LdapAuthenticationForm
   else:
   else:

+ 66 - 0
desktop/core/src/desktop/auth/views_test.py

@@ -539,6 +539,72 @@ class TestMultipleBackendLogin(PseudoHdfsTestBase):
     assert_true(self.fs.exists("/user/%s" % self.test_username))
     assert_true(self.fs.exists("/user/%s" % self.test_username))
 
 
 
 
+class TestMultipleBackendLoginNoHadoop(object):
+  reset = []
+  test_username = "test_mlogin_no_hadoop"
+
+  @classmethod
+  def setup_class(cls):
+    # Simulate first login ever
+    User.objects.all().delete()
+
+    cls.ldap_backend = django_auth_ldap_backend.LDAPBackend
+    django_auth_ldap_backend.LDAPBackend = MockLdapBackend
+
+    # Override auth backend, settings are only loaded from conf at initialization so we can't use set_for_testing
+    cls.auth_backends = settings.AUTHENTICATION_BACKENDS
+    settings.AUTHENTICATION_BACKENDS = (['desktop.auth.backend.LdapBackend', 'desktop.auth.backend.AllowFirstUserDjangoBackend'])
+
+    # Need to recreate LdapBackend class with new monkey patched base class
+    reload(backend)
+
+  @classmethod
+  def teardown_class(cls):
+    django_auth_ldap_backend.LDAPBackend = cls.ldap_backend
+
+    settings.AUTHENTICATION_BACKENDS = cls.auth_backends
+
+    reload(backend)
+
+  def setUp(self):
+    self.c = Client()
+    self.reset.append( conf.AUTH.BACKEND.set_for_testing(['AllowFirstUserDjangoBackend', 'LdapBackend']) )
+    self.reset.append(conf.LDAP.LDAP_URL.set_for_testing('does not matter'))
+
+  def tearDown(self):
+    User.objects.all().delete()
+
+    for finish in self.reset:
+      finish()
+
+  def test_login(self):
+    response = self.c.get('/hue/accounts/login/')
+    assert_equal(200, response.status_code, "Expected ok status.")
+    assert_true(response.context['first_login_ever'])
+
+    response = self.c.post('/hue/accounts/login/', {
+        'username': self.test_username,
+        'password': "ldap1",
+        'password1': "ldap1",
+        'password2': "ldap1",
+        'server': "Local"
+    })
+    assert_equal(302, response.status_code, "Expected ok redirect status.")
+
+    response = self.c.get('/hue/accounts/login/')
+    assert_equal(200, response.status_code, "Expected ok status.")
+    assert_false(response.context['first_login_ever'])
+
+    self.c.get('/accounts/logout')
+
+    response = self.c.post('/hue/accounts/login/', {
+        'username': self.test_username,
+        'password': "ldap1",
+        'server': "LDAP"
+    })
+    assert_equal(200, response.status_code, "Expected ok status.")
+
+
 class TestLogin(PseudoHdfsTestBase):
 class TestLogin(PseudoHdfsTestBase):
 
 
   reset = []
   reset = []