Browse Source

[#680] better support for is_active params

Guénaël Muller 6 years ago
parent
commit
098e300a8f

+ 2 - 0
tracim/__init__.py View File

29
 from tracim.views.contents_api.comment_controller import CommentController
29
 from tracim.views.contents_api.comment_controller import CommentController
30
 from tracim.views.errors import ErrorSchema
30
 from tracim.views.errors import ErrorSchema
31
 from tracim.exceptions import NotAuthenticated
31
 from tracim.exceptions import NotAuthenticated
32
+from tracim.exceptions import UserNotActive
32
 from tracim.exceptions import InvalidId
33
 from tracim.exceptions import InvalidId
33
 from tracim.exceptions import InsufficientUserProfile
34
 from tracim.exceptions import InsufficientUserProfile
34
 from tracim.exceptions import InsufficientUserRoleInWorkspace
35
 from tracim.exceptions import InsufficientUserRoleInWorkspace
94
     context.handle_exception(InvalidId, HTTPStatus.BAD_REQUEST)
95
     context.handle_exception(InvalidId, HTTPStatus.BAD_REQUEST)
95
     # Auth exception
96
     # Auth exception
96
     context.handle_exception(NotAuthenticated, HTTPStatus.UNAUTHORIZED)
97
     context.handle_exception(NotAuthenticated, HTTPStatus.UNAUTHORIZED)
98
+    context.handle_exception(UserNotActive, HTTPStatus.FORBIDDEN)
97
     context.handle_exception(AuthenticationFailed, HTTPStatus.FORBIDDEN)
99
     context.handle_exception(AuthenticationFailed, HTTPStatus.FORBIDDEN)
98
     context.handle_exception(InsufficientUserRoleInWorkspace, HTTPStatus.FORBIDDEN)  # nopep8
100
     context.handle_exception(InsufficientUserRoleInWorkspace, HTTPStatus.FORBIDDEN)  # nopep8
99
     context.handle_exception(InsufficientUserProfile, HTTPStatus.FORBIDDEN)
101
     context.handle_exception(InsufficientUserProfile, HTTPStatus.FORBIDDEN)

+ 4 - 0
tracim/exceptions.py View File

167
 
167
 
168
 class EmptyCommentContentNotAllowed(EmptyValueNotAllowed):
168
 class EmptyCommentContentNotAllowed(EmptyValueNotAllowed):
169
     pass
169
     pass
170
+
171
+
172
+class UserNotActive(TracimException):
173
+    pass

+ 8 - 6
tracim/lib/core/user.py View File

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

+ 1 - 0
tracim/lib/utils/authentification.py View File

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

+ 3 - 0
tracim/lib/utils/request.py View File

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

+ 82 - 0
tracim/tests/functional/test_session.py View File

1
 # coding=utf-8
1
 # coding=utf-8
2
 import datetime
2
 import datetime
3
 import pytest
3
 import pytest
4
+import transaction
4
 from sqlalchemy.exc import OperationalError
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
 from tracim.tests import FunctionalTest
11
 from tracim.tests import FunctionalTest
7
 from tracim.tests import FunctionalTestNoDB
12
 from tracim.tests import FunctionalTestNoDB
8
 
13
 
59
         assert res.json_body['caldav_url'] is None
64
         assert res.json_body['caldav_url'] is None
60
         assert res.json_body['avatar_url'] is None
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
     def test_api__try_login_enpoint__err_403__bad_password(self):
106
     def test_api__try_login_enpoint__err_403__bad_password(self):
63
         params = {
107
         params = {
64
             'email': 'admin@admin.admin',
108
             'email': 'admin@admin.admin',
117
         assert res.json_body['caldav_url'] is None
161
         assert res.json_body['caldav_url'] is None
118
         assert res.json_body['avatar_url'] is None
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
     def test_api__try_whoami_enpoint__err_401__unauthenticated(self):
202
     def test_api__try_whoami_enpoint__err_401__unauthenticated(self):
121
         self.testapp.authorization = (
203
         self.testapp.authorization = (
122
             'Basic',
204
             'Basic',

+ 29 - 3
tracim/tests/library/test_user_api.py View File

1
 # -*- coding: utf-8 -*-
1
 # -*- coding: utf-8 -*-
2
 import pytest
2
 import pytest
3
-from sqlalchemy.orm.exc import NoResultFound
4
-
5
 import transaction
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
 from tracim.lib.core.user import UserApi
9
 from tracim.lib.core.user import UserApi
9
 from tracim.models import User
10
 from tracim.models import User
10
 from tracim.models.context_models import UserInContext
11
 from tracim.models.context_models import UserInContext
171
         assert isinstance(user, User)
172
         assert isinstance(user, User)
172
         assert user.email == 'admin@admin.admin'
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
     def test_unit__authenticate_user___err__wrong_password(self):
200
     def test_unit__authenticate_user___err__wrong_password(self):
175
         api = UserApi(
201
         api = UserApi(
176
             current_user=None,
202
             current_user=None,