FASWho Plugin

Authors:Luke Macken Toshio Kuratomi
Date:3 September 2011

This plugin provides authentication to the Fedora Account System using the repoze.who WSGI middleware. It is designed for use with TurboGears2 but it may be used with any repoze.who using application. Like TurboGears Identity Provider 2, faswho has builtin CSRF protection. This protection is implemented as a second piece of middleware and may be used with other repoze.who authentication schemes.

Authenticating against FAS with TurboGears2

Setting up authentication against FAS in TurboGears2 is very easy. It requires one change to be made to app/config/app_cfg.py. This change will take care of registering faswho as the authentication provider, enabling CSRF protection, switching tg.url() to use fedora.ta2g.utils.url() instead, and allowing the _csrf_token parameter to be given to any URL.

Using CSRF middleware with other Auth Methods

This section needs to be made clearer so that apps like mirrormanager can be ported to use this.

Cross-site Request Forgery Protection.

http://en.wikipedia.org/wiki/Cross-site_request_forgery

Module author: John (J5) Palmieri <johnp@redhat.com>

Module author: Luke Macken <lmacken@redhat.com>

New in version 0.3.17.

class fedora.wsgi.csrf.CSRFProtectionMiddleware(application, csrf_token_id='_csrf_token', clear_env='repoze.who.identity repoze.what.credentials', token_env='CSRF_TOKEN', auth_state='CSRF_AUTH_STATE')

CSRF Protection WSGI Middleware.

A layer of WSGI middleware that is responsible for making sure authenticated requests originated from the user inside of the app’s domain and not a malicious website.

This middleware works with the repoze.who middleware, and requires that it is placed below repoze.who in the WSGI stack, since it relies upon repoze.who.identity to exist in the environ before it is called.

To utilize this middleware, you can just add it to your WSGI stack below the repoze.who middleware. Here is an example of utilizing the CSRFProtectionMiddleware within a TurboGears2 application. In your project/config/middleware.py, you would wrap your main application with the CSRFProtectionMiddleware, like so:

from fedora.wsgi.csrf import CSRFProtectionMiddleware
def make_app(global_conf, full_stack=True, **app_conf):
    app = make_base_app(global_conf, wrap_app=CSRFProtectionMiddleware,
                        full_stack=full_stack, **app_conf)

You then need to add the CSRF token to every url that you need to be authenticated for. When used with TurboGears2, an overridden version of tg.url() is provided. You can use it directly by calling:

from fedora.tg2.utils import url
[...]
url = url('/authentication_needed')

An easier and more portable way to use that is from within TG2 to set this up is to use fedora.tg2.utils.enable_csrf() when you setup your application. This function will monkeypatch TurboGears2’s tg.url() so that it adds a csrf token to urls. This way, you can keep the same code in your templates and controller methods whether or not you configure the CSRF middleware to provide you with protection via enable_csrf().

class fedora.wsgi.csrf.CSRFMetadataProvider(csrf_token_id='_csrf_token', session_cookie='tg-visit', clear_env='repoze.who.identity repoze.what.credentials', login_handler='/post_login', token_env='CSRF_TOKEN', auth_session_id='CSRF_AUTH_SESSION_ID', auth_state='CSRF_AUTH_STATE')

Repoze.who CSRF Metadata Provider Plugin.

This metadata provider is called with an authenticated users identity automatically by repoze.who. It will then take the SHA1 hash of the users session cookie, and set it as the CSRF token in environ['repoze.who.identity']['_csrf_token'].

This plugin will also set CSRF_AUTH_STATE in the environ if the user has just authenticated during this request.

To enable this plugin in a TurboGears2 application, you can add the following to your project/config/app_cfg.py

from fedora.wsgi.csrf import CSRFMetadataProvider
base_config.sa_auth.mdproviders = [('csrfmd', CSRFMetadataProvider())]

Note: If you use the faswho plugin, this is turned on automatically.

Templates

The fedora.tg2.utils module contains some templates to help you write CSRF aware login forms and buttons. You can use the fedora_template() function to integrate them into your templates:

The templates themselves come in two flavors. One set for use with mako and one set for use with genshi.

Mako

Mako version of templates to make adding certain Fedora widgets easier.

fedora.tg2.templates.mako.login.mak

Module author: Toshio Kuratomi <tkuratom@redhat.com>

New in version 0.3.25.

Include this using:

<%namespace name="fedora" file="${context['fedora_template']('login.mak')}" />
fedora.tg2.templates.mako.login.mak.loginform(message='')
kwarg message:Any text or elements contained by the <loginform> tag will be shown as a message to the user. This is generally used to show status of the last login attempt (“Please provide your credentials”, “Supplied credentials were not correct”, etc)

A function for generating the main login form. This is a CSRF token-aware login form that will prompt for username and password when no session identity is present and ask the user to click a link if they merely lack a token.

Typical usage, given the above import of the login.mak template would be:

${fedora.loginform()}
fedora.tg2.templates.mako.login.mak.logintoolitem(href=None)
kwarg href:If an href is given, when a user is logged in, their username or display_name will be a link to the URL.

This function creates an entry into a toolbar for logging into a web app. The entry will contain the user’s username and a logout button if the user is logged in, a verify login button if the user has a session cookie but not a CSRF token, or a login button if the user doesn’t have a session cookie.

Typical usage looks like this:

<ul class="toolbar" id="#main-toolbar">
  ${fedora.logintoolitem(href=tg.url('/users/info'))}
</ul>

fedora.tg2.templates.mako.jsglobals.mak

Module author: Toshio Kuratomi <tkuratom@redhat.com>

New in version 0.3.25.

Include this using:

<%namespace name="jsglobals" file="${context['fedora_template']('jsglobals.mak')}" />
fedora.tg2.templates.mako.jsglobals.mak.jsglobals()

A function to add global variables to a page. Typically, you’d include this in your master.mak template and let the javascript variables defined there propogate to every page on your site (since they all should inherit from master.mak). This adds the following variables in the fedora namespace for other scripts to access:

fedora.baseurl:URL fragment to prepend to any calls to the application. In a TurboGears application, this is the scheme, host, and server.webpath. Example: https://admin.fedoraproject.org/pkgdb/. This may be a relative link.
fedora.identity.anonymous:
 If true, there will be no other variables in the fedora.identity namespace. If false, these variables are defined:
fedora.identity.userid:
 Numeric, unique identifier for the user
fedora.identity.username:
 Publically visible unique identifier for the user
fedora.identity.display_name:
 Common human name for the user
fedora.identity.token:
 csrf token for this user’s session to be added to urls that query the server.

Typical usage would be:

${jsglobals.jsglobals()}

Genshi

Genshi version of templates to make adding certain Fedora widgets easier.

fedora.tg2.templates.genshi.login.html

Module author: Toshio Kuratomi <tkuratom@redhat.com>

New in version 0.3.26.

Include this using::
<xi:include href=”${fedora_template(‘login.html’, template_type=’genshi’)}” />
fedora.tg2.templates.genshi.login.html.loginform([message])
message:Any text or elements contained by the <loginform> tag will be shown as a message to the user. This is generally used to show status of the last login attempt (“Please provide your credentials”, “Supplied credentials were not correct”, etc)

A match template for the main login form. This is a CSRF token-aware login form that will prompt for username and password when no session identity is present and ask the user to click a link if they merely lack a token.

Typical usage would be:

<loginform>${message}</loginform>
fedora.tg2.templates.genshi.login.html.logintoolitem(@href=URL)
@href:If an href attribute is present for this tag, when a user is logged in, their username or display_name will be a link to the URL.

A match template to add an entry to a toolbar. The entry will contain the user’s username and a logout button if the user is logged in, a verify login button if the user has a session cookie but not a CSRF token, or a login button if the user doesn’t have a session cookie.

Typical usage looks like this:

<ul class="toolbar" id="#main-toolbar">
  <logintoolitem href="${tg.url('/users/info')}" />
</ul>

fedora.tg2.templates.genshi.jsglobals.html

Module author: Toshio Kuratomi <tkuratom@redhat.com>

New in version 0.3.26.

Include this using::
<xi:include href=”${fedora_template(‘jsglobals.html’, template_type=’genshi’)}” />
fedora.tg2.templates.genshi.jsglobals.html.jsglobals()

A match template to add global variables to a page. Typically, you’d include this in your master.html template and let it be added to every other page from there. This adds the following variables in the fedora namespace for other scripts to access:

fedora.baseurl:URL fragment to prepend to any calls to the application. In a TurboGears application, this is the scheme, host, and server.webpath. Example: https://admin.fedoraproject.org/pkgdb/. This may be a relative link.
fedora.identity.anonymous:
 If true, there will be no other variables in the fedora.identity namespace. If false, these variables are defined:
fedora.identity.userid:
 Numeric, unique identifier for the user
fedora.identity.username:
 Publically visible unique identifier for the user
fedora.identity.display_name:
 Common human name for the user
fedora.identity.token:
 csrf token for this user’s session to be added to urls that query the server.

Typical usage would be:

<jsglobals />