瀏覽代碼

[#680] better support for is_active params

Guénaël Muller 5 年之前
父節點
當前提交
098e300a8f

+ 2 - 0
tracim/__init__.py 查看文件

@@ -29,6 +29,7 @@ from tracim.views.core_api.workspace_controller import WorkspaceController
29 29
 from tracim.views.contents_api.comment_controller import CommentController
30 30
 from tracim.views.errors import ErrorSchema
31 31
 from tracim.exceptions import NotAuthenticated
32
+from tracim.exceptions import UserNotActive
32 33
 from tracim.exceptions import InvalidId
33 34
 from tracim.exceptions import InsufficientUserProfile
34 35
 from tracim.exceptions import InsufficientUserRoleInWorkspace
@@ -94,6 +95,7 @@ def web(global_config, **local_settings):
94 95
     context.handle_exception(InvalidId, HTTPStatus.BAD_REQUEST)
95 96
     # Auth exception
96 97
     context.handle_exception(NotAuthenticated, HTTPStatus.UNAUTHORIZED)
98
+    context.handle_exception(UserNotActive, HTTPStatus.FORBIDDEN)
97 99
     context.handle_exception(AuthenticationFailed, HTTPStatus.FORBIDDEN)
98 100
     context.handle_exception(InsufficientUserRoleInWorkspace, HTTPStatus.FORBIDDEN)  # nopep8
99 101
     context.handle_exception(InsufficientUserProfile, HTTPStatus.FORBIDDEN)

+ 4 - 0
tracim/exceptions.py 查看文件

@@ -167,3 +167,7 @@ class EmptyLabelNotAllowed(EmptyValueNotAllowed):
167 167
 
168 168
 class EmptyCommentContentNotAllowed(EmptyValueNotAllowed):
169 169
     pass
170
+
171
+
172
+class UserNotActive(TracimException):
173
+    pass

+ 8 - 6
tracim/lib/core/user.py 查看文件

@@ -1,21 +1,21 @@
1 1
 # -*- coding: utf-8 -*-
2
-import threading
3 2
 from smtplib import SMTPException
4 3
 
5 4
 import transaction
6 5
 import typing as typing
7
-
8
-from tracim.exceptions import NotificationNotSend
9
-from tracim.lib.mail_notifier.notifier import get_email_manager
10 6
 from sqlalchemy.orm import Session
7
+from sqlalchemy.orm.exc import NoResultFound
11 8
 
12 9
 from tracim import CFG
13 10
 from tracim.models.auth import User
14 11
 from tracim.models.auth import Group
15
-from sqlalchemy.orm.exc import NoResultFound
16
-from tracim.exceptions import WrongUserPassword, UserDoesNotExist
12
+from tracim.exceptions import WrongUserPassword
13
+from tracim.exceptions import UserDoesNotExist
17 14
 from tracim.exceptions import AuthenticationFailed
15
+from tracim.exceptions import NotificationNotSend
16
+from tracim.exceptions import UserNotActive
18 17
 from tracim.models.context_models import UserInContext
18
+from tracim.lib.mail_notifier.notifier import get_email_manager
19 19
 
20 20
 
21 21
 class UserApi(object):
@@ -103,6 +103,8 @@ class UserApi(object):
103 103
         """
104 104
         try:
105 105
             user = self.get_one_by_email(email)
106
+            if not user.is_active:
107
+                raise UserNotActive('User "{}" is not active'.format(email))
106 108
             if user.validate_password(password):
107 109
                 return user
108 110
             else:

+ 1 - 0
tracim/lib/utils/authentification.py 查看文件

@@ -32,6 +32,7 @@ def basic_auth_check_credentials(
32 32
     user = _get_basic_auth_unsafe_user(request)
33 33
     if not user \
34 34
             or user.email != login \
35
+            or not user.is_active \
35 36
             or not user.validate_password(cleartext_password):
36 37
         return None
37 38
     return []

+ 3 - 0
tracim/lib/utils/request.py 查看文件

@@ -3,6 +3,7 @@ from pyramid.request import Request
3 3
 from sqlalchemy.orm.exc import NoResultFound
4 4
 
5 5
 from tracim.exceptions import NotAuthenticated
6
+from tracim.exceptions import UserNotActive
6 7
 from tracim.exceptions import ContentNotFound
7 8
 from tracim.exceptions import InvalidUserId
8 9
 from tracim.exceptions import InvalidWorkspaceId
@@ -321,6 +322,8 @@ class TracimRequest(Request):
321 322
             if not login:
322 323
                 raise UserNotFoundInTracimRequest('You request a current user but the context not permit to found one')  # nopep8
323 324
             user = uapi.get_one_by_email(login)
325
+            if not user.is_active:
326
+                raise UserNotActive('User {} is not active'.format(login))
324 327
         except (UserDoesNotExist, UserNotFoundInTracimRequest) as exc:
325 328
             raise NotAuthenticated('User {} not found'.format(login)) from exc
326 329
         return user

+ 82 - 0
tracim/tests/functional/test_session.py 查看文件

@@ -1,8 +1,13 @@
1 1
 # coding=utf-8
2 2
 import datetime
3 3
 import pytest
4
+import transaction
4 5
 from sqlalchemy.exc import OperationalError
5 6
 
7
+from tracim import models
8
+from tracim.lib.core.group import GroupApi
9
+from tracim.lib.core.user import UserApi
10
+from tracim.models import get_tm_session
6 11
 from tracim.tests import FunctionalTest
7 12
 from tracim.tests import FunctionalTestNoDB
8 13
 
@@ -59,6 +64,45 @@ class TestLoginEndpoint(FunctionalTest):
59 64
         assert res.json_body['caldav_url'] is None
60 65
         assert res.json_body['avatar_url'] is None
61 66
 
67
+    def test_api__try_login_enpoint__err_401__user_not_activated(self):
68
+        dbsession = get_tm_session(self.session_factory, transaction.manager)
69
+        admin = dbsession.query(models.User) \
70
+            .filter(models.User.email == 'admin@admin.admin') \
71
+            .one()
72
+        uapi = UserApi(
73
+            current_user=admin,
74
+            session=dbsession,
75
+            config=self.app_config,
76
+        )
77
+        gapi = GroupApi(
78
+            current_user=admin,
79
+            session=dbsession,
80
+            config=self.app_config,
81
+        )
82
+        groups = [gapi.get_one_with_name('users')]
83
+        test_user = uapi.create_user(
84
+            email='test@test.test',
85
+            password='pass',
86
+            name='bob',
87
+            groups=groups,
88
+            timezone='Europe/Paris',
89
+            do_save=True,
90
+            do_notify=False,
91
+        )
92
+        uapi.save(test_user)
93
+        uapi.disable(test_user)
94
+        transaction.commit()
95
+
96
+        params = {
97
+            'email': 'test@test.test',
98
+            'password': 'test@test.test',
99
+        }
100
+        res = self.testapp.post_json(
101
+            '/api/v2/sessions/login',
102
+            params=params,
103
+            status=403,
104
+        )
105
+
62 106
     def test_api__try_login_enpoint__err_403__bad_password(self):
63 107
         params = {
64 108
             'email': 'admin@admin.admin',
@@ -117,6 +161,44 @@ class TestWhoamiEndpoint(FunctionalTest):
117 161
         assert res.json_body['caldav_url'] is None
118 162
         assert res.json_body['avatar_url'] is None
119 163
 
164
+    def test_api__try_whoami_enpoint__err_401__user_is_not_active(self):
165
+        dbsession = get_tm_session(self.session_factory, transaction.manager)
166
+        admin = dbsession.query(models.User) \
167
+            .filter(models.User.email == 'admin@admin.admin') \
168
+            .one()
169
+        uapi = UserApi(
170
+            current_user=admin,
171
+            session=dbsession,
172
+            config=self.app_config,
173
+        )
174
+        gapi = GroupApi(
175
+            current_user=admin,
176
+            session=dbsession,
177
+            config=self.app_config,
178
+        )
179
+        groups = [gapi.get_one_with_name('users')]
180
+        test_user = uapi.create_user(
181
+            email='test@test.test',
182
+            password='pass',
183
+            name='bob',
184
+            groups=groups,
185
+            timezone='Europe/Paris',
186
+            do_save=True,
187
+            do_notify=False,
188
+        )
189
+        uapi.save(test_user)
190
+        uapi.disable(test_user)
191
+        transaction.commit()
192
+        self.testapp.authorization = (
193
+            'Basic',
194
+            (
195
+                'test@test.test',
196
+                'pass'
197
+            )
198
+        )
199
+
200
+        res = self.testapp.get('/api/v2/sessions/whoami', status=401)
201
+
120 202
     def test_api__try_whoami_enpoint__err_401__unauthenticated(self):
121 203
         self.testapp.authorization = (
122 204
             'Basic',

+ 29 - 3
tracim/tests/library/test_user_api.py 查看文件

@@ -1,10 +1,11 @@
1 1
 # -*- coding: utf-8 -*-
2 2
 import pytest
3
-from sqlalchemy.orm.exc import NoResultFound
4
-
5 3
 import transaction
6 4
 
7
-from tracim.exceptions import UserDoesNotExist, AuthenticationFailed
5
+from tracim.exceptions import AuthenticationFailed
6
+from tracim.exceptions import UserDoesNotExist
7
+from tracim.exceptions import UserNotActive
8
+from tracim.lib.core.group import GroupApi
8 9
 from tracim.lib.core.user import UserApi
9 10
 from tracim.models import User
10 11
 from tracim.models.context_models import UserInContext
@@ -171,6 +172,31 @@ class TestUserApi(DefaultTest):
171 172
         assert isinstance(user, User)
172 173
         assert user.email == 'admin@admin.admin'
173 174
 
175
+    def test_unit__authenticate_user___err__user_not_active(self):
176
+        api = UserApi(
177
+            current_user=None,
178
+            session=self.session,
179
+            config=self.config,
180
+        )
181
+        gapi = GroupApi(
182
+            current_user=None,
183
+            session=self.session,
184
+            config=self.config,
185
+        )
186
+        groups = [gapi.get_one_with_name('users')]
187
+        user = api.create_user(
188
+            email='test@test.test',
189
+            password='pass',
190
+            name='bob',
191
+            groups=groups,
192
+            timezone='Europe/Paris',
193
+            do_save=True,
194
+            do_notify=False,
195
+        )
196
+        api.disable(user)
197
+        with pytest.raises(UserNotActive):
198
+            api.authenticate_user('test@test.test', 'test@test.test')
199
+
174 200
     def test_unit__authenticate_user___err__wrong_password(self):
175 201
         api = UserApi(
176 202
             current_user=None,