|
1 |
| -from bolt.csrf.middleware import rotate_token |
2 |
| -from bolt.exceptions import ImproperlyConfigured |
3 |
| -from bolt.packages import packages as bolt_packages |
4 |
| -from bolt.runtime import settings |
5 |
| -from bolt.utils.crypto import constant_time_compare |
| 1 | +from .sessions import get_user, get_user_model, login, logout |
6 | 2 |
|
7 |
| -from .signals import user_logged_in, user_logged_out |
8 |
| - |
9 |
| -USER_ID_SESSION_KEY = "_auth_user_id" |
10 |
| -USER_HASH_SESSION_KEY = "_auth_user_hash" |
11 |
| - |
12 |
| - |
13 |
| -def _get_user_id_from_session(request): |
14 |
| - # This value in the session is always serialized to a string, so we need |
15 |
| - # to convert it back to Python whenever we access it. |
16 |
| - return get_user_model()._meta.pk.to_python(request.session[USER_ID_SESSION_KEY]) |
17 |
| - |
18 |
| - |
19 |
| -def login(request, user): |
20 |
| - """ |
21 |
| - Persist a user id and a backend in the request. This way a user doesn't |
22 |
| - have to reauthenticate on every request. Note that data set during |
23 |
| - the anonymous session is retained when the user logs in. |
24 |
| - """ |
25 |
| - if user.SESSION_HASH_FIELD: |
26 |
| - session_auth_hash = user.get_session_auth_hash() |
27 |
| - else: |
28 |
| - session_auth_hash = "" |
29 |
| - |
30 |
| - if USER_ID_SESSION_KEY in request.session: |
31 |
| - if _get_user_id_from_session(request) != user.pk: |
32 |
| - # To avoid reusing another user's session, create a new, empty |
33 |
| - # session if the existing session corresponds to a different |
34 |
| - # authenticated user. |
35 |
| - request.session.flush() |
36 |
| - elif session_auth_hash and not constant_time_compare( |
37 |
| - request.session.get(USER_HASH_SESSION_KEY, ""), session_auth_hash |
38 |
| - ): |
39 |
| - # If the session hash does not match the current hash, reset the |
40 |
| - # session. Most likely this means the password was changed. |
41 |
| - request.session.flush() |
42 |
| - else: |
43 |
| - request.session.cycle_key() |
44 |
| - |
45 |
| - request.session[USER_ID_SESSION_KEY] = user._meta.pk.value_to_string(user) |
46 |
| - request.session[USER_HASH_SESSION_KEY] = session_auth_hash |
47 |
| - if hasattr(request, "user"): |
48 |
| - request.user = user |
49 |
| - rotate_token(request) |
50 |
| - user_logged_in.send(sender=user.__class__, request=request, user=user) |
51 |
| - |
52 |
| - |
53 |
| -def logout(request): |
54 |
| - """ |
55 |
| - Remove the authenticated user's ID from the request and flush their session |
56 |
| - data. |
57 |
| - """ |
58 |
| - # Dispatch the signal before the user is logged out so the receivers have a |
59 |
| - # chance to find out *who* logged out. |
60 |
| - user = getattr(request, "user", None) |
61 |
| - user_logged_out.send(sender=user.__class__, request=request, user=user) |
62 |
| - request.session.flush() |
63 |
| - if hasattr(request, "user"): |
64 |
| - request.user = None |
65 |
| - |
66 |
| - |
67 |
| -def get_user_model(): |
68 |
| - """ |
69 |
| - Return the User model that is active in this project. |
70 |
| - """ |
71 |
| - try: |
72 |
| - return bolt_packages.get_model(settings.AUTH_USER_MODEL, require_ready=False) |
73 |
| - except ValueError: |
74 |
| - raise ImproperlyConfigured( |
75 |
| - "AUTH_USER_MODEL must be of the form 'package_label.model_name'" |
76 |
| - ) |
77 |
| - except LookupError: |
78 |
| - raise ImproperlyConfigured( |
79 |
| - "AUTH_USER_MODEL refers to model '%s' that has not been installed" |
80 |
| - % settings.AUTH_USER_MODEL |
81 |
| - ) |
82 |
| - |
83 |
| - |
84 |
| -def get_user(request): |
85 |
| - """ |
86 |
| - Return the user model instance associated with the given request session. |
87 |
| - If no user is retrieved, return None. |
88 |
| - """ |
89 |
| - if USER_ID_SESSION_KEY not in request.session: |
90 |
| - return None |
91 |
| - |
92 |
| - user_id = _get_user_id_from_session(request) |
93 |
| - |
94 |
| - UserModel = get_user_model() |
95 |
| - try: |
96 |
| - user = UserModel._default_manager.get(pk=user_id) |
97 |
| - except UserModel.DoesNotExist: |
98 |
| - return None |
99 |
| - |
100 |
| - # If the user models defines a specific field to also hash and compare |
101 |
| - # (like password), then we verify that the hash of that field is still |
102 |
| - # the same as when the session was created. |
103 |
| - # |
104 |
| - # If it has changed (i.e. password changed), then the session |
105 |
| - # is no longer valid and cleared out. |
106 |
| - if user.SESSION_HASH_FIELD: |
107 |
| - session_hash = request.session.get(USER_HASH_SESSION_KEY) |
108 |
| - if not session_hash: |
109 |
| - session_hash_verified = False |
110 |
| - else: |
111 |
| - session_auth_hash = user.get_session_auth_hash() |
112 |
| - session_hash_verified = constant_time_compare( |
113 |
| - session_hash, session_auth_hash |
114 |
| - ) |
115 |
| - if not session_hash_verified: |
116 |
| - # If the current secret does not verify the session, try |
117 |
| - # with the fallback secrets and stop when a matching one is |
118 |
| - # found. |
119 |
| - if session_hash and any( |
120 |
| - constant_time_compare(session_hash, fallback_auth_hash) |
121 |
| - for fallback_auth_hash in user.get_session_auth_fallback_hash() |
122 |
| - ): |
123 |
| - request.session.cycle_key() |
124 |
| - request.session[USER_HASH_SESSION_KEY] = session_auth_hash |
125 |
| - else: |
126 |
| - request.session.flush() |
127 |
| - user = None |
128 |
| - |
129 |
| - return user |
| 3 | +__all__ = ["login", "logout", "get_user_model", "get_user"] |
0 commit comments