Annotate zproject/backends.py.

This commit is contained in:
Umair Khan 2016-08-08 12:38:50 +05:00 committed by Tim Abbott
parent fe812a89bf
commit 60f30fdb36
1 changed files with 39 additions and 3 deletions

View File

@ -1,12 +1,15 @@
from __future__ import absolute_import from __future__ import absolute_import
import logging import logging
from typing import Any, Set, Tuple, Optional
from six import text_type
from django.contrib.auth.backends import RemoteUserBackend from django.contrib.auth.backends import RemoteUserBackend
from django.conf import settings from django.conf import settings
from django.http import HttpResponse
import django.contrib.auth import django.contrib.auth
from django_auth_ldap.backend import LDAPBackend from django_auth_ldap.backend import LDAPBackend, _LDAPUser
from zerver.lib.actions import do_create_user from zerver.lib.actions import do_create_user
from zerver.models import UserProfile, Realm, get_user_profile_by_id, \ from zerver.models import UserProfile, Realm, get_user_profile_by_id, \
@ -21,6 +24,7 @@ from social.exceptions import AuthFailed
from django.contrib.auth import authenticate from django.contrib.auth import authenticate
def password_auth_enabled(realm): def password_auth_enabled(realm):
# type: (Realm) -> bool
if realm is not None: if realm is not None:
if realm.domain == 'zulip.com' and settings.PRODUCTION: if realm.domain == 'zulip.com' and settings.PRODUCTION:
# the dropbox realm is SSO only, but the unit tests still need to be # the dropbox realm is SSO only, but the unit tests still need to be
@ -35,18 +39,21 @@ def password_auth_enabled(realm):
return False return False
def dev_auth_enabled(): def dev_auth_enabled():
# type: () -> bool
for backend in django.contrib.auth.get_backends(): for backend in django.contrib.auth.get_backends():
if isinstance(backend, DevAuthBackend): if isinstance(backend, DevAuthBackend):
return True return True
return False return False
def google_auth_enabled(): def google_auth_enabled():
# type: () -> bool
for backend in django.contrib.auth.get_backends(): for backend in django.contrib.auth.get_backends():
if isinstance(backend, GoogleMobileOauth2Backend): if isinstance(backend, GoogleMobileOauth2Backend):
return True return True
return False return False
def common_get_active_user_by_email(email, return_data=None): def common_get_active_user_by_email(email, return_data=None):
# type: (text_type, Optional[Dict[str, Any]]) -> Optional[UserProfile]
try: try:
user_profile = get_user_profile_by_email(email) user_profile = get_user_profile_by_email(email)
except UserProfile.DoesNotExist: except UserProfile.DoesNotExist:
@ -62,6 +69,7 @@ def common_get_active_user_by_email(email, return_data=None):
return user_profile return user_profile
def github_auth_enabled(): def github_auth_enabled():
# type: () -> bool
for backend in django.contrib.auth.get_backends(): for backend in django.contrib.auth.get_backends():
if isinstance(backend, GitHubAuthBackend): if isinstance(backend, GitHubAuthBackend):
return True return True
@ -69,6 +77,7 @@ def github_auth_enabled():
class ZulipAuthMixin(object): class ZulipAuthMixin(object):
def get_user(self, user_profile_id): def get_user(self, user_profile_id):
# type: (int) -> Optional[UserProfile]
""" Get a UserProfile object from the user_profile_id. """ """ Get a UserProfile object from the user_profile_id. """
try: try:
return get_user_profile_by_id(user_profile_id) return get_user_profile_by_id(user_profile_id)
@ -77,12 +86,15 @@ class ZulipAuthMixin(object):
class SocialAuthMixin(ZulipAuthMixin): class SocialAuthMixin(ZulipAuthMixin):
def get_email_address(self, *args, **kwargs): def get_email_address(self, *args, **kwargs):
# type: (*Any, **Any) -> text_type
raise NotImplementedError raise NotImplementedError
def get_full_name(self, *args, **kwargs): def get_full_name(self, *args, **kwargs):
# type: (*Any, **Any) -> text_type
raise NotImplementedError raise NotImplementedError
def authenticate(self, *args, **kwargs): def authenticate(self, *args, **kwargs):
# type: (*Any, **Any) -> Optional[UserProfile]
return_data = kwargs.get('return_data', {}) return_data = kwargs.get('return_data', {})
email_address = self.get_email_address(*args, **kwargs) email_address = self.get_email_address(*args, **kwargs)
@ -106,6 +118,7 @@ class SocialAuthMixin(ZulipAuthMixin):
return user_profile return user_profile
def process_do_auth(self, user_profile, *args, **kwargs): def process_do_auth(self, user_profile, *args, **kwargs):
# type: (UserProfile, *Any, **Any) -> Optional[HttpResponse]
# This function needs to be imported from here due to the cyclic # This function needs to be imported from here due to the cyclic
# dependency. # dependency.
from zerver.views import login_or_register_remote_user from zerver.views import login_or_register_remote_user
@ -118,7 +131,7 @@ class SocialAuthMixin(ZulipAuthMixin):
if inactive_user or inactive_realm: if inactive_user or inactive_realm:
return None return None
request = self.strategy.request request = self.strategy.request # type: ignore # This comes from Python Social Auth.
email_address = self.get_email_address(*args, **kwargs) email_address = self.get_email_address(*args, **kwargs)
full_name = self.get_full_name(*args, **kwargs) full_name = self.get_full_name(*args, **kwargs)
@ -130,6 +143,7 @@ class ZulipDummyBackend(ZulipAuthMixin):
Used when we want to log you in but we don't know which backend to use. Used when we want to log you in but we don't know which backend to use.
""" """
def authenticate(self, username=None, use_dummy_backend=False): def authenticate(self, username=None, use_dummy_backend=False):
# type: (Optional[str], bool) -> Optional[UserProfile]
if use_dummy_backend: if use_dummy_backend:
return common_get_active_user_by_email(username) return common_get_active_user_by_email(username)
return None return None
@ -143,6 +157,7 @@ class EmailAuthBackend(ZulipAuthMixin):
""" """
def authenticate(self, username=None, password=None, return_data=None): def authenticate(self, username=None, password=None, return_data=None):
# type: (Optional[text_type], Optional[str], Optional[Dict[str, Any]]) -> Optional[UserProfile]
""" Authenticate a user based on email address as the user name. """ """ Authenticate a user based on email address as the user name. """
if username is None or password is None: if username is None or password is None:
# Return immediately. Otherwise we will look for a SQL row with # Return immediately. Otherwise we will look for a SQL row with
@ -171,7 +186,8 @@ class GoogleMobileOauth2Backend(ZulipAuthMixin):
https://developers.google.com/accounts/docs/CrossClientAuth#offlineAccess https://developers.google.com/accounts/docs/CrossClientAuth#offlineAccess
""" """
def authenticate(self, google_oauth2_token=None, return_data={}): def authenticate(self, google_oauth2_token=None, return_data=dict()):
# type: (Optional[str], Dict[str, Any]) -> Optional[UserProfile]
try: try:
token_payload = googleapiclient.verify_id_token(google_oauth2_token, settings.GOOGLE_CLIENT_ID) token_payload = googleapiclient.verify_id_token(google_oauth2_token, settings.GOOGLE_CLIENT_ID)
except AppIdentityError: except AppIdentityError:
@ -196,6 +212,7 @@ class ZulipRemoteUserBackend(RemoteUserBackend):
create_unknown_user = False create_unknown_user = False
def authenticate(self, remote_user): def authenticate(self, remote_user):
# type: (str) -> Optional[UserProfile]
if not remote_user: if not remote_user:
return None return None
@ -208,27 +225,40 @@ class ZulipLDAPException(Exception):
class ZulipLDAPAuthBackendBase(ZulipAuthMixin, LDAPBackend): class ZulipLDAPAuthBackendBase(ZulipAuthMixin, LDAPBackend):
# Don't use Django LDAP's permissions functions # Don't use Django LDAP's permissions functions
def has_perm(self, user, perm, obj=None): def has_perm(self, user, perm, obj=None):
# type: (UserProfile, Any, Any) -> bool
# Using Any type is safe because we are not doing anything with
# the arguments.
return False return False
def has_module_perms(self, user, app_label): def has_module_perms(self, user, app_label):
# type: (UserProfile, str) -> bool
return False return False
def get_all_permissions(self, user, obj=None): def get_all_permissions(self, user, obj=None):
# type: (UserProfile, Any) -> Set
# Using Any type is safe because we are not doing anything with
# the arguments.
return set() return set()
def get_group_permissions(self, user, obj=None): def get_group_permissions(self, user, obj=None):
# type: (UserProfile, Any) -> Set
# Using Any type is safe because we are not doing anything with
# the arguments.
return set() return set()
def django_to_ldap_username(self, username): def django_to_ldap_username(self, username):
# type: (text_type) -> text_type
if settings.LDAP_APPEND_DOMAIN: if settings.LDAP_APPEND_DOMAIN:
if not username.endswith("@" + settings.LDAP_APPEND_DOMAIN): if not username.endswith("@" + settings.LDAP_APPEND_DOMAIN):
raise ZulipLDAPException("Username does not match LDAP domain.") raise ZulipLDAPException("Username does not match LDAP domain.")
return email_to_username(username) return email_to_username(username)
return username return username
def ldap_to_django_username(self, username): def ldap_to_django_username(self, username):
# type: (str) -> str
if settings.LDAP_APPEND_DOMAIN: if settings.LDAP_APPEND_DOMAIN:
return "@".join((username, settings.LDAP_APPEND_DOMAIN)) return "@".join((username, settings.LDAP_APPEND_DOMAIN))
return username return username
class ZulipLDAPAuthBackend(ZulipLDAPAuthBackendBase): class ZulipLDAPAuthBackend(ZulipLDAPAuthBackendBase):
def authenticate(self, username, password, return_data=None): def authenticate(self, username, password, return_data=None):
# type: (text_type, str, Optional[Dict[str, Any]]) -> Optional[str]
try: try:
username = self.django_to_ldap_username(username) username = self.django_to_ldap_username(username)
return ZulipLDAPAuthBackendBase.authenticate(self, username, password) return ZulipLDAPAuthBackendBase.authenticate(self, username, password)
@ -238,6 +268,7 @@ class ZulipLDAPAuthBackend(ZulipLDAPAuthBackendBase):
return None return None
def get_or_create_user(self, username, ldap_user): def get_or_create_user(self, username, ldap_user):
# type: (str, _LDAPUser) -> Tuple[UserProfile, bool]
try: try:
user_profile = get_user_profile_by_email(username) user_profile = get_user_profile_by_email(username)
if not user_profile.is_active or user_profile.realm.deactivated: if not user_profile.is_active or user_profile.realm.deactivated:
@ -262,6 +293,7 @@ class ZulipLDAPAuthBackend(ZulipLDAPAuthBackendBase):
# Just like ZulipLDAPAuthBackend, but doesn't let you log in. # Just like ZulipLDAPAuthBackend, but doesn't let you log in.
class ZulipLDAPUserPopulator(ZulipLDAPAuthBackendBase): class ZulipLDAPUserPopulator(ZulipLDAPAuthBackendBase):
def authenticate(self, username, password): def authenticate(self, username, password):
# type: (text_type, str) -> None
return None return None
class DevAuthBackend(ZulipAuthMixin): class DevAuthBackend(ZulipAuthMixin):
@ -269,22 +301,26 @@ class DevAuthBackend(ZulipAuthMixin):
# This is used for convenience when developing Zulip. # This is used for convenience when developing Zulip.
def authenticate(self, username, return_data=None): def authenticate(self, username, return_data=None):
# type: (text_type, Optional[Dict[str, Any]]) -> UserProfile
return common_get_active_user_by_email(username, return_data=return_data) return common_get_active_user_by_email(username, return_data=return_data)
class GitHubAuthBackend(SocialAuthMixin, GithubOAuth2): class GitHubAuthBackend(SocialAuthMixin, GithubOAuth2):
def get_email_address(self, *args, **kwargs): def get_email_address(self, *args, **kwargs):
# type: (*Any, **Any) -> Optional[text_type]
try: try:
return kwargs['response']['email'] return kwargs['response']['email']
except KeyError: except KeyError:
return None return None
def get_full_name(self, *args, **kwargs): def get_full_name(self, *args, **kwargs):
# type: (*Any, **Any) -> text_type
try: try:
return kwargs['response']['name'] return kwargs['response']['name']
except KeyError: except KeyError:
return '' return ''
def do_auth(self, *args, **kwargs): def do_auth(self, *args, **kwargs):
# type: (*Any, **Any) -> Optional[UserProfile]
kwargs['return_data'] = {} kwargs['return_data'] = {}
user_profile = None user_profile = None