1# Copyright (c) 2012-2016 Seafile Ltd. 2import datetime 3from importlib import import_module 4from warnings import warn 5 6from django.conf import settings 7from django.core.exceptions import ImproperlyConfigured 8 9from seahub.auth.signals import user_logged_in 10 11from constance import config 12 13SESSION_KEY = '_auth_user_name' 14BACKEND_SESSION_KEY = '_auth_user_backend_2' 15REDIRECT_FIELD_NAME = 'next' 16 17def load_backend(path): 18 i = path.rfind('.') 19 module, attr = path[:i], path[i+1:] 20 try: 21 mod = import_module(module) 22 except ImportError as e: 23 raise ImproperlyConfigured('Error importing authentication backend %s: "%s"' % (module, e)) 24 except ValueError as e: 25 raise ImproperlyConfigured('Error importing authentication backends. Is AUTHENTICATION_BACKENDS a correctly defined list or tuple?') 26 try: 27 cls = getattr(mod, attr) 28 except AttributeError: 29 raise ImproperlyConfigured('Module "%s" does not define a "%s" authentication backend' % (module, attr)) 30 try: 31 getattr(cls, 'supports_object_permissions') 32 except AttributeError: 33 warn("Authentication backends without a `supports_object_permissions` attribute are deprecated. Please define it in %s." % cls, 34 PendingDeprecationWarning) 35 cls.supports_object_permissions = False 36 try: 37 getattr(cls, 'supports_anonymous_user') 38 except AttributeError: 39 warn("Authentication backends without a `supports_anonymous_user` attribute are deprecated. Please define it in %s." % cls, 40 PendingDeprecationWarning) 41 cls.supports_anonymous_user = False 42 return cls() 43 44def get_backends(): 45 backends = [] 46 for backend_path in settings.AUTHENTICATION_BACKENDS: 47 backends.append(load_backend(backend_path)) 48 return backends 49 50def authenticate(**credentials): 51 """ 52 If the given credentials are valid, return a User object. 53 """ 54 for backend in get_backends(): 55 try: 56 user = backend.authenticate(**credentials) 57 except TypeError: 58 # This backend doesn't accept these credentials as arguments. Try the next one. 59 continue 60 if user is None: 61 continue 62 # Annotate the user object with the path of the backend. 63 user.backend = "%s.%s" % (backend.__module__, backend.__class__.__name__) 64 return user 65 66def login(request, user): 67 """ 68 Persist a user id and a backend in the request. This way a user doesn't 69 have to reauthenticate on every request. 70 """ 71 if user is None: 72 user = request.user 73 # TODO: It would be nice to support different login methods, like signed cookies. 74 user.last_login = datetime.datetime.now() 75 76 if SESSION_KEY in request.session: 77 if request.session[SESSION_KEY] != user.username: 78 # To avoid reusing another user's session, create a new, empty 79 # session if the existing session corresponds to a different 80 # authenticated user. 81 request.session.flush() 82 else: 83 request.session.cycle_key() 84 85 request.session[SESSION_KEY] = user.username 86 request.session[BACKEND_SESSION_KEY] = user.backend 87 88 if request.session.get('remember_me', False): 89 request.session.set_expiry(config.LOGIN_REMEMBER_DAYS * 24 * 60 * 60) 90 if hasattr(request, 'user'): 91 request.user = user 92 user_logged_in.send(sender=user.__class__, request=request, user=user) 93 94def logout(request): 95 """ 96 Removes the authenticated user's ID from the request and flushes their 97 session data. 98 Also remove all passwords used to decrypt repos. 99 """ 100 request.session.flush() 101 if hasattr(request, 'user'): 102 from seahub.base.accounts import User 103 if isinstance(request.user, User): 104 # Do not directly/indirectly import models in package root level. 105 from seahub.utils import is_org_context 106 if is_org_context(request): 107 org_id = request.user.org.org_id 108 request.user.remove_org_repo_passwds(org_id) 109 else: 110 request.user.remove_repo_passwds() 111 from seahub.auth.models import AnonymousUser 112 request.user = AnonymousUser() 113 114def get_user(request): 115 from seahub.auth.models import AnonymousUser 116 try: 117 username = request.session[SESSION_KEY] 118 backend_path = request.session[BACKEND_SESSION_KEY] 119 backend = load_backend(backend_path) 120 user = backend.get_user(username) or AnonymousUser() 121 except KeyError: 122 user = AnonymousUser() 123 return user 124