[Repoze-dev] repoze.what custom predicate parameters
Hi, I'd like to write custom Predicates for an application using repoze.what with TurboGears2. My predicate would perform some query on the database and check the resulting object against predefined criterion. The issue is that the request to the db needs to filter based on a parameter that is posted on the controller method I protected with @require. At the moment the check_auth function takes only predicate and environ and I'd like to add some *args, **kwargs to pass in the params that would then go to the decorated controller. This would permit my custom predicate to perfom its db query based on the request params (as I would do in my controller's code) and thus avoid code duplication inside each protected controller. If you know any other pattern that would help solve my issue, please don't hesitate to enlighten me... if you think this would be a worthy addition, then state so and I'll go ahead and propose a patch. Florent Aide. ___ Repoze-dev mailing list Repoze-dev@lists.repoze.org http://lists.repoze.org/listinfo/repoze-dev
Re: [Repoze-dev] repoze.what custom predicate parameters
On Monday January 26, 2009 16:18:36 Florent Aide wrote: a here is the patch that would permit to write the kind of predicates I need... Gustavo, what do you think? Is that ok with you to apply this on the trunk. You broke compatibility anyway so why not break it a little more... :) Well, I've not broken compatibility since the first stable release and I hope that won't ever be necessary. I've just deprecated some things for forward compatibility. :) The problem is that people are not expected to evaluate predicates by themselves using Predicate.evaluate(); that's what check_authorization() is for: http://static.repoze.org/whatdocs/Manual/Predicates.html#repoze.what.predicates.Predicate.evaluate Therefore, unfortunately it'd be useless that .evaluate() was able to receive arbitrary arguments and keyword arguments because it will never receive them. It'll only receive what check_authorization() passes to it (unless you run .evaluate() by yourself, which is discouraged -- check_authorization() does some useful things for you unlike plain .evaluate()). As I mentioned in the previous email, I agree that context-sensitive authorization should require less code (i.e., not using paste.request.parse_formvars by yourself). But my concern is how to do it without breaking compatibility. I'm open to any solution that won't break compatibility. In repoze.what v2, the way I'll address this is by passing the POST and GET variables to .evaluate() too. At least that's the solution I have in mind right now. Cheers! -- Gustavo Narea http://gustavonarea.net/. Get rid of unethical constraints! Get freedomware: http://www.getgnulinux.org/ ___ Repoze-dev mailing list Repoze-dev@lists.repoze.org http://lists.repoze.org/listinfo/repoze-dev
[Repoze-dev] repoze.bfg 0.6.5 released
repoze.bfg 0.6.5 was just put into the http://dist.repoze.org/lemonade/dev/simple/ index. This release has a couple of new features, but it's mostly a speed micro-optimization release. As a result, a repoze.bfg hello world application runs (for me) at somewhere between 900 and 1100 req/sec on a MacBook 2GHz machine, up from somewhere around 700 req/sec or so in 0.6.3. 0.6.5 (2009-01-26) == Features - You can now override the NotFound and Unauthorized responses that :mod:`repoze.bfg` generates when a view cannot be found or cannot be invoked due to lack of permission. See the ZCML Hooks chapter in the docs for more information. - Added Routes ZCML directive attribute explanations in documentation. - Added a ``traversal_path`` API to the traversal module; see the traversal API chapter in the docs. This was a function previously known as ``split_path`` that was not an API but people were using it anyway. Unlike ``split_path``, it now returns a tuple instead of a list (as its values are cached). Behavior Changes - The ``repoze.bfg.view.render_view_to_response`` API will no longer raise a ValueError if an object returned by a view function it calls does not possess certain attributes (``headerlist``, ``app_iter``, ``status``). This API used to attempt to perform a check using the ``is_response`` function in ``repoze.bfg.view``, and raised a ``ValueError`` if the ``is_response`` check failed. The responsibility is now the caller's to ensure that the return value from a view function is a real response. - WSGI environ dicts passed to ``repoze.bfg`` 's Router must now contain a REQUEST_METHOD key/value; if they do not, a KeyError will be raised (speed). - It is no longer permissible to pass a nested list of principals to ``repoze.bfg.ACLAuthorizer.permits`` (e.g. ``['fred', ['larry', 'bob']]``). The principals list must be fully expanded. This feature was never documented, and was never an API, so it's not a backwards incompatibility. - It is no longer permissible for a security ACE to contain a nested list of permissions (e.g. ``(Allow, Everyone, ['read', ['view', ['write', 'manage']]])`)`. The list must instead be fully expanded (e.g. ``(Allow, Everyone, ['read', 'view', 'write', 'manage])``). This feature was never documented, and was never an API, so it's not a backwards incompatibility. - The ``repoze.bfg.urldispatch.RoutesRootFactory`` now injects the ``wsgiorg.routing_args`` environment variable into the environ when a route matches. This is a tuple of ((), routing_args) where routing_args is the value that comes back from the routes mapper match (the match dict). - The ``repoze.bfg.traversal.RoutesModelTraverser`` class now wants to obtain the ``view_name`` and ``subpath`` from the ``wsgiorgs.routing_args`` environment variable. It falls back to obtaining these from the context for backwards compatibility. Implementation Changes -- - Get rid of ``repoze.bfg.security.ACLAuthorizer``: the ``ACLSecurityPolicy`` now does what it did inline. - Get rid of ``repoze.bfg.interfaces.NoAuthorizationInformation`` exception: it was used only by ``ACLAuthorizer``. - Use a homegrown NotFound error instead of ``webob.exc.HTTPNotFound`` (the latter is slow). - Use a homegrown Unauthorized error instead of ``webob.exc.Unauthorized`` (the latter is slow). - the ``repoze.bfg.lru.lru_cached`` decorator now uses functools.wraps in order to make documentation of LRU-cached functions possible. - Various speed micro-tweaks. Bug Fixes - - ``repoze.bfg.testing.DummyModel`` did not have a ``get`` method; it now does. ___ Repoze-dev mailing list Repoze-dev@lists.repoze.org http://lists.repoze.org/listinfo/repoze-dev
Re: [Repoze-dev] repoze.what custom predicate parameters
On Monday January 26, 2009 17:50:25 Florent Aide wrote: this won't work with urls of the form: /blog/post/post_id and thus we'll need to devise something more, like introspection of the decorated controller's method's args... That's a good point. Fortunately I read this email before sending the other email/poll to the Repoze and TG mailing lists. Let's continue this over there :) Cheers. -- Gustavo Narea http://gustavonarea.net/. Get rid of unethical constraints! Get freedomware: http://www.getgnulinux.org/ ___ Repoze-dev mailing list Repoze-dev@lists.repoze.org http://lists.repoze.org/listinfo/repoze-dev
Re: [Repoze-dev] [r.what] Backwards incompatibility in exchange for better context sensitivity?
-BEGIN PGP SIGNED MESSAGE- Hash: SHA1 Gustavo Narea wrote: Hello, everybody. Florent and I have been discussing about context-sensitivity in repoze.what-1.0 predicates and there's a good enhancement that may be applied but will break backwards compatibility, and I won't break backwards incompatibility unless you want it. If you have repoze.what predicates this would affect you, so please read on. Right now repoze.what predicates are context-sensitive because they are evaluated with the WSGI environment. *But* if you have predicates that depend on POST/GET variables, then you have to use Paste to extract the variables you need from the WSGI environment. This is, GET/POST variables are used a lot in context-sensitivity authorization but they're not at hand (you need to write a little more code to get them). So, there's a proposed solution which would make the Predicate.evaluate(environ, credentials) method receive one more argument: The GET and POST variables. So its signature would end up as: evaluate(environ, credentials, variables) (where ``variables`` is a dict, and ``variables['post']`` and ``variables['get']`` contain the POST and GET variables respectively) But if I implement it, then your custom predicates (if any) will break. I think it's a good compromise because: 1.- If your predicates still use the ._eval_with_environ() method then you'll have to switch to .evaluate() the sooner or later anyway because it's deprecated (but still supported). 2.- Upgrading is easy: Just add the variables argument to your .evaluate() method. In case you don't find the big advantage of this change, think how you'd deal with predicates that depend on GET/POST variables: from paste.request import parse_formvars from repoze.what.predicates import Predicate from yourcoolapplication.model import BlogPost, DBSession class can_edit_post(Predicate): message = 'Post %(post_id)s can only be edited by its author' def __init__(self, post_id_variable='post_id', **kwargs): self.post_id_variable = post_id_variable super(can_edit_post, self).__init__(**kwargs) def evaluate(self, environ, credentials): # Extracting the post Id from the POST/GET variables vars = parse_formvars(environ) post_id = vars.get(self.post_id_variable) if not post_id: self.unmet('Post Id is not available') # Loading the post object post = DBSession.query(BlogPost).filter(post_id=post_id).one() # Checking if it's the author if post.author_userid != credentials.get('repoze.what.userid'): self.unmet(post_id=post_id) While you could write: from repoze.what.predicates import Predicate from yourcoolapplication.model import BlogPost, DBSession class can_edit_post(Predicate): message = 'Post %(post_id)s can only be edited by its author' def __init__(self, post_id_variable='post_id', **kwargs): self.post_id_variable = post_id_variable super(can_edit_post, self).__init__(**kwargs) def evaluate(self, environ, credentials, variables): post_id = variables['post'].get(self.post_id_variable) if not post_id: self.unmet('Post Id is not available') # Loading the post object post = DBSession.query(BlogPost).filter(post_id=post_id).one() # Checking if it's the author if post.author_userid != credentials.get('repoze.what.userid'): self.unmet(post_id=post_id) Regarding variables available before the query string (if any; e.g., /blog/post/post_id), as supported in TG, they could be passed by the framework to the check_authorization() function so that it inserts them into ``variables['extra']``. This would be optional, of course. Finally, do you think this backwards incompatible change worths it? The poll ends by tomorrow evening here in western Europe. :) I would make 'check_authorization' call a new method 'evaluate_with_variables', which just passes through to 'evaluate' in the base class (Predicate): people could override it to do the extra checking. The cost is one extra function call for those not using the indirection, but preserves backward compatibility. Tres. - -- === Tres Seaver +1 540-429-0999 tsea...@palladion.com Palladion Software Excellence by Designhttp://palladion.com -BEGIN PGP SIGNATURE- Version: GnuPG v1.4.6 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQFJfgj4+gerLs4ltQ4RAomMAJ9BMNAEkd6msnGq2YINaGe4w5tnDQCglSEx Cd60dqxfYgp7QO9fDngZ5B8= =gQdH -END PGP SIGNATURE- ___ Repoze-dev mailing list
Re: [Repoze-dev] [tg-trunk] [r.what] Backwards incompatibility in exchange for better context sensitivity?
On Mon, Jan 26, 2009 at 1:36 PM, Gustavo Narea m...@gustavonarea.net wrote: Hello, everybody. Florent and I have been discussing about context-sensitivity in repoze.what-1.0 predicates and there's a good enhancement that may be applied but will break backwards compatibility, and I won't break backwards incompatibility unless you want it. If you have repoze.what predicates this would affect you, so please read on. Right now repoze.what predicates are context-sensitive because they are evaluated with the WSGI environment. *But* if you have predicates that depend on POST/GET variables, then you have to use Paste to extract the variables you need from the WSGI environment. This is, GET/POST variables are used a lot in context-sensitivity authorization but they're not at hand (you need to write a little more code to get them). So, there's a proposed solution which would make the Predicate.evaluate(environ, credentials) method receive one more argument: The GET and POST variables. So its signature would end up as: evaluate(environ, credentials, variables) (where ``variables`` is a dict, and ``variables['post']`` and ``variables['get']`` contain the POST and GET variables respectively) But if I implement it, then your custom predicates (if any) will break. I think it's a good compromise because: 1.- If your predicates still use the ._eval_with_environ() method then you'll have to switch to .evaluate() the sooner or later anyway because it's deprecated (but still supported). 2.- Upgrading is easy: Just add the variables argument to your .evaluate() method. sounds interesting. Just a though can't we make it so that. evaluate(environ, credentials, variables=None) if variables: new stuff else: warn.warning(...) old behaviour Won't this keep backward compatibility and still allow the specific predicates to work? ___ Repoze-dev mailing list Repoze-dev@lists.repoze.org http://lists.repoze.org/listinfo/repoze-dev