Browse Source

added security module

also started using fixtures on tests
master
Holger Frey 7 years ago
parent
commit
000d5582dd
  1. 55
      ordr2/security.py
  2. 73
      tests/__init__.py
  3. 105
      tests/security.py

55
ordr2/security.py

@ -0,0 +1,55 @@
''' User Authentication and Authorization '''
from pyramid.authentication import AuthTktAuthenticationPolicy
from pyramid.authorization import ACLAuthorizationPolicy
from pyramid.security import Authenticated, Everyone
from .models import User
class AuthenticationPolicy(AuthTktAuthenticationPolicy):
''' How to authenticate users '''
def authenticated_userid(self, request):
''' returns the id of an authenticated user
heavy lifting done in get_user() attached to request
'''
user = request.user
if user is not None:
return user.id
def effective_principals(self, request):
''' returns a list of principals for the user '''
principals = [Everyone]
user = request.user
if user is not None:
principals.append(Authenticated)
principals.append(user.principal)
principals.extend(user.role_principals)
return principals
def get_user(request):
''' retrieves the user object by the unauthenticated user id '''
user_id = request.unauthenticated_userid
if user_id is not None:
user = request.dbsession.query(User).filter_by(id=user_id).first()
if user and user.is_active:
return user
return None
def includeme(config):
''' initializing authentication and authorization for the Pyramid app
Activate this setup using ``config.include('ordr2.security')``.
'''
settings = config.get_settings()
authn_policy = AuthenticationPolicy(
settings['auth.secret'],
hashalg='sha512',
)
config.set_authentication_policy(authn_policy)
config.set_authorization_policy(ACLAuthorizationPolicy())
config.add_request_method(get_user, 'user', reify=True)

73
tests/__init__.py

@ -1 +1,74 @@
''' Test package for ordr2. ''' ''' Test package for ordr2. '''
import pytest
import transaction
from pyramid import testing
APP_SETTINGS = {
'sqlalchemy.url': 'sqlite:///:memory:',
'auth.secret': 'not-very-secure',
'session.secret': 'not-very-secure',
'session.auto_csrf': True
}
# helpers
def create_users(db):
''' set up some well known example users '''
from ordr2.models import Role, User
stubs = [
('Graham', 'Chapman', Role.UNVALIDATED),
('John', 'Cleese', Role.NEW),
('Terry', 'Gilliam', Role.USER),
('Eric', 'Idle', Role.PURCHASER),
('Terry', 'Jones', Role.ADMIN),
('Michael', 'Palin', Role.INACTIVE)
]
for i, stub in enumerate(stubs):
first_name, last_name, role = stub
user = User(
id=i+1,
username=first_name + last_name,
first_name = first_name,
last_name = last_name,
email = last_name.lower() + '@example.com',
role=role,
password_hash = first_name.lower()
)
db.add(user)
# fixtures
@pytest.fixture(scope='session')
def app_config():
''' fixture for tests requiring a pyramid.testing setup '''
with testing.testConfig(settings=APP_SETTINGS) as config:
config.include('pyramid_jinja2')
#config.include('pyramid_mailer.testing')
yield config
@pytest.fixture(scope='function')
def dbsession(app_config):
''' fixture for testing with database connection '''
from ordr2.models.meta import Base
from ordr2.models import (
get_engine,
get_session_factory,
get_tm_session
)
settings = app_config.get_settings()
engine = get_engine(settings)
session_factory = get_session_factory(engine)
session = get_tm_session(session_factory, transaction.manager)
Base.metadata.create_all(engine)
yield session
transaction.abort()
Base.metadata.drop_all(engine)

105
tests/security.py

@ -0,0 +1,105 @@
''' Tests for ordr2.security '''
import pytest
from . import app_config, dbsession, create_users
# tests for ordr2.security.AuthenticationPolicy
def test_authenticated_userid_no_user():
''' test if authenticated user id is None if no active user present '''
from pyramid.testing import DummyRequest
from ordr2.security import AuthenticationPolicy
request = DummyRequest(user=None)
policy = AuthenticationPolicy(secret='')
assert policy.authenticated_userid(request) is None
def test_authenticated_userid_with_user():
''' test if authenticated user id is the id of the user '''
from pyramid.testing import DummyRequest
from ordr2.models import User
from ordr2.security import AuthenticationPolicy
user = User(id=3)
request = DummyRequest(user=user)
policy = AuthenticationPolicy(secret='')
assert policy.authenticated_userid(request) == 3
def test_effective_principals_no_user():
''' test the effective principals if no user is authenticated '''
from pyramid.testing import DummyRequest
from pyramid.security import Everyone
from ordr2.security import AuthenticationPolicy
request = DummyRequest(user=None)
policy = AuthenticationPolicy(secret='')
assert policy.effective_principals(request) == [Everyone]
@pytest.mark.parametrize(
'role_name, role_principals', [
('UNVALIDATED', ['role:unvalidated']),
('NEW', ['role:new']),
('USER', ['role:user']),
('PURCHASER', ['role:purchaser', 'role:user']),
('ADMIN', ['role:admin', 'role:purchaser', 'role:user']),
('INACTIVE', ['role:inactive'])
]
)
def test_effective_principals_with_user(role_name, role_principals):
''' test the effective principals if a user is authenticated '''
from pyramid.testing import DummyRequest
from pyramid.security import Authenticated, Everyone
from ordr2.models import User, Role
from ordr2.security import AuthenticationPolicy
role = Role[role_name]
user = User(id=3, role=role)
request = DummyRequest(user=user)
policy = AuthenticationPolicy(secret='')
expected = [Everyone, Authenticated, 'user:3']
expected.extend(role_principals)
assert policy.effective_principals(request) == expected
# tests for the get_user function
def test_get_user_no_unauthenticated_user_id():
''' get_user() should return None if unauthenticated_userid is None '''
from pyramid.testing import DummyRequest
from ordr2.security import get_user
request = DummyRequest(unauthenticated_userid=None)
assert get_user(request) is None
@pytest.mark.parametrize(
'user_id', [
3, # active user, must work
pytest.mark.xfail(1), # inactive user, must fail
pytest.mark.xfail(1969), # unknown user id, must fail
]
)
def test_get_user_no_unauthenticated_user_id(user_id, dbsession):
''' get_user() should return None if unauthenticated_userid is None '''
from collections import namedtuple
from ordr2.models import User, Role
from ordr2.security import get_user
create_users(dbsession)
# pyramid.testing.DummyRequest can't be used, since the parameter
# unauthenticated_userid cannot be set. A named tuple is used instead
Request = namedtuple('Request', 'dbsession, unauthenticated_userid')
request = Request(dbsession=dbsession, unauthenticated_userid=user_id)
user = get_user(request)
assert isinstance(user, User)