From b0a3958409901788da67ad5bf9f8ff4e664c6516 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sat, 30 May 2009 06:54:31 +0000 Subject: Modify tutorial for a6. --- docs/tutorials/bfgwiki/authorization.rst | 235 ++++++++------------- docs/tutorials/bfgwiki/src/authorization/setup.py | 1 - .../bfgwiki/src/authorization/tutorial.ini | 5 - .../src/authorization/tutorial/configure.zcml | 3 + .../bfgwiki/src/authorization/tutorial/login.py | 43 ++++ .../bfgwiki/src/authorization/tutorial/run.py | 13 +- .../src/authorization/tutorial/templates/login.pt | 32 +++ .../src/authorization/tutorial/templates/view.pt | 2 +- .../bfgwiki/src/authorization/tutorial/views.py | 18 +- docs/tutorials/bfgwiki/src/authorization/who.ini | 40 ---- .../bfgwiki/src/authorization/wiki.passwd | 1 - 11 files changed, 179 insertions(+), 214 deletions(-) create mode 100644 docs/tutorials/bfgwiki/src/authorization/tutorial/login.py create mode 100644 docs/tutorials/bfgwiki/src/authorization/tutorial/templates/login.pt delete mode 100644 docs/tutorials/bfgwiki/src/authorization/who.ini delete mode 100644 docs/tutorials/bfgwiki/src/authorization/wiki.passwd (limited to 'docs/tutorials') diff --git a/docs/tutorials/bfgwiki/authorization.rst b/docs/tutorials/bfgwiki/authorization.rst index 3b5c2e3de..f52312c14 100644 --- a/docs/tutorials/bfgwiki/authorization.rst +++ b/docs/tutorials/bfgwiki/authorization.rst @@ -7,133 +7,121 @@ view, edit, and add pages to our wiki. For purposes of demonstration we'll change our application to allow people whom possess a specific username (`editor`) to add and edit wiki pages but we'll continue allowing anyone with access to the server to view pages. +:mod:`repoze.bfg` provides facilities for *authorization* and +*authentication*. We'll make use of both features to provide security +to our application. -:mod:`repoze.bfg` provides a facility for *authorization*, but it -relies on "upstream" software to provide *authentication* information. -We're going to use a package named ``repoze.who`` to our setup, and -we'll rely on it to give us authentication information. - -Adding a Dependency on ``repoze.who`` to Our ``setup.py`` File --------------------------------------------------------------- - -We need to change our ``setup.py`` file, adding a dependency on the -``repoze.who`` package. The ``repoze.who`` package provides a -mechanism for providing *authentication* data via :term:`WSGI` -middleware. We'll add the ``repoze.who`` package to our ``requires`` -list. +Configuring a ``repoze.bfg`` Authentication Policy +-------------------------------------------------- -The resulting setup.py file: +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. 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/setup.py +.. literalinclude:: src/authorization/tutorial/run.py :linenos: :language: python -Changing our ``tutorial.ini`` file to Include the ``repoze.who`` Middleware ---------------------------------------------------------------------------- - -In order to make use of the ``repoze.who`` middleware which provides -authentication services, we need to wire it into our ``tutorial.ini`` -file. We'll add a ``[filter:who]`` section to our ``tutorial.ini`` -file and wire it into our pipeline. Our resulting ``tutorial.ini`` -file will look like so: +BFG's ``make_app`` callable also can accept an authorization policy +parameter. We don't need to specify one, we'll use the default. -.. literalinclude:: src/authorization/tutorial.ini - :linenos: - :language: ini +Adding Login and Logout Views +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Note that we added a ``who`` line to our pipeline. This refers to the -``[filter:who]`` section above it. The ``[filter:who]`` section has a -``use`` line that points at an egg entry point for configuring the -repoze.who middleware via a config file. The ``config_file`` line -points at an .ini config file named ``who.ini``. This file is assumed -to live in the same directory as the ``tutorial.ini`` file. We'll -need to create this file in order to get authentication working. +We'll add a ``login`` view which renders a login form and processes +the post from the login form, checking credentials. -Adding a ``who.ini`` File -------------------------- +We'll also add a ``logout`` view to our application and provide a link +to it. This view will clear the credentials of the logged in user and +redirect back to the front page. -We'll create a file in our package directory named ``who.ini``. It -will have the following contents. +We'll add a different file (for presentation convenience) to add login +and logout views. Add a file to your application in the same +directory as ``login.py`` with the following content: -.. literalinclude:: src/authorization/who.ini +.. literalinclude:: src/authorization/tutorial/login.py :linenos: - :language: ini + :language: python -The ``[general]``, ``[identifiers]``, ``[authenticators]``, and -``[challengers]`` section of this file are the meat of the -configuration in this file. +Changing Existing Views +~~~~~~~~~~~~~~~~~~~~~~~ -The ``[general]`` Section -~~~~~~~~~~~~~~~~~~~~~~~~~ +Then we need to change each opf our ``view_page``, ``edit_page`` and +``add_page`` views to pass a "logged in" parameter into its template. +We'll add something like this to each view body: -The ``[general]`` section configures the default "request classifier" -and "challenge decider". For the purposes of this tutorial, it is not -important that you understand these settings. +.. code-block:: python + :linenos: -The ``[identifiers]`` Section -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + logged_in = authenticated_user(context, request) -The ``[identifiers]`` section configures the identifier plugins that -will be used for this application. In our case, our identifiers are -both the ``form`` plugin (configured above the ``[identifiers]`` -section within ``[plugin:form]``) and the ``auth_tkt`` plugin -(configured above the ``[identifiers]`` section within -``[plugin:auth_tkt]``. The ``form`` identifier will only be used when -the request is a "browser request" (for example, it *won't* be used -when the request is an XML-RPC request). +We'll then change the return value of ``render_template_to_response`` +to pass the `resulting `logged_in`` value to the template, e.g.: -The ``[authenticators]`` Section +.. code-block:: python + :linenos: + + return render_template_to_response('templates/view.pt', + request = request, + page = context, + content = content, + logged_in = logged_in, + edit_url = edit_url) + +Adding the ``login.pt`` Template ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The ``[authenticators]`` section configures the "authenticator" -plugins that will be used in our setup. An authenticator plugin is -one which checks a username and password provided by a user against a -database of valid username/password combinations. We'll use an -htpasswd file as this database. Since the ``htpasswd`` plugin -requires a file, we'll need to add a ``wiki.passwd`` file to our -``tutorial`` package with these contents: +Add a ``login.pt`` template to your templates directory. It's +referred to within the login view we just added to ``login.py``. -.. literalinclude:: src/authorization/wiki.passwd +.. literalinclude:: src/authorization/tutorial/templates/login.pt :linenos: - :language: ini + :language: xml -The ``[challengers]`` Section -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Change ``view.pt`` and ``edit.pt`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The ``[challengers]`` section configures a "challenger" which is a -``repoze.who`` plugin which displays a login form. We'll use the -standard ``repoze.who.plugins.form`` plugin for this, configured -within the ``[plugin:form]`` section of the file. +We'll also need to change our ``edit.pt`` and ``view.pt`` templates to +display a "Logout" link if someone is logged in. This link will +invoke the logout view. -The ``[plugin:*]`` Sections ---------------------------- +To do so we'll add this to both templates within the ``
`` div: -The ``[plugin:*]`` sections of the configuration file configure -individual plugins used by the more general configuration sections -(``[identifiers]``, ``[authenticators]``, ``[challengers]``). The -``auth_tkt`` plugin is an identifier plugin which obtains credentials -from a cookie, the ``form`` plugin is an identifier and challenger -plugin which obtains credentials from a form post, the ``htpasswd`` -plugin is an authenticator plugin which checks credentials against -valid usernames and files specified in an htpasswd file. +.. code-block:: xml + :linenos: -Configuring a ``repoze.bfg`` Authentication Policy --------------------------------------------------- + Logout -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 causes the system to use -authorization. +Changing ``configure.zcml`` +~~~~~~~~~~~~~~~~~~~~~~~~~ -Change your run.py to import the ``RepozeWho1AuthenticationPolicy`` -from ``repoze.who.authentication``, construct an instance of the -policy, and pass it as the ``authentication_policy`` argument to the -``make_app`` function. When you're done, your application's -``run.py`` will look like this. +Change your application's ``configure.zcml`` to add a slightly +inscrutable ``utility`` 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/run.py +.. literalinclude:: src/authorization/tutorial/configure.zcml :linenos: - :language: python + :language: xml Giving Our Root Model Object an ACL ----------------------------------- @@ -248,61 +236,6 @@ our application in a browser. The views we'll try are as follows: username ``editor``, password ``editor`` will show the edit page form being displayed. -Add A Logout View -------------------- - -We'll add a ``logout`` view to our application and provide a link to -it. This view will clear the credentials of the logged in user and -redirect back to the front page. The logout view will look someting -like this: - -.. code-block:: python - :linenos: - - @bfg_view(for_=Wiki, name='logout') - def logout(context, request): - identity = request.environ.get('repoze.who.identity') - headers = [] - if identity is not None: - auth_tkt = request.environ['repoze.who.plugins']['auth_tkt'] - headers = auth_tkt.forget(request.environ, identity) - return HTTPFound(location = model_url(context, request), - headers = headers) - - -We'll also change our ``edit.pt`` template to display a "Logout" link -if someone is logged in. This link will invoke the logout view. - -To do so we'll add this to both templates within the ``
`` div: - -.. code-block:: xml - :linenos: - - Logout - -Then we need to change each opf our ``view_page``, ``edit_page`` and -``add_page`` views to pass a "logged in" parameter into its template. -We'll add something like this to each view body: - -.. code-block:: python - :linenos: - - logged_in = 'repoze.who.identity' in request.environ - -We'll then change the return value of ``render_template_to_response`` -to pass the `resulting `logged_in`` value to the template, e.g.: - -.. code-block:: python - :linenos: - - return render_template_to_response('templates/view.pt', - request = request, - page = context, - content = content, - logged_in = logged_in, - edit_url = edit_url) - Seeing Our Changes To ``views.py`` and our Templates ---------------------------------------------------- diff --git a/docs/tutorials/bfgwiki/src/authorization/setup.py b/docs/tutorials/bfgwiki/src/authorization/setup.py index 6d300b473..b289ca8b0 100644 --- a/docs/tutorials/bfgwiki/src/authorization/setup.py +++ b/docs/tutorials/bfgwiki/src/authorization/setup.py @@ -15,7 +15,6 @@ requires = [ 'ZODB3', 'repoze.zodbconn', 'repoze.tm', - 'repoze.who', ] setup(name='tutorial', diff --git a/docs/tutorials/bfgwiki/src/authorization/tutorial.ini b/docs/tutorials/bfgwiki/src/authorization/tutorial.ini index d30aa2672..181682585 100644 --- a/docs/tutorials/bfgwiki/src/authorization/tutorial.ini +++ b/docs/tutorials/bfgwiki/src/authorization/tutorial.ini @@ -8,16 +8,11 @@ debug_authorization = false debug_notfound = false zodb_uri = file://%(here)s/Data.fs?connection_cache_size=20000 -[filter:who] -use = egg:repoze.who#config -config_file = %(here)s/who.ini - [pipeline:main] pipeline = egg:repoze.zodbconn#closer egg:Paste#evalerror egg:repoze.tm#tm - who zodb [server:main] diff --git a/docs/tutorials/bfgwiki/src/authorization/tutorial/configure.zcml b/docs/tutorials/bfgwiki/src/authorization/tutorial/configure.zcml index b1501597d..df11c18b1 100644 --- a/docs/tutorials/bfgwiki/src/authorization/tutorial/configure.zcml +++ b/docs/tutorials/bfgwiki/src/authorization/tutorial/configure.zcml @@ -5,4 +5,7 @@ + + diff --git a/docs/tutorials/bfgwiki/src/authorization/tutorial/login.py b/docs/tutorials/bfgwiki/src/authorization/tutorial/login.py new file mode 100644 index 000000000..c4c595e81 --- /dev/null +++ b/docs/tutorials/bfgwiki/src/authorization/tutorial/login.py @@ -0,0 +1,43 @@ +from webob.exc import HTTPFound + +from repoze.bfg.chameleon_zpt import render_template_to_response +from repoze.bfg.security import remember +from repoze.bfg.security import forget +from repoze.bfg.view import bfg_view +from repoze.bfg.url import model_url + +from tutorial.models import Wiki +from tutorial.run import USERS + +@bfg_view(for_=Wiki, name='login') +def login(context, request): + referrer = request.environ.get('HTTP_REFERER', '/') + came_from = request.params.get('came_from', referrer) + message = '' + login = '' + password = '' + if 'form.submitted' in request.params: + login = request.params['login'] + password = request.params['password'] + if USERS.get(login) == password: + headers = remember(context, request, login) + return HTTPFound(location = came_from, + headers = headers) + message = 'Failed login' + + return render_template_to_response( + 'templates/login.pt', + message = message, + url = request.application_url + '/login', + came_from = came_from, + login = login, + password = password, + request =request, + ) + +@bfg_view(for_=Wiki, name='logout') +def logout(context, request): + headers = forget(context, request) + return HTTPFound(location = model_url(context, request), + headers = headers) + diff --git a/docs/tutorials/bfgwiki/src/authorization/tutorial/run.py b/docs/tutorials/bfgwiki/src/authorization/tutorial/run.py index 45920615f..a5d0cf39c 100644 --- a/docs/tutorials/bfgwiki/src/authorization/tutorial/run.py +++ b/docs/tutorials/bfgwiki/src/authorization/tutorial/run.py @@ -1,5 +1,5 @@ from repoze.bfg.router import make_app -from repoze.bfg.authentication import RepozeWho1AuthenticationPolicy +from repoze.bfg.authentication import AuthTktAuthenticationPolicy from repoze.zodbconn.finder import PersistentApplicationFinder @@ -15,8 +15,17 @@ def app(global_config, **kw): if zodb_uri is None: raise ValueError("No 'zodb_uri' in application configuration.") - authpolicy = RepozeWho1AuthenticationPolicy() + 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): + if userid in USERS: + return GROUPS.get(userid, []) + diff --git a/docs/tutorials/bfgwiki/src/authorization/tutorial/templates/login.pt b/docs/tutorials/bfgwiki/src/authorization/tutorial/templates/login.pt new file mode 100644 index 000000000..a9e086461 --- /dev/null +++ b/docs/tutorials/bfgwiki/src/authorization/tutorial/templates/login.pt @@ -0,0 +1,32 @@ + + + + + + bfg tutorial wiki (based on TurboGears 20-Minute Wiki) + + + + + +

Log In

+ +
+ +
+
+ + +
+ +
+ +
+
+ + + diff --git a/docs/tutorials/bfgwiki/src/authorization/tutorial/templates/view.pt b/docs/tutorials/bfgwiki/src/authorization/tutorial/templates/view.pt index cae6940c2..3c5cc2a33 100644 --- a/docs/tutorials/bfgwiki/src/authorization/tutorial/templates/view.pt +++ b/docs/tutorials/bfgwiki/src/authorization/tutorial/templates/view.pt @@ -17,7 +17,7 @@
Viewing Page Name Goes Here
You can return to the FrontPage. - Logout +Logout
Page text goes here.
diff --git a/docs/tutorials/bfgwiki/src/authorization/tutorial/views.py b/docs/tutorials/bfgwiki/src/authorization/tutorial/views.py index 7beab58b0..1d3e57de3 100644 --- a/docs/tutorials/bfgwiki/src/authorization/tutorial/views.py +++ b/docs/tutorials/bfgwiki/src/authorization/tutorial/views.py @@ -4,6 +4,9 @@ import re from webob.exc import HTTPFound from repoze.bfg.url import model_url from repoze.bfg.chameleon_zpt import render_template_to_response + +from repoze.bfg.security import authenticated_userid + from repoze.bfg.view import static from repoze.bfg.view import bfg_view @@ -41,7 +44,7 @@ def view_page(context, request): content = wikiwords.sub(check, content) edit_url = model_url(context, request, 'edit_page') - logged_in = 'repoze.who.identity' in request.environ + logged_in = authenticated_userid(context, request) return render_template_to_response('templates/view.pt', request = request, @@ -88,15 +91,4 @@ def edit_page(context, request): save_url = model_url(context, request, 'edit_page') ) - - -@bfg_view(for_=Wiki, name='logout') -def logout(context, request): - identity = request.environ.get('repoze.who.identity') - headers = [] - if identity is not None: - auth_tkt = request.environ['repoze.who.plugins']['auth_tkt'] - headers = auth_tkt.forget(request.environ, identity) - return HTTPFound(location = model_url(context, request), - headers = headers) - + diff --git a/docs/tutorials/bfgwiki/src/authorization/who.ini b/docs/tutorials/bfgwiki/src/authorization/who.ini deleted file mode 100644 index 73d820b3d..000000000 --- a/docs/tutorials/bfgwiki/src/authorization/who.ini +++ /dev/null @@ -1,40 +0,0 @@ -[plugin:form] -# identification and challenge -use = repoze.who.plugins.form:make_plugin -login_form_qs = __do_login -rememberer_name = auth_tkt - -[plugin:auth_tkt] -# identification -use = repoze.who.plugins.auth_tkt:make_plugin -secret = s33kr1t -cookie_name = oatmeal -secure = False -include_ip = False - -[plugin:htpasswd] -# authentication -use = repoze.who.plugins.htpasswd:make_plugin -filename = %(here)s/wiki.passwd -check_fn = repoze.who.plugins.htpasswd:plain_check - -[general] -request_classifier = repoze.who.classifiers:default_request_classifier -challenge_decider = repoze.who.classifiers:default_challenge_decider - -[identifiers] -# plugin_name;classifier_name:.. or just plugin_name (good for any) -plugins = - form;browser - auth_tkt - -[authenticators] -# plugin_name;classifier_name.. or just plugin_name (good for any) -plugins = - htpasswd - -[challengers] -# plugin_name;classifier_name:.. or just plugin_name (good for any) -plugins = - form - diff --git a/docs/tutorials/bfgwiki/src/authorization/wiki.passwd b/docs/tutorials/bfgwiki/src/authorization/wiki.passwd deleted file mode 100644 index c9cd6fe83..000000000 --- a/docs/tutorials/bfgwiki/src/authorization/wiki.passwd +++ /dev/null @@ -1 +0,0 @@ -editor:editor -- cgit v1.2.3