Merge branch 'master' of github.com:pecan/pecan

This commit is contained in:
Jeremy M. Jones
2011-09-02 11:32:29 -04:00
4 changed files with 74 additions and 46 deletions

View File

@@ -134,6 +134,8 @@ manner:
#. If the controller returns successfully, ``model.clear()`` is called.
Also note that there is a useful ``@after_commit`` decorator provided in :ref:`pecan_decorators`.
Splitting Reads and Writes
----------------
Employing the strategy above with ``TransactionHook`` makes it very simple to split database
@@ -141,4 +143,4 @@ reads and writes based upon HTTP methods (i.e., GET/HEAD requests are read-only
be routed to a read-only database slave, while POST/PUT/DELETE requests require writing, and
would always bind to a master database with read/write privileges). It's also very easy to extend
``TransactionHook`` or write your own hook implementation for more refined control over where and
when database bindings are called.
when database bindings are called.

View File

@@ -5,8 +5,8 @@ Routing
When a user requests a Pecan-powered page how does Pecan know which
controller to use? Pecan uses a method known as Object-dispatch to map a
HTTP request to a controller. Obejct-dispatch begins by splitting the
path into a list of components and then walking object path starting at
HTTP request to a controller. Object-dispatch begins by splitting the
path into a list of components and then walking an object path starting at
the root controller. Let's look at a simple store application:
::
@@ -51,7 +51,7 @@ example above, you may have noticed the ``expose`` decorator.
Routing Algorithm
-----------------
Sometimes, the standard object-dispatch routing isn't adquate to properly
Sometimes, the standard object-dispatch routing isn't adequate to properly
route a URL to a controller. Pecan provides several ways to short-circuit
the object-dispatch system to process URLs with more control, including the
``_lookup``, ``_default``, and ``_route`` special methods. Defining these
@@ -214,28 +214,28 @@ Helper Functions
----------------
Pecan also provides several useful helper functions. The ``redirect``
function allows you to issue internal or ``HTTP 302`` The ``redirect``
utility, along with several other useful helpers, are documented in
the :ref:`pecan_core`.
function allows you to issue internal or ``HTTP 302`` redirects.
The ``redirect`` utility, along with several other useful helpers,
are documented in :ref:`pecan_core`.
``@expose``
-----------
At its core, ``expose`` is how you tell Pecan which methods in a class
are controllers. ``expose`` accepts eight optional parameters some of
At its core, ``@expose`` is how you tell Pecan which methods in a class
are controllers. ``@expose`` accepts eight optional parameters some of
which can impact routing.
::
def expose(template = None,
expose(template = None,
content_type = 'text/html',
schema = None,
json_schema = None,
variable_decode = False,
error_handler = None,
htmlfill = None,
generic = False):
generic = False)
Let's look at an example using template and content_type
@@ -252,11 +252,11 @@ Let's look at an example using template and content_type
return {'msg': 'Hello!'}
You'll notice that we used three expose decorators. The first tells
Pecan to serialize ``dict`` using JSON serialization when the client
requests ``/hello.json``. The second tells the templating engine to use
``text_template.mako`` when the client request ``/hello.txt``. The third
tells Pecan to use the html_template.mako when the client requests
``/hello.html``. If the client requests ``/hello``, Pecan will use the
text/html template.
Pecan to serialize our response namespace using JSON serialization when
the client requests ``/hello.json``. The second tells the templating
engine to use ``text_template.mako`` when the client request ``/hello.txt``.
The third tells Pecan to use the html_template.mako when the client
requests ``/hello.html``. If the client requests ``/hello``, Pecan will
use the text/html template.
Please see :ref:`pecan_decorators` for more information on ``@expose``.

View File

@@ -1,22 +1,24 @@
.. _secure_controller:
Security and Authentication
=============
Pecan provides no out-of-the-box support for authentication, but it does give you the
necessary tools to handle authentication and authorization as you see fit.
===========================
Pecan provides no out-of-the-box support for authentication, but it does give
you the necessary tools to handle authentication and authorization as you see
fit.
In Pecan, you can wrap entire controller subtrees *or* individual method calls with
function calls to determine access and secure portions of your application.
In Pecan, you can wrap entire controller subtrees *or* individual method calls
with function calls to determine access and secure portions of your
application.
Pecan's ``secure`` method secures a method or class depending on invocation.
Pecan's ``secure`` decorator secures a method or class depending on invocation.
To decorate a method, use one argument::
@secure('<check_permissions_method>')
secure('<check_permissions_method>')
To secure a class, invoke with two arguments::
secure(<object instance>, '<check_permissions_method>')
secure(object_instance, '<check_permissions_method>')
::
@@ -57,9 +59,11 @@ To secure a class, invoke with two arguments::
highly_classified = secure(HighlyClassifiedController(), 'check_permissions')
unclassified = UnclassifiedController()
Alternatively, the same functionality can also be accomplished by subclassing Pecan's ``SecureController`` class.
Implementations of ``SecureController`` should extend the ``check_permissions`` classmethod to return a ``True``
or ``False`` value (depending on whether or not the user has permissions to the controller branch)::
Alternatively, the same functionality can also be accomplished by subclassing
Pecan's ``SecureController`` class. Implementations of ``SecureController``
should extend the ``check_permissions`` classmethod to return a ``True``
or ``False`` value (depending on whether or not the user has permissions to
the controller branch)::
from pecan import expose
from pecan.secure import SecureController, unlocked
@@ -97,19 +101,31 @@ or ``False`` value (depending on whether or not the user has permissions to the
highly_classified = HighlyClassifiedController()
unclassified = unlocked(UnclassifiedController())
Also note the use of the ``@unlocked`` decorator in the above example, which
can be used similarly to explicitly unlock a controller for public access
without any security checks.
Writing Authentication/Authorization Methods
----------------
The ``check_permissions`` method should be used to determine user authentication and authorization. The
code you implement here could range from simple session assertions (the existing user is authenticated
as an administrator) to connecting to an LDAP service.
--------------------------------------------
The ``check_permissions`` method should be used to determine user
authentication and authorization. The code you implement here could range
from simple session assertions (the existing user is authenticated as an
administrator) to connecting to an LDAP service.
More on ``secure``
----------------
The ``secure`` method has several advanced uses that allow you to create robust security policies for your application.
------------------
The ``secure`` method has several advanced uses that allow you to create
robust security policies for your application.
First, you can pass via a string the name of either a classmethod or an instance method of the controller to use as the
``check_permission`` method. Instance methods are particularly useful if you wish to authorize access to attributes
of a particular model instance. Consider the following example of a basic virtual filesystem::
First, you can pass via a string the name of either a classmethod or an
instance method of the controller to use as the ``check_permission`` method.
Instance methods are particularly useful if you wish to authorize access to
attributes of a particular model instance. Consider the following example
of a basic virtual filesystem::
from pecan import expose
from pecan.secure import secure
@@ -143,7 +159,10 @@ of a particular model instance. Consider the following example of a basic virtu
return FileController(name), remainder
The ``secure`` method also accepts a function instead of a string. When passing a function, make sure that the function is imported from another file or defined in the same file before the class definition -- otherwise you will likely get error during module import. ::
The ``secure`` method also accepts a function instead of a string. When
passing a function, make sure that the function is imported from another
file or defined in the same file before the class definition -- otherwise
you will likely get error during module import. ::
from pecan import expose
from pecan.secure import secure
@@ -157,7 +176,11 @@ The ``secure`` method also accepts a function instead of a string. When passing
return 'Logged in'
You can also use the ``secure`` method to change the behavior of a SecureController. Decorating a method or wrapping a subcontroller tells Pecan to use another security function other than the default controller method. This is useful for situations where you want a different level or type of security.
You can also use the ``secure`` method to change the behavior of a
``SecureController``. Decorating a method or wrapping a subcontroller tells
Pecan to use another security function other than the default controller
method. This is useful for situations where you want a different level or
type of security.
::
@@ -184,11 +207,18 @@ You can also use the ``secure`` method to change the behavior of a SecureControl
api = secure(ApiController(), 'check_api_permissions')
In the example above, pecan will *only* call ``admin_user`` when a request is made for ``/api/``.
In the example above, pecan will *only* call ``admin_user`` when a request is
made for ``/api/``.
Multiple Secure Controllers
---------------------------
Pecan allows you to have nested secure controllers. In the example below, when a request is made for ``/admin/index/``, Pecan first calls ``check_permissions`` on the RootController and then calls ``check_permissions`` on the AdminController. The ability to nest ``SsecureController`` instances allows you to protect controllers with an increasing level of protection. ::
Pecan allows you to have nested secure controllers. In the example below, when
a request is made for ``/admin/index/``, Pecan first calls
``check_permissions`` on the RootController and then calls
``check_permissions`` on the AdminController. The ability to nest
``SecureController`` instances allows you to protect controllers with an
increasing level of protection. ::
from pecan import expose
from pecan.secure import SecureController

View File

@@ -2,15 +2,11 @@ from inspect import getargspec, getmembers, isclass, ismethod
from util import _cfg
__all__ = [
'expose', 'transactional', 'accept_noncanonical'
'expose', 'transactional', 'accept_noncanonical', 'after_commit'
]
def when_for(controller):
'''
'''
def when(method=None, **kw):
def decorate(f):
expose(**kw)(f)