diff --git a/docs/source/databases.rst b/docs/source/databases.rst index 47c1760..2dd6e89 100644 --- a/docs/source/databases.rst +++ b/docs/source/databases.rst @@ -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. \ No newline at end of file +when database bindings are called. diff --git a/docs/source/routing.rst b/docs/source/routing.rst index 11432bd..9b2081b 100644 --- a/docs/source/routing.rst +++ b/docs/source/routing.rst @@ -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``. diff --git a/docs/source/secure_controller.rst b/docs/source/secure_controller.rst index d0d7fd0..65709b5 100644 --- a/docs/source/secure_controller.rst +++ b/docs/source/secure_controller.rst @@ -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('') + secure('') To secure a class, invoke with two arguments:: - secure(, '') + secure(object_instance, '') :: @@ -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 diff --git a/pecan/decorators.py b/pecan/decorators.py index 113a67d..95e3cef 100644 --- a/pecan/decorators.py +++ b/pecan/decorators.py @@ -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)