Skip to content

Commit

Permalink
@require now provides smart behavior, and can be used to just abort, …
Browse files Browse the repository at this point in the history
…rather than do redirect. Closes #27
  • Loading branch information
pedersen committed Sep 25, 2012
1 parent d3016c6 commit bcb5e77
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 6 deletions.
17 changes: 17 additions & 0 deletions tests/test_stack/test_authz.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,10 @@ def index(self):
def commit(self):
return 'you can commit'

@expose()
@require(is_user('developer'), smart_denial=True)
def smartabort(self):
return {'key': 'value'}

class ControllerWithAllowOnlyAttributeAndAuthzDenialHandler(TGController):
"""Mock TG2 protected controller using the .allow_only attribute"""
Expand Down Expand Up @@ -247,6 +251,19 @@ def test_authz_denied_in_sub_controller(self):
assert "was just registered" not in resp.body
self._check_flash(resp, r'The current user must be \"admin\"')

def test_smart_auth_json(self):
nouser = {'accept': 'application/json'}
baduser = {'accept': 'application/json',
'REMOTE_USER': 'foobar'}
gooduser = {'accept': 'application/json',
'REMOTE_USER': 'developer'}
resp = self.app.get('/smartabort', extra_environ=nouser, status=401)
assert resp.status == '401 Unauthorized', 'Expected 401, got %s' % (resp.status)
resp = self.app.get('/smartabort', extra_environ=baduser, status=403)
assert resp.status == '403 Forbidden', 'Expected 403, got %s' % (resp.status)
resp = self.app.get('/smartabort.json', extra_environ=gooduser, status=200)
assert resp.status == '200 OK', 'Expected 200, got %s' % (resp.body)


class TestAllowOnlyDecoratorInSubController(BaseIntegrationTests):
"""Test case for the @allow_only decorator in a sub-controller"""
Expand Down
13 changes: 7 additions & 6 deletions tg/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -698,7 +698,7 @@ def sample(self, *args):
class _BaseProtectionDecorator(object):
default_denial_handler = None

def __init__(self, predicate, denial_handler=None):
def __init__(self, predicate, denial_handler=None, smart_denial=False):
"""Verify that the predicate is met.
:param predicate: An object with a check_authorization(environ) method which
Expand All @@ -713,6 +713,7 @@ def __init__(self, predicate, denial_handler=None):

self.predicate = predicate
self.denial_handler = denial_handler or self.default_denial_handler
self.smart_denial = smart_denial


class require(_BaseProtectionDecorator):
Expand Down Expand Up @@ -750,12 +751,12 @@ def wrap_action(self, action_, *args, **kwargs):

def default_denial_handler(self, reason):
"""Authorization denial handler for protectors."""
if response.status_int == 401:
status = 'warning'
status = 'warning' if response.status_int == 401 else 'error'
if not self.smart_denial:
flash(reason, status=status)
else:
# Status is a 403
status = 'error'
flash(reason, status=status)
if response.content_type not in ['application/json', 'text/xml']:
flash(reason, status=status)
abort(response.status_int, reason)


Expand Down

0 comments on commit bcb5e77

Please sign in to comment.