From 57f6ebd8ea4b33be7b8be21085ee578d77169edd 2014-07-13 22:38:39 From: Lance Edgar Date: 2014-07-13 22:38:39 Subject: [PATCH] Add `User.active` and disallow authentication for inactive users. --- diff --git a/rattail/db/auth.py b/rattail/db/auth.py index 1a94c9b8135005b83809d6909773f9e2911f6225..a4c8cfe3b5666f06c38b6999f1b13d91a4e00d97 100644 --- a/rattail/db/auth.py +++ b/rattail/db/auth.py @@ -1,9 +1,8 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- +# -*- coding: utf-8 -*- ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2012 Lance Edgar +# Copyright © 2010-2014 Lance Edgar # # This file is part of Rattail. # @@ -27,7 +26,8 @@ Authentication & Authorization """ import bcrypt -from .model import User, Role + +from rattail.db import model def authenticate_user(session, username, password): @@ -37,11 +37,10 @@ def authenticate_user(session, username, password): :returns: A :class:`.model.User` instance, if successful. Otherwise returns ``None``. """ - - user = session.query(User)\ + user = session.query(model.User)\ .filter_by(username=username)\ .first() - if user and bcrypt.hashpw(password, user.salt) == user.password: + if user and user.active and bcrypt.hashpw(password, user.salt) == user.password: return user return None @@ -60,9 +59,9 @@ def special_role(session, uuid, name): Fetches, or creates, a "special" role. """ - role = session.query(Role).get(uuid) + role = session.query(model.Role).get(uuid) if not role: - role = Role(uuid=uuid, name=name) + role = model.Role(uuid=uuid, name=name) session.add(role) return role diff --git a/rattail/db/model.py b/rattail/db/model.py index dacba2ade030f21f9cd52c07549f156a457978c8..7512da6f97fe1bc48953563ab116388154727635 100644 --- a/rattail/db/model.py +++ b/rattail/db/model.py @@ -289,6 +289,11 @@ class User(Base): salt = Column(String(length=29)) person_uuid = Column(String(length=32), ForeignKey('people.uuid')) + active = sa.Column(sa.Boolean(), nullable=False, default=True) + """ + Whether the user is active, e.g. allowed to log in via the UI. + """ + def __repr__(self): return "User(uuid={0})".format(repr(self.uuid)) diff --git a/tests/db/test_auth.py b/tests/db/test_auth.py new file mode 100644 index 0000000000000000000000000000000000000000..3236db58c5f199600e2f6bf341e8b7ea283aeb27 --- /dev/null +++ b/tests/db/test_auth.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- + +from .. import DataTestCase + +from rattail.db import auth +from rattail.db import model + + +class TestAuthenticateUser(DataTestCase): + + def test_nonexistent_user_returns_none(self): + self.assertTrue(auth.authenticate_user(self.session, u'fred', u'fredpass') is None) + + def test_correct_credentials_returns_user(self): + fred = model.User(username=u'fred') + auth.set_user_password(fred, u'fredpass') + self.session.add(fred) + self.session.commit() + user = auth.authenticate_user(self.session, u'fred', u'fredpass') + self.assertTrue(user is fred) + + def test_wrong_password_user_returns_none(self): + fred = model.User(username=u'fred', active=False) + auth.set_user_password(fred, u'fredpass') + self.session.add(fred) + self.session.commit() + self.assertTrue(auth.authenticate_user(self.session, u'fred', u'BADPASS') is None) + + def test_inactive_user_returns_none(self): + fred = model.User(username=u'fred', active=False) + auth.set_user_password(fred, u'fredpass') + self.session.add(fred) + self.session.commit() + self.assertTrue(auth.authenticate_user(self.session, u'fred', u'fredpass') is None)