Files
pecan/tests/test_secure.py
Mark McClain 6c053856f3 Permissions are now checked as routing moves between controllers
.pecan metadata renamed to ._pecan
2011-01-14 21:40:23 -05:00

277 lines
9.0 KiB
Python

from unittest import TestCase
from pecan import expose, make_app
from pecan.secure import secure, unlocked, SecureController, Protected
from webtest import TestApp
try:
set()
except:
from sets import Set as set
class TestSecure(object):
def test_simple_secure(self):
authorized = False
class SecretController(SecureController):
@expose()
def index(self):
return 'Index'
@expose()
@unlocked
def allowed(self):
return 'Allowed!'
@classmethod
def check_permissions(self):
return authorized
class RootController(object):
@expose()
def index(self):
return 'Hello, World!'
@expose()
@secure(lambda: False)
def locked(self):
return 'No dice!'
@expose()
@secure(lambda: True)
def unlocked(self):
return 'Sure thing'
secret = SecretController()
app = TestApp(make_app(RootController(), static_root='tests/static'))
response = app.get('/')
assert response.status_int == 200
assert response.body == 'Hello, World!'
response = app.get('/unlocked')
assert response.status_int == 200
assert response.body == 'Sure thing'
response = app.get('/locked', expect_errors=True)
assert response.status_int == 401
response = app.get('/secret', expect_errors=True)
assert response.status_int == 401
response = app.get('/secret/allowed')
assert response.status_int == 200
assert response.body == 'Allowed!'
def test_unlocked_attribute(self):
class AuthorizedSubController(object):
@expose()
def index(self):
return 'Index'
@expose()
def allowed(self):
return 'Allowed!'
class SecretController(SecureController):
@expose()
def index(self):
return 'Index'
@expose()
@unlocked
def allowed(self):
return 'Allowed!'
authorized = unlocked(AuthorizedSubController())
class RootController(object):
@expose()
def index(self):
return 'Hello, World!'
@expose()
@secure(lambda: False)
def locked(self):
return 'No dice!'
@expose()
@secure(lambda: True)
def unlocked(self):
return 'Sure thing'
secret = SecretController()
app = TestApp(make_app(RootController(), static_root='tests/static'))
response = app.get('/')
assert response.status_int == 200
assert response.body == 'Hello, World!'
response = app.get('/unlocked')
assert response.status_int == 200
assert response.body == 'Sure thing'
response = app.get('/locked', expect_errors=True)
assert response.status_int == 401
response = app.get('/secret', expect_errors=True)
assert response.status_int == 401
response = app.get('/secret/allowed')
assert response.status_int == 200
assert response.body == 'Allowed!'
response = app.get('/secret/authorized')
assert response.status_int == 200
assert response.body == 'Index'
response = app.get('/secret/authorized/allowed')
assert response.status_int == 200
assert response.body == 'Allowed!'
def test_state_attribute(self):
from pecan.secure import Any, Protected
assert repr(Any) == '<SecureState Any>'
assert bool(Any) is False
assert repr(Protected) == '<SecureState Protected>'
assert bool(Protected) is True
class TestObjectPathSecurity(TestCase):
def setUp(self):
permissions_checked = getattr(self, 'permissions_checked', set())
class DeepSecretController(SecureController):
authorized = False
@expose()
@unlocked
def _lookup(self, someID, *remainder):
if someID == 'notfound':
return None
return SubController(someID), remainder
@expose()
def index(self):
return 'Deep Secret'
@classmethod
def check_permissions(self):
permissions_checked.add('deepsecret')
return self.authorized
deepsecret_instance = DeepSecretController()
class SubController(object):
def __init__(self, myID):
self.myID = myID
@expose()
def index(self):
return 'Index %s' % self.myID
deepsecret = DeepSecretController()
class SecretController(SecureController):
authorized = False
@expose()
def _lookup(self, someID, *remainder):
if someID == 'notfound':
return None
return SubController(someID), remainder
@classmethod
def check_permissions(self):
permissions_checked.add('secretcontroller')
return self.authorized
class NotSecretController(object):
@expose()
def _lookup(self, someID, *remainder):
if someID == 'notfound':
return None
return SubController(someID), remainder
class RootController(object):
secret = SecretController()
notsecret = NotSecretController()
self.deepsecret_cls = DeepSecretController
self.secret_cls = SecretController
self.permissions_checked = permissions_checked
self.app = TestApp(make_app(RootController(), static_root='tests/static'))
def tearDown(self):
self.permissions_checked.clear()
self.secret_cls.authorized = False
self.deepsecret_cls.authorized = False
def test_sub_of_both_not_secret(self):
response = self.app.get('/notsecret/hi/')
assert response.status_int == 200
assert response.body == 'Index hi'
def test_protected_lookup(self):
response = self.app.get('/secret/hi/', expect_errors=True)
assert response.status_int == 401
self.secret_cls.authorized = True
response = self.app.get('/secret/hi/')
assert response.status_int == 200
assert response.body == 'Index hi'
assert 'secretcontroller' in self.permissions_checked
def test_secured_notfound_lookup(self):
response = self.app.get('/secret/notfound/', expect_errors=True)
assert response.status_int == 404
def test_secret_through_lookup(self):
response = self.app.get('/notsecret/hi/deepsecret/', expect_errors=True)
assert response.status_int == 401
def test_layered_protection(self):
response = self.app.get('/secret/hi/deepsecret/', expect_errors=True)
assert response.status_int == 401
assert 'secretcontroller' in self.permissions_checked
self.secret_cls.authorized = True
response = self.app.get('/secret/hi/deepsecret/', expect_errors=True)
assert response.status_int == 401
assert 'secretcontroller' in self.permissions_checked
assert 'deepsecret' in self.permissions_checked
self.deepsecret_cls.authorized = True
response = self.app.get('/secret/hi/deepsecret/')
assert response.status_int == 200
assert response.body == 'Deep Secret'
assert 'secretcontroller' in self.permissions_checked
assert 'deepsecret' in self.permissions_checked
def test_cyclical_protection(self):
self.secret_cls.authorized = True
self.deepsecret_cls.authorized = True
response = self.app.get('/secret/1/deepsecret/2/deepsecret/')
assert response.status_int == 200
assert response.body == 'Deep Secret'
assert 'secretcontroller' in self.permissions_checked
assert 'deepsecret' in self.permissions_checked
def test_unlocked_lookup(self):
response = self.app.get('/notsecret/1/deepsecret/2/')
assert response.status_int == 200
assert response.body == 'Index 2'
assert 'deepsecret' not in self.permissions_checked
response = self.app.get('/notsecret/1/deepsecret/notfound/', expect_errors=True)
assert response.status_int == 404
assert 'deepsecret' not in self.permissions_checked
def test_mixed_protection(self):
self.secret_cls.authorized = True
response = self.app.get('/secret/1/deepsecret/notfound/', expect_errors=True)
assert response.status_int == 404
assert 'secretcontroller' in self.permissions_checked
assert 'deepsecret' not in self.permissions_checked