nope, what ChrisP wants is to be able to protect a full controller
without being forced to used a decorator on each exposed method.
This is something that is still needed.
Florent.
I think I have a sample of something that could work for this
somewhere, I'll try to post it up somewhere (or just add it to
tgrepozewho) in the next couple of days.
--Mark Ramm
Here's the code snipit Jonathan sent me a while back::
from pylons.controllers.util import abort
from pylons.controllers.objectdispatch import iscontroller
from tg import expose
import inspect
def walk_controller(root_class, controller):
if hasattr(controller, 'lookup'):
lookup = controller.lookup
@expose()
def new_lookup(*args, **kwargs):
root_class._perform_validation()
return lookup(*args, **kwargs)
controller.lookup = new_lookup
for name, value in inspect.getmembers(controller):
if inspect.ismethod(value):
if iscontroller(value):
value.decoration.hooks['before_call'].append(
root_class._perform_validation
)
elif hasattr(value, '__class__'):
if name.startswith('__') and name.endswith('__'): continue
walk_controller(root_class, value)
class SecuredControllerMeta(type):
def __init__(cls, name, bases, dict_):
walk_controller(cls, cls)
class SecuredController(object):
__metaclass__ = SecuredControllerMeta
@classmethod
def check_permissions(cls):
return True
@classmethod
def _perform_validation(cls, *args, **kwargs):
if not cls.check_permissions():
abort(401, 'Unauthorized')
Basically this ensures that the classmethod check_permissions is
called (at the before_call hook) for every method in the class, or any
of it's member objects.
Obviously we could extend this so that we do identity predicate checks
specifically. But as long as check_permission returns a boolian value
we're good.
And we might be able to tweek the dispatch mechanism a bit to
eliminate the need for some of this stuff. This works, but it's not
particularly efficient at object instantiation time...
--Mark
--
Mark Ramm-Christensen
email: mark at compoundthinking dot com
blog: www.compoundthinking.com/blog
> And we might be able to tweek the dispatch mechanism a bit to
> eliminate the need for some of this stuff. This works, but it's
> not particularly efficient at object instantiation time...
We should definitely push some of this into the dispatch mechanism,
just to make the code simpler. However, since its using a
metaclass, its actually quite efficient at object instantiation
time, since all of the work occurs when the class is loaded (at
import).
--
Jonathan LaCour
http://cleverdevil.org
I'll add a hook in the object dispatch which enforces restrictions on
classes so that dispatch can stop as soon as a not-authorized event is
hit. We should be able to make this backwards compatible with TG1's
secure controller -- but my plan is just to check for a callable
grant_access in the controller, and evaluate that callable if it
exists. We can create a SecureResource class with two things:
1) a require property that can be set to an identity predicate. It
will default to requiring login, because that's the most common case::
require = not_anonymous()
2) a grant_access callable that returns True or False, using require.
To create custom security mechanisms for a controller you'd just need
to add a grant_access callable....
What do you think?