Skip to content
This repository has been archived by the owner on Oct 24, 2018. It is now read-only.

Commit

Permalink
[#680] better support for is_active params
Browse files Browse the repository at this point in the history
  • Loading branch information
inkhey committed Jul 24, 2018
1 parent 69b14fb commit 098e300
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 9 deletions.
2 changes: 2 additions & 0 deletions tracim/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
from tracim.views.contents_api.comment_controller import CommentController
from tracim.views.errors import ErrorSchema
from tracim.exceptions import NotAuthenticated
from tracim.exceptions import UserNotActive
from tracim.exceptions import InvalidId
from tracim.exceptions import InsufficientUserProfile
from tracim.exceptions import InsufficientUserRoleInWorkspace
Expand Down Expand Up @@ -94,6 +95,7 @@ def web(global_config, **local_settings):
context.handle_exception(InvalidId, HTTPStatus.BAD_REQUEST)
# Auth exception
context.handle_exception(NotAuthenticated, HTTPStatus.UNAUTHORIZED)
context.handle_exception(UserNotActive, HTTPStatus.FORBIDDEN)
context.handle_exception(AuthenticationFailed, HTTPStatus.FORBIDDEN)
context.handle_exception(InsufficientUserRoleInWorkspace, HTTPStatus.FORBIDDEN) # nopep8
context.handle_exception(InsufficientUserProfile, HTTPStatus.FORBIDDEN)
Expand Down
4 changes: 4 additions & 0 deletions tracim/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,3 +167,7 @@ class EmptyLabelNotAllowed(EmptyValueNotAllowed):

class EmptyCommentContentNotAllowed(EmptyValueNotAllowed):
pass


class UserNotActive(TracimException):
pass
14 changes: 8 additions & 6 deletions tracim/lib/core/user.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
# -*- coding: utf-8 -*-
import threading
from smtplib import SMTPException

import transaction
import typing as typing

from tracim.exceptions import NotificationNotSend
from tracim.lib.mail_notifier.notifier import get_email_manager
from sqlalchemy.orm import Session
from sqlalchemy.orm.exc import NoResultFound

from tracim import CFG
from tracim.models.auth import User
from tracim.models.auth import Group
from sqlalchemy.orm.exc import NoResultFound
from tracim.exceptions import WrongUserPassword, UserDoesNotExist
from tracim.exceptions import WrongUserPassword
from tracim.exceptions import UserDoesNotExist
from tracim.exceptions import AuthenticationFailed
from tracim.exceptions import NotificationNotSend
from tracim.exceptions import UserNotActive
from tracim.models.context_models import UserInContext
from tracim.lib.mail_notifier.notifier import get_email_manager


class UserApi(object):
Expand Down Expand Up @@ -103,6 +103,8 @@ def authenticate_user(self, email: str, password: str) -> User:
"""
try:
user = self.get_one_by_email(email)
if not user.is_active:
raise UserNotActive('User "{}" is not active'.format(email))
if user.validate_password(password):
return user
else:
Expand Down
1 change: 1 addition & 0 deletions tracim/lib/utils/authentification.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ def basic_auth_check_credentials(
user = _get_basic_auth_unsafe_user(request)
if not user \
or user.email != login \
or not user.is_active \
or not user.validate_password(cleartext_password):
return None
return []
Expand Down
3 changes: 3 additions & 0 deletions tracim/lib/utils/request.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from sqlalchemy.orm.exc import NoResultFound

from tracim.exceptions import NotAuthenticated
from tracim.exceptions import UserNotActive
from tracim.exceptions import ContentNotFound
from tracim.exceptions import InvalidUserId
from tracim.exceptions import InvalidWorkspaceId
Expand Down Expand Up @@ -321,6 +322,8 @@ def _get_auth_safe_user(
if not login:
raise UserNotFoundInTracimRequest('You request a current user but the context not permit to found one') # nopep8
user = uapi.get_one_by_email(login)
if not user.is_active:
raise UserNotActive('User {} is not active'.format(login))
except (UserDoesNotExist, UserNotFoundInTracimRequest) as exc:
raise NotAuthenticated('User {} not found'.format(login)) from exc
return user
Expand Down
82 changes: 82 additions & 0 deletions tracim/tests/functional/test_session.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
# coding=utf-8
import datetime
import pytest
import transaction
from sqlalchemy.exc import OperationalError

from tracim import models
from tracim.lib.core.group import GroupApi
from tracim.lib.core.user import UserApi
from tracim.models import get_tm_session
from tracim.tests import FunctionalTest
from tracim.tests import FunctionalTestNoDB

Expand Down Expand Up @@ -59,6 +64,45 @@ def test_api__try_login_enpoint__ok_200__nominal_case(self):
assert res.json_body['caldav_url'] is None
assert res.json_body['avatar_url'] is None

def test_api__try_login_enpoint__err_401__user_not_activated(self):
dbsession = get_tm_session(self.session_factory, transaction.manager)
admin = dbsession.query(models.User) \
.filter(models.User.email == 'admin@admin.admin') \
.one()
uapi = UserApi(
current_user=admin,
session=dbsession,
config=self.app_config,
)
gapi = GroupApi(
current_user=admin,
session=dbsession,
config=self.app_config,
)
groups = [gapi.get_one_with_name('users')]
test_user = uapi.create_user(
email='test@test.test',
password='pass',
name='bob',
groups=groups,
timezone='Europe/Paris',
do_save=True,
do_notify=False,
)
uapi.save(test_user)
uapi.disable(test_user)
transaction.commit()

params = {
'email': 'test@test.test',
'password': 'test@test.test',
}
res = self.testapp.post_json(
'/api/v2/sessions/login',
params=params,
status=403,
)

def test_api__try_login_enpoint__err_403__bad_password(self):
params = {
'email': 'admin@admin.admin',
Expand Down Expand Up @@ -117,6 +161,44 @@ def test_api__try_whoami_enpoint__ok_200__nominal_case(self):
assert res.json_body['caldav_url'] is None
assert res.json_body['avatar_url'] is None

def test_api__try_whoami_enpoint__err_401__user_is_not_active(self):
dbsession = get_tm_session(self.session_factory, transaction.manager)
admin = dbsession.query(models.User) \
.filter(models.User.email == 'admin@admin.admin') \
.one()
uapi = UserApi(
current_user=admin,
session=dbsession,
config=self.app_config,
)
gapi = GroupApi(
current_user=admin,
session=dbsession,
config=self.app_config,
)
groups = [gapi.get_one_with_name('users')]
test_user = uapi.create_user(
email='test@test.test',
password='pass',
name='bob',
groups=groups,
timezone='Europe/Paris',
do_save=True,
do_notify=False,
)
uapi.save(test_user)
uapi.disable(test_user)
transaction.commit()
self.testapp.authorization = (
'Basic',
(
'test@test.test',
'pass'
)
)

res = self.testapp.get('/api/v2/sessions/whoami', status=401)

def test_api__try_whoami_enpoint__err_401__unauthenticated(self):
self.testapp.authorization = (
'Basic',
Expand Down
32 changes: 29 additions & 3 deletions tracim/tests/library/test_user_api.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
# -*- coding: utf-8 -*-
import pytest
from sqlalchemy.orm.exc import NoResultFound

import transaction

from tracim.exceptions import UserDoesNotExist, AuthenticationFailed
from tracim.exceptions import AuthenticationFailed
from tracim.exceptions import UserDoesNotExist
from tracim.exceptions import UserNotActive
from tracim.lib.core.group import GroupApi
from tracim.lib.core.user import UserApi
from tracim.models import User
from tracim.models.context_models import UserInContext
Expand Down Expand Up @@ -171,6 +172,31 @@ def test_unit__authenticate_user___ok__nominal_case(self):
assert isinstance(user, User)
assert user.email == 'admin@admin.admin'

def test_unit__authenticate_user___err__user_not_active(self):
api = UserApi(
current_user=None,
session=self.session,
config=self.config,
)
gapi = GroupApi(
current_user=None,
session=self.session,
config=self.config,
)
groups = [gapi.get_one_with_name('users')]
user = api.create_user(
email='test@test.test',
password='pass',
name='bob',
groups=groups,
timezone='Europe/Paris',
do_save=True,
do_notify=False,
)
api.disable(user)
with pytest.raises(UserNotActive):
api.authenticate_user('test@test.test', 'test@test.test')

def test_unit__authenticate_user___err__wrong_password(self):
api = UserApi(
current_user=None,
Expand Down

0 comments on commit 098e300

Please sign in to comment.