On Thu, Feb 5, 2009 at 10:49 AM, Christoph Zwerschke <[email protected]> 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. >
this is a good option too. > 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. > I don't like this one, same reasons. > 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. > so far this is the best compromise. > 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. > this isn't bad either, but it's more stuff than the simple #3 > 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. > for the record something similar to this was proposed by me some time ago http://groups.google.com/group/turbogears-trunk/browse_thread/thread/4991c7ef2f713dca/bde319e023fa7f21 > 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. One thing I am concern about all the solutions above is the db hits, will a new evaluation of the same predicate hit the db, or the check will return from the environ dict? --~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---
