Hello,
I think we need more comments on this to make sure we'll end up with the right
solution, but so far only three of us have participated. :(
What do you people think about this?
Cheers.
On Thursday February 5, 2009 15:49:22 Christoph Zwerschke wrote:
> Hello all,
>
> recently in a now pretty lengthy thread we discussed how you can ceck
> authorization information in TG2 applications. We had some ideas which I
> will summarize in the following, and we would like to get your feedback
> concerning these ideas.
>
> The problem: Restricting access with the require() decorator based on
> repoze.what predicates such as has_permission('edit') is often not
> sufficient; you want to e.g. check the same permissions in a py:if
> directive of a Genshi template to show certain info only to editors, or
> e.g. get the set of groups of which the current user is a member because
> you want to use them as values in a drop down box etc.
>
> In TG1, this was easily possible using the properties and methods of
> turbogears.identity.current, which was also available as tg.identity
> inside templates.
>
> For instance, in a TG1 template you could write py:if="'edit' in
> tg.identity.permissions".
>
> In a TG2 template, this is actually still possible, since tg.identity is
> in TG2 an alias for repoze.who.identity and (currently) repoze.what also
> stores the permissions here. However, the goal is to clearly separate
> identification and authentication from authorization, so that
> tg.identity will not contain authorization information any more in the
> future.
>
> So we need to find another way to check this information which should be
> very simple; at least as simple as it was in TG1.
>
> Gustavo (the author of repoze.what) already added a method is_met() to
> repoze.what predicates that evaluates the predicate and returns a
> boolean (instead of logging the result and raising an exception if
> necessary as predicates usually do). However, you still need to pass the
> current environment to that method which makes usage not as
> straightforward as in TG1.
>
> In order to simplify this, we have discussed the following ideas so far.
> Please let us know how you like them or if you have any better ideas:
>
> 1) Often the need for checking permissions in a template arises because
> you want to hide links to restricted pages which may not be accessible.
> You currently have to repeat the predicate that is used in the require
> decorator of the restricted controller which is against DRY. The idea
> here is to implement a function can_access() or accessible() that checks
> for a given controller path whether it would be accsible
> (http://trac.turbogears.org/ticket/2172), using the information from the
> existing require() decorator. I think that's a good idea.
>
> 2) There should be another TG function evaluate() for evaluating
> repoze.what predicates, currying an internal function that expects the
> current environment (http://trac.turbogears.org/ticket/2173).
>
> Personally I think that is still not simple enough. You will have to use
> py:if="evaluate(has_permission('manage'))" in a template, with the need
> to pass both the evaluate function and the predicates as template
> variables (or make them standard variables which does not seem a good
> idea either). Also, it's easy to forget the evaluate() call, thus
> security holes would be preprogrammed.
>
> 3) Michael came up with the idea to overwrite the __nonzero__ method of
> predicates. This could for example raise an error when used in the form
> py:if="has_permission('manage')" without the evaluate call. But we could
> also go a step further and let __nonzero__ automatically evaluate the
> predicate. The predicates would have a dual use then, both for require
> decorators (not immediately evaluated) and for py:if statements
> (immediately evaluated).
>
> The following simple monkey-patch would allow this double usage of all
> repoze.what predicates in TG2:
>
> -----------------------------------------------------------------
> from tg import request
> from repoze.what.predicates import Predicate
> Predicate.__nonzero__ = lambda self: self.is_met(request.environ)
> -----------------------------------------------------------------
>
> Instead, we could also create a TG specific subclass of repoze.what
> predicates that allows this double usage, and also create copies of the
> existing predicates on the fly.
>
> Both the monkey-patching (or subclassing and copying) and the double
> usage is a bit hackish though and maybe a bit too much magic.
>
> 4) A different solution is to add an "access" object to TG2 and make it
> a standard template variable that auto-evaluates predicates passed as
> attributes. Here is a possible implementation:
>
> -------------------------------------------------------------
> from tg import request
> from repoze.what import predicates
>
> class Access(object):
> """Environ-aware predicates evaluating immediately."""
>
> def __getattr__(self, name):
> predicate = getattr(predicates, name)
> if callable(predicate):
> def predicate_is_met(*args, **kwargs):
> return predicate(*args, *kwargs).is_met(
> request.environ)
> return predicate_is_met
> else:
> return predicate
>
> access = Access() # make this a standard tg template variable
> -------------------------------------------------------------
>
> This would allow easy evaluation of all existing predicates in templates
> in the form tg.acess.has_permission('edit'). We could also provide a
> mechanism for including additional custom predicates in the access object.
>
> 5) Another idea was to make repoze.what.credentials publicly available
> in TG2 templates with an alias tg.credentials. However, the problem here
> is that Gustavo wants to keep repoze.what.credentials an implementation
> detail and not part of the public API, because he wants the concept of
> groups and permission flexible enough to evolve in the future; e.g.
> groups may become hierarchical.
>
> Instead, repoze.what v2 will have additional functions for getting the
> current groups and permissions. I think that's good; and these functions
> should be made available as standard template variables.
>
> 6) Just for the record, we also need replacements for the TG1 identity
> predicates identity.from_host and identity.from_any_host in form of
> repoze.what predicates. There will hopefully be a repoze.what network
> plugin including such predicates soon. Until then, we need to write a
> custom predicate checking REMOTE_ADDR.
>
> -- Christoph
>
>
--
Gustavo Narea <http://gustavonarea.net/>.
Get rid of unethical constraints! Get freedomware:
http://www.getgnulinux.org/
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"TurboGears Trunk" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/turbogears-trunk?hl=en
-~----------~----~----~----~------~----~------~--~---