auth: Reject authentication if auth backends are disabled.

This commit is contained in:
Tim Abbott 2016-11-06 15:09:21 -08:00
parent 30ab27c843
commit b41c15fa05
2 changed files with 57 additions and 7 deletions

View File

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
from django.conf import settings
from django.http import HttpResponse
from django.test import TestCase
from django.test import TestCase, override_settings
from django_auth_ldap.backend import _LDAPUser
from django.test.client import RequestFactory
from typing import Any, Callable, Dict, Optional
@ -87,6 +87,15 @@ class AuthBackendTest(TestCase):
result = backend.authenticate(username, *good_args, **good_kwargs)
self.assertEqual(user_profile, result)
# ZulipDummyBackend isn't a real backend so the remainder
# doesn't make sense for it
if isinstance(backend, ZulipDummyBackend):
return
# Verify auth fails if the auth backend is disabled on server
with self.settings(AUTHENTICATION_BACKENDS=('zproject.backends.ZulipDummyBackend',)):
self.assertIsNone(backend.authenticate(username, *good_args, **good_kwargs))
def test_dummy_backend(self):
# type: () -> None
self.verify_backend(ZulipDummyBackend(),
@ -146,6 +155,7 @@ class AuthBackendTest(TestCase):
with mock.patch('zproject.backends.password_auth_enabled', return_value=False):
self.assertIsNone(EmailAuthBackend().authenticate(email, password))
@override_settings(AUTHENTICATION_BACKENDS=('zproject.backends.GoogleMobileOauth2Backend',))
def test_google_backend(self):
# type: () -> None
email = "hamlet@zulip.com"
@ -192,6 +202,7 @@ class AuthBackendTest(TestCase):
result = backend.authenticate(return_data=ret)
self.assertIsNone(result)
@override_settings(AUTHENTICATION_BACKENDS=('zproject.backends.ZulipLDAPAuthBackend',))
def test_ldap_backend(self):
# type: () -> None
email = "hamlet@zulip.com"
@ -240,6 +251,7 @@ class AuthBackendTest(TestCase):
# type: () -> None
self.verify_backend(DevAuthBackend())
@override_settings(AUTHENTICATION_BACKENDS=('zproject.backends.ZulipRemoteUserBackend',))
def test_remote_user_backend(self):
# type: () -> None
self.setup_subdomain(get_user_profile_by_email(u'hamlet@zulip.com'))
@ -253,6 +265,7 @@ class AuthBackendTest(TestCase):
good_kwargs=dict(realm_subdomain='zulip'),
bad_kwargs=dict(realm_subdomain='acme'))
@override_settings(AUTHENTICATION_BACKENDS=('zproject.backends.ZulipRemoteUserBackend',))
def test_remote_user_backend_sso_append_domain(self):
# type: () -> None
self.setup_subdomain(get_user_profile_by_email(u'hamlet@zulip.com'))
@ -271,6 +284,7 @@ class AuthBackendTest(TestCase):
good_kwargs=dict(realm_subdomain='zulip'),
bad_kwargs=dict(realm_subdomain='acme'))
@override_settings(AUTHENTICATION_BACKENDS=('zproject.backends.GitHubAuthBackend',))
def test_github_backend(self):
# type: () -> None
email = 'hamlet@zulip.com'
@ -1148,6 +1162,7 @@ class TestLDAP(ZulipTestCase):
realm.string_id = 'zulip'
realm.save()
@override_settings(AUTHENTICATION_BACKENDS=('zproject.backends.ZulipLDAPAuthBackend',))
def test_login_success(self):
# type: () -> None
self.mock_ldap.directory = {
@ -1162,6 +1177,7 @@ class TestLDAP(ZulipTestCase):
user_profile = self.backend.authenticate('hamlet@zulip.com', 'testing')
self.assertEqual(user_profile.email, 'hamlet@zulip.com')
@override_settings(AUTHENTICATION_BACKENDS=('zproject.backends.ZulipLDAPAuthBackend',))
def test_login_failure_due_to_wrong_password(self):
# type: () -> None
self.mock_ldap.directory = {
@ -1177,6 +1193,7 @@ class TestLDAP(ZulipTestCase):
'uid=hamlet,ou=users,dc=zulip,dc=com:wrong'):
self.backend.authenticate('hamlet@zulip.com', 'wrong')
@override_settings(AUTHENTICATION_BACKENDS=('zproject.backends.ZulipLDAPAuthBackend',))
def test_login_failure_due_to_nonexistent_user(self):
# type: () -> None
self.mock_ldap.directory = {
@ -1192,6 +1209,7 @@ class TestLDAP(ZulipTestCase):
'uid=nonexistent,ou=users,dc=zulip,dc=com:testing'):
self.backend.authenticate('nonexistent@zulip.com', 'testing')
@override_settings(AUTHENTICATION_BACKENDS=('zproject.backends.ZulipLDAPAuthBackend',))
def test_ldap_permissions(self):
# type: () -> None
backend = self.backend
@ -1200,6 +1218,7 @@ class TestLDAP(ZulipTestCase):
self.assertTrue(backend.get_all_permissions(None, None) == set())
self.assertTrue(backend.get_group_permissions(None, None) == set())
@override_settings(AUTHENTICATION_BACKENDS=('zproject.backends.ZulipLDAPAuthBackend',))
def test_django_to_ldap_username(self):
# type: () -> None
backend = self.backend
@ -1207,6 +1226,7 @@ class TestLDAP(ZulipTestCase):
username = backend.django_to_ldap_username('"hamlet@test"@zulip.com')
self.assertEqual(username, '"hamlet@test"')
@override_settings(AUTHENTICATION_BACKENDS=('zproject.backends.ZulipLDAPAuthBackend',))
def test_ldap_to_django_username(self):
# type: () -> None
backend = self.backend
@ -1214,6 +1234,7 @@ class TestLDAP(ZulipTestCase):
username = backend.ldap_to_django_username('"hamlet@test"')
self.assertEqual(username, '"hamlet@test"@zulip.com')
@override_settings(AUTHENTICATION_BACKENDS=('zproject.backends.ZulipLDAPAuthBackend',))
def test_get_or_create_user_when_user_exists(self):
# type: () -> None
class _LDAPUser(object):
@ -1225,6 +1246,7 @@ class TestLDAP(ZulipTestCase):
self.assertFalse(created)
self.assertEqual(user_profile.email, email)
@override_settings(AUTHENTICATION_BACKENDS=('zproject.backends.ZulipLDAPAuthBackend',))
def test_get_or_create_user_when_user_does_not_exist(self):
# type: () -> None
class _LDAPUser(object):
@ -1240,6 +1262,7 @@ class TestLDAP(ZulipTestCase):
self.assertEqual(user_profile.email, email)
self.assertEqual(user_profile.full_name, 'Full Name')
@override_settings(AUTHENTICATION_BACKENDS=('zproject.backends.ZulipLDAPAuthBackend',))
def test_get_or_create_user_when_realm_is_deactivated(self):
# type: () -> None
class _LDAPUser(object):
@ -1255,6 +1278,7 @@ class TestLDAP(ZulipTestCase):
with self.assertRaisesRegexp(Exception, 'Realm has been deactivated'):
backend.get_or_create_user(email, _LDAPUser())
@override_settings(AUTHENTICATION_BACKENDS=('zproject.backends.ZulipLDAPAuthBackend',))
def test_django_to_ldap_username_when_domain_does_not_match(self):
# type: () -> None
backend = self.backend
@ -1263,6 +1287,7 @@ class TestLDAP(ZulipTestCase):
with self.settings(LDAP_APPEND_DOMAIN='acme.com'):
backend.django_to_ldap_username(email)
@override_settings(AUTHENTICATION_BACKENDS=('zproject.backends.ZulipLDAPAuthBackend',))
def test_login_failure_due_to_wrong_subdomain(self):
# type: () -> None
self.mock_ldap.directory = {
@ -1279,6 +1304,7 @@ class TestLDAP(ZulipTestCase):
realm_subdomain='acme')
self.assertIs(user_profile, None)
@override_settings(AUTHENTICATION_BACKENDS=('zproject.backends.ZulipLDAPAuthBackend',))
def test_login_failure_due_to_empty_subdomain(self):
# type: () -> None
self.mock_ldap.directory = {
@ -1295,6 +1321,7 @@ class TestLDAP(ZulipTestCase):
realm_subdomain='')
self.assertIs(user_profile, None)
@override_settings(AUTHENTICATION_BACKENDS=('zproject.backends.ZulipLDAPAuthBackend',))
def test_login_success_when_subdomain_is_none(self):
# type: () -> None
self.mock_ldap.directory = {
@ -1311,6 +1338,7 @@ class TestLDAP(ZulipTestCase):
realm_subdomain=None)
self.assertEqual(user_profile.email, 'hamlet@zulip.com')
@override_settings(AUTHENTICATION_BACKENDS=('zproject.backends.ZulipLDAPAuthBackend',))
def test_login_success_with_valid_subdomain(self):
# type: () -> None
self.mock_ldap.directory = {

View File

@ -95,6 +95,8 @@ class ZulipAuthMixin(object):
return None
class SocialAuthMixin(ZulipAuthMixin):
auth_backend_name = None # type: text_type
def get_email_address(self, *args, **kwargs):
# type: (*Any, **Any) -> text_type
raise NotImplementedError
@ -130,6 +132,10 @@ class SocialAuthMixin(ZulipAuthMixin):
return_data["invalid_subdomain"] = True
return None
if not auth_enabled_helper([self.auth_backend_name], user_profile.realm):
return_data["auth_backend_disabled"] = True
return None
return user_profile
def process_do_auth(self, user_profile, *args, **kwargs):
@ -238,6 +244,9 @@ class GoogleMobileOauth2Backend(ZulipAuthMixin):
if not check_subdomain(realm_subdomain, user_profile.realm.subdomain):
return_data["invalid_subdomain"] = True
return None
if not google_auth_enabled(realm=user_profile.realm):
return_data["google_auth_disabled"] = True
return None
return user_profile
else:
return_data["valid_attestation"] = False
@ -250,10 +259,14 @@ class ZulipRemoteUserBackend(RemoteUserBackend):
return None
email = remote_user_to_email(remote_user)
user = common_get_active_user_by_email(email)
if user is not None and check_subdomain(realm_subdomain, user.realm.subdomain):
return user
return None
user_profile = common_get_active_user_by_email(email)
if user_profile is None:
return None
if not check_subdomain(realm_subdomain, user_profile.realm.subdomain):
return None
if not auth_enabled_helper([u"RemoteUser"], user_profile.realm):
return None
return user_profile
class ZulipLDAPException(Exception):
pass
@ -314,6 +327,8 @@ class ZulipLDAPAuthBackend(ZulipLDAPAuthBackendBase):
user_profile = get_user_profile_by_email(username)
if not user_profile.is_active or user_profile.realm.deactivated:
raise ZulipLDAPException("Realm has been deactivated")
if not ldap_auth_enabled(user_profile.realm):
raise ZulipLDAPException("LDAP Authentication is not enabled")
return user_profile, False
except UserProfile.DoesNotExist:
domain = resolve_email_to_domain(username)
@ -341,10 +356,17 @@ class DevAuthBackend(ZulipAuthMixin):
# Allow logging in as any user without a password.
# This is used for convenience when developing Zulip.
def authenticate(self, username, realm_subdomain=None, return_data=None):
# type: (text_type, Optional[text_type], Optional[Dict[str, Any]]) -> UserProfile
return common_get_active_user_by_email(username, return_data=return_data)
# type: (text_type, Optional[text_type], Optional[Dict[str, Any]]) -> Optional[UserProfile]
user_profile = common_get_active_user_by_email(username, return_data=return_data)
if user_profile is None:
return None
if not dev_auth_enabled(user_profile.realm):
return None
return user_profile
class GitHubAuthBackend(SocialAuthMixin, GithubOAuth2):
auth_backend_name = u"GitHub"
def get_email_address(self, *args, **kwargs):
# type: (*Any, **Any) -> Optional[text_type]
try: