summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris McDonough <chrism@agendaless.com>2009-07-01 08:13:25 +0000
committerChris McDonough <chrism@agendaless.com>2009-07-01 08:13:25 +0000
commit0688dad3e51361e3274650f39897100063f89459 (patch)
tree585ba59c6ddef0aef171116eb682a0a64220b756
parentdd7614a8e486735b7106331ca6b86229115de249 (diff)
downloadpyramid-0688dad3e51361e3274650f39897100063f89459.tar.gz
pyramid-0688dad3e51361e3274650f39897100063f89459.tar.bz2
pyramid-0688dad3e51361e3274650f39897100063f89459.zip
- Deprecate the ``authentication_policy`` and ``authorization_policy``
arguments to ``repoze.bfg.router.make_app``. Instead, developers should use the various authentication policy ZCML directives (``repozewho1authenticationpolicy``, ``remoteuserauthenticationpolicy`` and ``authtktauthenticationpolicy``) and the `aclauthorizationpolicy`` authorization policy directive as described in the changes to the "Security" narrative documentation chapter and the wiki tutorials.
-rw-r--r--CHANGES.txt9
-rw-r--r--docs/api/authentication.rst16
-rw-r--r--docs/api/authorization.rst11
-rw-r--r--docs/index.rst2
-rw-r--r--docs/narr/security.rst275
-rw-r--r--docs/tutorials/bfgwiki/authorization.rst72
-rw-r--r--docs/tutorials/bfgwiki/src/authorization/tutorial/configure.zcml6
-rw-r--r--docs/tutorials/bfgwiki/src/authorization/tutorial/run.py15
-rw-r--r--docs/tutorials/bfgwiki/src/authorization/tutorial/security.py8
-rw-r--r--docs/tutorials/bfgwiki2/authorization.rst82
-rw-r--r--docs/tutorials/bfgwiki2/src/authorization/tutorial/configure.zcml6
-rw-r--r--docs/tutorials/bfgwiki2/src/authorization/tutorial/run.py14
-rw-r--r--docs/tutorials/bfgwiki2/src/authorization/tutorial/security.py8
-rw-r--r--repoze/bfg/router.py33
-rw-r--r--repoze/bfg/tests/test_router.py15
15 files changed, 367 insertions, 205 deletions
diff --git a/CHANGES.txt b/CHANGES.txt
index d590f63eb..bdaf17545 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,6 +1,15 @@
Next release
============
+- Deprecate the ``authentication_policy`` and ``authorization_policy``
+ arguments to ``repoze.bfg.router.make_app``. Instead, developers
+ should use the various authentication policy ZCML directives
+ (``repozewho1authenticationpolicy``,
+ ``remoteuserauthenticationpolicy`` and
+ ``authtktauthenticationpolicy``) and the `aclauthorizationpolicy``
+ authorization policy directive as described in the changes to the
+ "Security" narrative documentation chapter and the wiki tutorials.
+
- Add three new ZCML directives which configure authentication
policies:
diff --git a/docs/api/authentication.rst b/docs/api/authentication.rst
deleted file mode 100644
index 6514de510..000000000
--- a/docs/api/authentication.rst
+++ /dev/null
@@ -1,16 +0,0 @@
-:mod:`repoze.bfg.authentication`
-================================
-
-.. automodule:: repoze.bfg.authentication
-
-.. _authentication_policies_api_section:
-
-Authentication Policies
-~~~~~~~~~~~~~~~~~~~~~~~
-
-.. autoclass:: AuthTktAuthenticationPolicy
-
-.. autoclass:: RemoteUserAuthenticationPolicy
-
-.. autoclass:: RepozeWho1AuthenticationPolicy
-
diff --git a/docs/api/authorization.rst b/docs/api/authorization.rst
deleted file mode 100644
index e44b1e293..000000000
--- a/docs/api/authorization.rst
+++ /dev/null
@@ -1,11 +0,0 @@
-:mod:`repoze.bfg.authorization`
-===============================
-
-.. automodule:: repoze.bfg.authorization
-
-.. _authorization_policies_api_section:
-
-Authorization Policies
-~~~~~~~~~~~~~~~~~~~~~~
-
-.. autoclass:: ACLAuthorizationPolicy
diff --git a/docs/index.rst b/docs/index.rst
index 7691e2400..41d3409b3 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -52,8 +52,6 @@ Per-module :mod:`repoze.bfg` API documentation.
.. toctree::
:maxdepth: 2
- api/authentication
- api/authorization
api/events
api/interfaces
api/location
diff --git a/docs/narr/security.rst b/docs/narr/security.rst
index bf60f10b0..e86451570 100644
--- a/docs/narr/security.rst
+++ b/docs/narr/security.rst
@@ -8,9 +8,8 @@ system that prevents a :term:`view` from being invoked when the user
represented by credentials in the :term:`request` does not have an
appropriate level of access in a specific context.
-Authorization is enabled by modifying your application's invocation of
-``repoze.bfg.router.make_app``, often located in the ``run.py`` module
-of a :mod:`repoze.bfg` application.
+Authorization is enabled by modifying your :term:`application
+registry` (aka "configure.zcml").
Enabling an Authorization Policy
--------------------------------
@@ -18,58 +17,50 @@ Enabling an Authorization Policy
By default, :mod:`repoze.bfg` enables no authorization policy. All
views are accessible by completely anonymous users.
-However, if you modify how your application calls to
-``repoze.bfg.router.make_app`` (usually found within the ``run.py``
-module in your application), you can enable an authorization policy.
+However, if you modify the :term:`application registry` file in your
+application's package (usually named ``configure.zcml``), you can
+enable an authorization policy.
-You must enable a a :term:`authentication policy` in order to enable
-the default authorization policy (this is because authorization, in
+You must also enable a a :term:`authentication policy` in order to
+enable the an authorization policy (this is because authorization, in
general, depends upon authentication).
-For example, to enable a policy which compares the ``REMOTE_USER``
-variable passed in the request's environment (as the sole
-:term:`principal`) against the principals present in any :term:`ACL`
-found in model data when attempting to call some :term:`view`, modify
-your ``run.py`` to look something like this:
+For example, to enable a policy which compares the value of an "auth
+ticket" cookie passed in the request's environment which contains a
+reference to a single :term:`principal` against the principals present
+in any :term:`ACL` found in model data when attempting to call some
+:term:`view`, modify your ``configure.zcml`` to look something like
+this:
-.. code-block:: python
+.. code-block:: xml
:linenos:
- from repoze.bfg.router import make_app
- from repoze.bfg.authentication import RemoteUserAuthenticationPolicy
-
- def app(global_config, **kw):
- """ This function returns a repoze.bfg.router.Router object. It
- is usually called by the PasteDeploy framework during ``paster
- serve``"""
- # paster app config callback
- from myproject.models import get_root
- import myproject
- policy = RemoteUserAuthenticationPolicy()
- return make_app(get_root, myproject, authentication_policy=policy,
- options=kw)
-
-This injects an instance of the
-``repoze.bfg.authentication.RemoteUserAuthenticationPolicy`` as the
-:term:`authentication policy` used by this application. It is
-possible to use a different authentication policy. :mod:`repoze.bfg`
-ships with a few prechewed authentication policies that should prove
-useful (see :ref:`authentication_policies_api_section`). It is also
-possible to construct your own authentication policy: see
-:ref:`creating_an_authentication_policy`.
-
-When you pass any ``authentication_policy`` argument to the
-``make_app`` function, and you don't also pass an
-``authorization_policy`` argument you are instructing BFG to use the
-*default* :term:`authorization policy`. The default authorization
-policy compares :term:`ACL` information attached to :term:`context`
-objects against the information rovided by the authentication policy.
-See :ref:`authorization_policies_api_section` for the details of the
-default authorization policy.
-
-.. note:: It's not common, but it is also possible for a developer to
- change the :term:`authorization policy` used by a :mod:`repoze.bfg`
- application. See :ref:`creating_an_authorization_policy`.
+ <configure xmlns="http://namespaces.repoze.org/bfg">
+
+ <!-- views and other directives before this... -->
+
+ <authtktauthenticationpolicy
+ secret="iamsosecret"/>
+
+ <aclauthorizationpolicy/>
+
+ </configure>
+
+"Under the hood", these statements cause an instance of the class
+``repoze.bfg.authentication.AuthTktAuthenticationPolicy`` to be
+injected as the :term:`authentication policy` used by this application
+and an instance of the class
+``repoze.bfg.authorization.ACLAuthorizationPolicy`` to be injected as
+the :term:`authorization policy` used by this application.
+
+:mod:`repoze.bfg` ships with a few prechewed authentication and
+authorization policies that should prove useful. See
+:ref:`authentication_policies_directives_section` and
+:ref:`authorization_policies_directives_section` for more information.
+
+It is also possible to construct your own custom authentication policy
+or authorization policy: see :ref:`creating_an_authentication_policy`
+and :ref:`creating_an_authorization_policy`.
Protecting Views with Permissions
---------------------------------
@@ -210,10 +201,11 @@ ACE, as below.
A principal is usually a user id, however it also may be a group id if
your authentication system provides group information and the
effective :term:`authentication policy` policy is written to respect
-group information. The ``RepozeWho1AuthenicationPolicy``
-authentication policy that comes with :mod:`repoze.bfg` respects group
-information (see the :mod:`repoze.bfg.authentication` API docs for
-more info on authentication policies).
+group information. For example, the ``RepozeWho1AuthenicationPolicy``
+enabled by the ``repozewho1authenticationpolicy`` ZCML directive
+respects group information if you configure it with a ``callback``.
+See :ref:`authentication_policies_directives_section` for more
+information about the ``callback`` attribute.
Each tuple within an ACL structure is known as a :term:`ACE`, which
stands for "access control entry". For example, in the above ACL,
@@ -391,17 +383,161 @@ indicating why permission was denied or allowed. Introspecting this
information in the debugger or via print statements when a
``has_permission`` fails is often useful.
+.. _authentication_policies_directives_section:
+
+Built-In Authentication Policy Directives
+-----------------------------------------
+
+:mod:`repoze.who` ships with a few "prechewed" authentication policy
+implementations that you can make use of within your application.
+
+``repozewho1authenticationpolicy``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When this directive is used, authentication information is obtained
+from a ``repoze.who.identity`` key in the WSGI environment, assumed to
+be set by :term:`repoze.who` middleware.
+
+An example of its usage, with all attributes fully expanded:
+
+.. code-block:: xml
+ :linenos:
+
+ <repozewho1authenticationpolicy
+ identifier_name="auth_tkt"
+ callback=".somemodule.somefunc"
+ />
+
+The ``identifier_name`` controls the name used to look up the
+:term:`repoze.who` "identifier" plugin within
+``environ['repoze.who.plugins']`` which is used by this policy to
+"remember" and "forget" credentials. It defaults to ``auth_tkt``.
+
+The ``callback`` is a Python dotted name to a function passed the
+repoze.who identity and the request as positional arguments. The
+callback is expected to return None if the user represented by the
+identity doesn't exist or a sequence of group identifiers (possibly
+empty) if the user does exist. If ``callback`` is None, the userid
+will be assumed to exist with no groups. It defaults to ``None``.
+
+``remoteuserauthenticationpolicy``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When this directive is used, authentication information is obtained
+from a ``REMOTE_USER`` key in the WSGI environment, assumed to
+be set by a WSGI server or an upstream middleware component.
+
+An example of its usage, with all attributes fully expanded:
+
+.. code-block:: xml
+ :linenos:
+
+ <remoteuserauthenticationpolicy
+ environ_key="REMOTE_USER"
+ callback=".somemodule.somefunc"
+ />
+
+The ``environ_key`` is the name that will be used to obtain the remote
+user value from the WSGI environment. It defaults to ``REMOTE_USER``.
+
+The ``callback`` is a Python dotted name to a function passed the
+string representing the remote user and the request as positional
+arguments. The callback is expected to return None if the user
+represented by the string doesn't exist or a sequence of group
+identifiers (possibly empty) if the user does exist. If ``callback``
+is None, the userid will be assumed to exist with no groups. It
+defaults to ``None``.
+
+``authtktauthenticationpolicy``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When this directive is used, authentication information is obtained
+from an "auth ticket" cookie value, assumed to be set by a custom
+login form.
+
+An example of its usage, with all attributes fully expanded:
+
+.. code-block:: xml
+ :linenos:
+
+ <authtktauthenticationpolicy
+ secret="goshiamsosecret"
+ callback=".somemodule.somefunc"
+ cookie_name="mycookiename"
+ secure="false"
+ include_ip="false"
+ timeout="86400"
+ reissue_time="600"
+ />
+
+The ``secret`` is a string that will be used to encrypt the data
+stored by the cookie. It is required and has no default.
+
+The ``callback`` is a Python dotted name to a function passed the
+string representing the userid stored in the cookie and the request as
+positional arguments. The callback is expected to return None if the
+user represented by the string doesn't exist or a sequence of group
+identifiers (possibly empty) if the user does exist. If ``callback``
+is None, the userid will be assumed to exist with no groups. It
+defaults to ``None``.
+
+The ``cookie_name`` is the name used for the cookie that contains the
+user information. It defaults to ``repoze.bfg.auth_tkt``.
+
+``secure`` is a boolean value. If it's set to "true", the cookie will
+only be sent back by the browser over a secure (HTTPS) connection.
+It defauls to "false".
+
+``include_ip`` is a boolean value. If it's set to true, the
+requesting IP address is made part of the authentication data in the
+cookie; if the IP encoded in the cookie differs from the IP of the
+requesting user agent, the cookie is considered invalid. It defaults
+to "false".
+
+``timeout`` is an integer value. It represents the maximum age in
+seconds allowed for a cookie to live. If ``timeout`` is specified,
+you must also set ``reissue_time`` to a lower value. It defaults to
+``None``, meaning that the cookie will only live for the duration of
+the user's browser session.
+
+``reissue_time`` is an integer value. If ``reissue_time`` is
+specified, when we encounter a cookie that is older than the reissue
+time (in seconds), but younger that the ``timeout``, a new cookie will
+be issued. It defaults to ``None``, meaning that authentication
+cookies are never reissued.
+
+.. _authorization_policies_directives_section:
+
+Built-In Authorization Policy Directives
+----------------------------------------
+
+``aclauthorizationpolicy``
+
+When this directive is used, authorization information is obtained
+from :term:`ACL` objects attached to model instances.
+
+An example of its usage, with all attributes fully expanded:
+
+.. code-block:: xml
+ :linenos:
+
+ <aclauthorizationpolicy/>
+
+In other words, it has no configuration attributes; its existence in a
+``configure.zcml`` file enables it.
+
.. _creating_an_authentication_policy:
Creating Your Own Authentication Policy
---------------------------------------
:mod:`repoze.bfg` ships with a number of useful out-of-the-box
-security policies (see :ref:`authentication_policies_api_section`).
-However, creating your own authentication policy is often necessary
-when you want to control the "horizontal and vertical" of how your
-users authenticate. Doing so is matter of creating an instance of
-something that implements the following interface:
+security policies (see
+:ref:`authentication_policies_directives_section`). However, creating
+your own authentication policy is often necessary when you want to
+control the "horizontal and vertical" of how your users authenticate.
+Doing so is matter of creating an instance of something that
+implements the following interface:
.. code-block:: python
@@ -427,9 +563,13 @@ something that implements the following interface:
""" Return a set of headers suitable for 'forgetting' the
current user on subsequent requests. """
-Pass the object you create into the ``repoze.bfg.router.make_app``
-function as the ``authentication_policy`` argument at application
-startup time (usually within a ``run.py`` module).
+You will then need to create a ZCML directive which allows you to use
+the authentication policy within a ZCML file. See the
+``repoze.bfg.zcml`` module in the :mod:`repoze.bfg` source code for
+examples of how to create a directive. Authorization policy ZCML
+directives should use the ZCML discriminator value
+"authentication_policy" in their actions to allow for conflict
+detection.
.. _creating_an_authorization_policy:
@@ -465,9 +605,10 @@ that implements the following interface:
""" Return a set of principal identifiers allowed by the
permission """
-Pass the object you create into the ``repoze.bfg.router.make_app``
-function as the ``authorization_policy`` argument at application
-startup time (usually within a ``run.py`` module). You must also pass
-an ``authentication_policy`` if you pass an ``authorization_policy``.
-If you pass only an ``authorization_policy`` argument, an error will
-be raised at startup time.
+You will then need to create a ZCML directive which allows you to use
+the authorization policy within a ZCML file. See the
+``repoze.bfg.zcml`` module in the :mod:`repoze.bfg` source for
+examples of how to create a directive. Authorization policy ZCML
+directives should use the ZCML discriminator value
+"authorization_policy" in their actions to allow for conflict
+detection.
diff --git a/docs/tutorials/bfgwiki/authorization.rst b/docs/tutorials/bfgwiki/authorization.rst
index e493852ec..304a3964b 100644
--- a/docs/tutorials/bfgwiki/authorization.rst
+++ b/docs/tutorials/bfgwiki/authorization.rst
@@ -15,34 +15,42 @@ Configuring a ``repoze.bfg`` Authentication Policy
--------------------------------------------------
For any :mod:`repoze.bfg` application to perform authorization, we
-need to change our ``run.py`` module to add an :term:`authentication
-policy`. Adding an authentication policy actually causes the system
-to begin to use :term:`authorization`.
-
-Changing ``run.py``
-~~~~~~~~~~~~~~~~~~~
-
-Change your ``run.py`` module to import the
-``AuthTktAuthenticationPolicy`` from ``repoze.bfg.authentication``.
-Within the body of the ``make_app`` function, construct an instance of
-the policy, and pass it as the ``authentication_policy`` argument to
-the ``make_app`` function. The first positional argument of an
-``AuthTktAuthenticationPolicy`` is a secret used to encrypt cookie
-data. Its second argument ("callback") should be a callable that
-accepts a userid ana a request. If the userid exists in the system,
-the callback should return a sequence of group identifiers (or an
-empty sequence if the user isn't a member of any groups). If the
-userid *does not* exist in the system, the callback should return
-``None``. We'll use "dummy" data to represent user and groups
-sources. When we're done, your application's ``run.py`` will look
-like this.
-
-.. literalinclude:: src/authorization/tutorial/run.py
+need to add a ``secrity.py`` module and we'll need to change our
+:term:`application registry` to add an :term:`authentication policy`
+and a :term:`authorization policy`.
+
+Changing ``configure.zcml``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+We'll change our ``configure.zcml`` file to enable an
+``AuthTktAuthenticationPolicy`` and an ``ACLAuthorizationPolicy`` to
+enable declarative security checking. We'll also add a ``forbidden``
+stanza. This configures our login view to show up when BFG detects
+that a view invocation can not be authorized. When you're done, your
+``configure.zcml`` will look like so:
+
+.. literalinclude:: src/authorization/tutorial/configure.zcml
:linenos:
- :language: python
+ :language: xml
-BFG's ``make_app`` callable also can accept an authorization policy
-parameter. We don't need to specify one, we'll use the default.
+
+Adding ``security.py``
+~~~~~~~~~~~~~~~~~~~~~
+
+Add a ``security.py`` module within your package (in the same
+directory as "run.py", "views.py", etc) with the following content:
+The groupfinder defined here is an authorization policy "callback"; it
+is a be a callable that accepts a userid ana a request. If the userid
+exists in the system, the callback will return a sequence of group
+identifiers (or an empty sequence if the user isn't a member of any
+groups). If the userid *does not* exist in the system, the callback
+will return ``None``. We'll use "dummy" data to represent user and
+groups sources. When we're done, your application's ``security.py``
+will look like this.
+
+.. literalinclude:: src/authorization/tutorial/security.py
+ :linenos:
+ :language: python
Adding Login and Logout Views
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -112,18 +120,6 @@ class="main_content">`` div:
<span tal:condition="logged_in"><a href="${request.application_url}/logout">Logout</a></span>
-Changing ``configure.zcml``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Change your application's ``configure.zcml`` to add a ``forbidden``
-stanza. This configures our login view to show up when BFG detects
-that a view invocation can not be authorized. When you're done, your
-``configure.zcml`` will look like so:
-
-.. literalinclude:: src/authorization/tutorial/configure.zcml
- :linenos:
- :language: xml
-
Giving Our Root Model Object an ACL
-----------------------------------
diff --git a/docs/tutorials/bfgwiki/src/authorization/tutorial/configure.zcml b/docs/tutorials/bfgwiki/src/authorization/tutorial/configure.zcml
index d13d812a8..660181918 100644
--- a/docs/tutorials/bfgwiki/src/authorization/tutorial/configure.zcml
+++ b/docs/tutorials/bfgwiki/src/authorization/tutorial/configure.zcml
@@ -8,4 +8,10 @@
<forbidden
view=".login.login"/>
+ <authtktauthenticationpolicy
+ secret="sosecret"
+ />
+
+ <aclauthorizationpolicy/>
+
</configure>
diff --git a/docs/tutorials/bfgwiki/src/authorization/tutorial/run.py b/docs/tutorials/bfgwiki/src/authorization/tutorial/run.py
index 32faa5899..ebe114c6f 100644
--- a/docs/tutorials/bfgwiki/src/authorization/tutorial/run.py
+++ b/docs/tutorials/bfgwiki/src/authorization/tutorial/run.py
@@ -1,5 +1,4 @@
from repoze.bfg.router import make_app
-from repoze.bfg.authentication import AuthTktAuthenticationPolicy
from repoze.zodbconn.finder import PersistentApplicationFinder
@@ -14,18 +13,6 @@ def app(global_config, **kw):
zodb_uri = kw.get('zodb_uri')
if zodb_uri is None:
raise ValueError("No 'zodb_uri' in application configuration.")
-
- authpolicy = AuthTktAuthenticationPolicy('seekr!t', callback=groupfinder)
-
get_root = PersistentApplicationFinder(zodb_uri, appmaker)
- return make_app(get_root, tutorial, authentication_policy=authpolicy,
- options=kw)
-
-USERS = {'editor':'editor',
- 'viewer':'viewer'}
-GROUPS = {'editor':['group.editors']}
-
-def groupfinder(userid, request):
- if userid in USERS:
- return GROUPS.get(userid, [])
+ return make_app(get_root, tutorial, options=kw)
diff --git a/docs/tutorials/bfgwiki/src/authorization/tutorial/security.py b/docs/tutorials/bfgwiki/src/authorization/tutorial/security.py
new file mode 100644
index 000000000..791367183
--- /dev/null
+++ b/docs/tutorials/bfgwiki/src/authorization/tutorial/security.py
@@ -0,0 +1,8 @@
+USERS = {'editor':'editor',
+ 'viewer':'viewer'}
+GROUPS = {'editor':['group.editors']}
+
+def groupfinder(userid, request):
+ if userid in USERS:
+ return GROUPS.get(userid, [])
+
diff --git a/docs/tutorials/bfgwiki2/authorization.rst b/docs/tutorials/bfgwiki2/authorization.rst
index f3f5a6f95..d95f54127 100644
--- a/docs/tutorials/bfgwiki2/authorization.rst
+++ b/docs/tutorials/bfgwiki2/authorization.rst
@@ -61,39 +61,52 @@ Configuring a ``repoze.bfg`` Authentication Policy
--------------------------------------------------
For any :mod:`repoze.bfg` application to perform authorization, we
-need to change our ``run.py`` module to add an :term:`authentication
-policy`. Adding an authentication policy actually causes the system
-to begin to use :term:`authorization`.
+need to add a ``secrity.py`` module and we'll need to change our
+:term:`application registry` to add an :term:`authentication policy`
+and a :term:`authorization policy`.
Changing ``run.py``
~~~~~~~~~~~~~~~~~~~
-Change your ``run.py`` module to import the
-``AuthTktAuthenticationPolicy`` from ``repoze.bfg.authentication``.
-Within the body of the ``make_app`` function, construct an instance of
-the policy, and pass it as the ``authentication_policy`` argument to
-the ``make_app`` function. The first positional argument of an
-``AuthTktAuthenticationPolicy`` is a secret used to encrypt cookie
-data. Its second argument ("callback") should be a callable that
-accepts a userid (usually a string) and a request object. If the
-userid exists in the system, the callback should return a sequence of
-group identifiers (or an empty sequence if the user isn't a member of
-any groups). If the userid *does not* exist in the system, the
-callback should return ``None``. We'll use "dummy" data to represent
-user and groups sources within ``run.py``. In a "real" application
-this information would almost certainly come from some database.
-
-We'll also use the opportunity to pass the ``RootFactory`` we created
-in the step above in as the first argument to ``make_app``. When
-we're done, your application's ``run.py`` will look like this.
+We'll use the opportunity to pass the ``RootFactory`` we created in
+the step above in as the first argument to ``make_app``. When we're
+done, your application's ``run.py`` will look like this.
.. literalinclude:: src/authorization/tutorial/run.py
:linenos:
:language: python
-BFG's ``make_app`` callable also can accept an "authorization_policy"
-parameter. We don't need to specify one, because we'll be using the
-default; it is the policy that scans the context for ACLs.
+Changing ``configure.zcml``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+We'' change our ``configure.zcml`` file to enable an
+``AuthTktAuthenticationPolicy`` and an ``ACLAuthorizationPolicy`` to
+enable declarative security checking. We'll also add a ``forbidden``
+stanza. This configures our login view to show up when BFG detects
+that a view invocation can not be authorized. When you're done, your
+``configure.zcml`` will look like so:
+
+.. literalinclude:: src/authorization/tutorial/configure.zcml
+ :linenos:
+ :language: xml
+
+Adding ``security.py``
+~~~~~~~~~~~~~~~~~~~~~
+
+Add a ``security.py`` module within your package (in the same
+directory as "run.py", "views.py", etc) with the following content:
+The groupfinder defined here is an authorization policy "callback"; it
+is a be a callable that accepts a userid ana a request. If the userid
+exists in the system, the callback will return a sequence of group
+identifiers (or an empty sequence if the user isn't a member of any
+groups). If the userid *does not* exist in the system, the callback
+will return ``None``. We'll use "dummy" data to represent user and
+groups sources. When we're done, your application's ``security.py``
+will look like this.
+
+.. literalinclude:: src/authorization/tutorial/security.py
+ :linenos:
+ :language: python
Adding Login and Logout Views
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -166,15 +179,18 @@ class="main_content">`` div:
Changing ``configure.zcml``
~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Change your application's ``configure.zcml`` to add a ``forbidden``
-stanza which points at our login view. This configures our newly
-created login view to show up when BFG detects that a view invocation
-can not be authorized. Also, add ``permission`` attributes with the
-value ``edit`` to the ``edit_page`` and ``add_page`` routes. This
-indicates that the views which these routes reference cannot be
-invoked without the authenticated user possessing the ``edit``
-permission with respect to the current context. When you're done,
-your ``configure.zcml`` will look like so:
+We'll change our ``configure.zcml`` file to enable an
+``AuthTktAuthenticationPolicy`` and an ``ACLAuthorizationPolicy`` to
+enable declarative security checking. We'll also change
+``configure.zcml`` to add a ``forbidden`` stanza which points at our
+login view. This configures our newly created login view to show up
+when BFG detects that a view invocation can not be authorized. Also,
+add ``permission`` attributes with the value ``edit`` to the
+``edit_page`` and ``add_page`` routes. This indicates that the views
+which these routes reference cannot be invoked without the
+authenticated user possessing the ``edit`` permission with respect to
+the current context. When you're done, your ``configure.zcml`` will
+look like so:
.. literalinclude:: src/authorization/tutorial/configure.zcml
:linenos:
diff --git a/docs/tutorials/bfgwiki2/src/authorization/tutorial/configure.zcml b/docs/tutorials/bfgwiki2/src/authorization/tutorial/configure.zcml
index 2904b0793..65b29019b 100644
--- a/docs/tutorials/bfgwiki2/src/authorization/tutorial/configure.zcml
+++ b/docs/tutorials/bfgwiki2/src/authorization/tutorial/configure.zcml
@@ -53,4 +53,10 @@
<forbidden
view=".login.login"/>
+ <authtktauthenticationpolicy
+ secret="sosecret"
+ />
+
+ <aclauthorizationpolicy/>
+
</configure>
diff --git a/docs/tutorials/bfgwiki2/src/authorization/tutorial/run.py b/docs/tutorials/bfgwiki2/src/authorization/tutorial/run.py
index 301f00312..a8ab1ce82 100644
--- a/docs/tutorials/bfgwiki2/src/authorization/tutorial/run.py
+++ b/docs/tutorials/bfgwiki2/src/authorization/tutorial/run.py
@@ -1,5 +1,4 @@
from repoze.bfg.router import make_app
-from repoze.bfg.authentication import AuthTktAuthenticationPolicy
import tutorial
from tutorial.models import DBSession
@@ -26,16 +25,5 @@ def app(global_config, **kw):
raise ValueError("No 'db_string' value in application configuration.")
initialize_sql(db_string)
- authpolicy = AuthTktAuthenticationPolicy('seekr!t', callback=groupfinder)
-
- return make_app(RootFactory, tutorial, authentication_policy=authpolicy,
- options=kw)
-
-USERS = {'editor':'editor',
- 'viewer':'viewer'}
-GROUPS = {'editor':['group.editors']}
-
-def groupfinder(userid, request):
- if userid in USERS:
- return GROUPS.get(userid, [])
+ return make_app(RootFactory, tutorial, options=kw)
diff --git a/docs/tutorials/bfgwiki2/src/authorization/tutorial/security.py b/docs/tutorials/bfgwiki2/src/authorization/tutorial/security.py
new file mode 100644
index 000000000..791367183
--- /dev/null
+++ b/docs/tutorials/bfgwiki2/src/authorization/tutorial/security.py
@@ -0,0 +1,8 @@
+USERS = {'editor':'editor',
+ 'viewer':'viewer'}
+GROUPS = {'editor':['group.editors']}
+
+def groupfinder(userid, request):
+ if userid in USERS:
+ return GROUPS.get(userid, [])
+
diff --git a/repoze/bfg/router.py b/repoze/bfg/router.py
index 0a863f93a..4eb0fed81 100644
--- a/repoze/bfg/router.py
+++ b/repoze/bfg/router.py
@@ -239,7 +239,10 @@ def make_app(root_factory, package=None, filename='configure.zcml',
authentication or authorization will be performed. Instead, BFG
will ignore any view permission assertions in your application and
imperative security checks performed by your application will
- always return ``True``.
+ always return ``True``. This argument is deprecated in
+ :mod:`repoze.bfg` 1.0; use a ZCML directive such as
+ ``authtktauthenticationpolicy`` instead, as documented in the
+ Security chapter of the :mod:`repoze.bfg` documentation.
``authorization_policy`` is an object that implements the
``repoze.bfg.interfaces.IAuthorizationPoicy`` interface
@@ -249,7 +252,10 @@ def make_app(root_factory, package=None, filename='configure.zcml',
authenticate that user. If the ``authentication_policy`` argument
is *not* ``None``, and the ``authorization_policy`` argument *is*
``None``, the authorization policy defaults to an authorization
- implementation that uses ACLs.
+ implementation that uses ACLs. This argument is deprecated in
+ :mod:`repoze.bfg` 1.0; use a ZCML directive such as
+ ``aclauthorizationpolicy`` instead, as documented in the Security
+ chapter of the :mod:`repoze.bfg` documentation.
``options``, if used, should be a dictionary containing runtime
options (e.g. the key/value pairs in an app section of a
@@ -272,12 +278,6 @@ def make_app(root_factory, package=None, filename='configure.zcml',
settings = Settings(get_options(options))
registry.registerUtility(settings, ISettings)
- if authentication_policy:
- registry.registerUtility(authentication_policy, IAuthenticationPolicy)
- if authorization_policy is None:
- authorization_policy = ACLAuthorizationPolicy()
- registry.registerUtility(authorization_policy, IAuthorizationPolicy)
-
if root_factory is None:
root_factory = DefaultRootFactory
@@ -287,6 +287,23 @@ def make_app(root_factory, package=None, filename='configure.zcml',
mapper = RoutesRootFactory(root_factory)
registry.registerUtility(mapper, IRoutesMapper)
+ if authentication_policy:
+ debug_logger.warn(
+ 'The "authentication_policy" and "authorization_policy" '
+ 'arguments to repoze.bfg.router.make_app have been deprecated '
+ 'in repoze.bfg version 1.0. Instead of using these arguments to '
+ 'configure an authorization/authentication policy pair, use '
+ 'a pair of ZCML directives (such as "authtktauthenticationpolicy" '
+ 'and "aclauthorizationpolicy" documented within the Security '
+ 'chapter in the BFG documentation. If you need to use a custom '
+ 'authentication or authorization policy, you should make a ZCML '
+ 'directive for it and use that directive within your '
+ 'application\'s ZCML')
+ registry.registerUtility(authentication_policy, IAuthenticationPolicy)
+ if authorization_policy is None:
+ authorization_policy = ACLAuthorizationPolicy()
+ registry.registerUtility(authorization_policy, IAuthorizationPolicy)
+
populateRegistry(registry, filename, package)
if mapper.has_routes():
diff --git a/repoze/bfg/tests/test_router.py b/repoze/bfg/tests/test_router.py
index 389920029..b0f75d899 100644
--- a/repoze/bfg/tests/test_router.py
+++ b/repoze/bfg/tests/test_router.py
@@ -780,8 +780,11 @@ class MakeAppTests(unittest.TestCase):
from repoze.bfg.interfaces import IAuthorizationPolicy
authzpolicy = DummyContext()
from repoze.bfg.tests import routesapp
- app = self._callFUT(None, routesapp, authorization_policy=authzpolicy)
+ logger = DummyLogger()
+ app = self._callFUT(None, routesapp, authorization_policy=authzpolicy,
+ debug_logger=logger)
self.failIf(app.registry.queryUtility(IAuthorizationPolicy))
+ self.assertEqual(logger.messages, [])
def test_authentication_policy_no_authorization_policy(self):
from repoze.bfg.interfaces import IAuthorizationPolicy
@@ -789,12 +792,15 @@ class MakeAppTests(unittest.TestCase):
from repoze.bfg.authorization import ACLAuthorizationPolicy
authnpolicy = DummyContext()
from repoze.bfg.tests import routesapp
- app = self._callFUT(None, routesapp, authentication_policy=authnpolicy)
+ logger = DummyLogger()
+ app = self._callFUT(None, routesapp, authentication_policy=authnpolicy,
+ debug_logger=logger)
self.assertEqual(app.registry.getUtility(IAuthenticationPolicy),
authnpolicy)
self.assertEqual(
app.registry.getUtility(IAuthorizationPolicy).__class__,
ACLAuthorizationPolicy)
+ self.assertEqual(len(logger.messages), 1) # deprecation warning
def test_authentication_policy_and_authorization_policy(self):
from repoze.bfg.interfaces import IAuthorizationPolicy
@@ -802,12 +808,15 @@ class MakeAppTests(unittest.TestCase):
authnpolicy = DummyContext()
authzpolicy = DummyContext()
from repoze.bfg.tests import routesapp
+ logger = DummyLogger()
app = self._callFUT(None, routesapp, authentication_policy=authnpolicy,
- authorization_policy = authzpolicy)
+ authorization_policy = authzpolicy,
+ debug_logger=logger)
self.assertEqual(app.registry.getUtility(IAuthenticationPolicy),
authnpolicy)
self.assertEqual(app.registry.getUtility(IAuthorizationPolicy),
authzpolicy)
+ self.assertEqual(len(logger.messages), 1) # deprecation warning
class TestDefaultForbiddenView(unittest.TestCase):
def _callFUT(self, context, request):