Merge branch 'master' of github.com:pecan/pecan
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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``.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user