You need to configure repoze.who through repoze.what in order to use
repoze what protectors like not_anonymous. Besides that, remember that
the standard openid plugin has only a dummy authenticator plugin that
does nothing and you might need to extend it to make it talk with your
database or whatever.
In my case instead of using who.ini for configuring the plugin I did all
in middleware.py. Find below my configuration (repdotcom is the name of
my pylons project, everything else is standard repoze what/who).
Feel free to ask any clarification you need to understand the code.
from repoze.who.plugins.auth_tkt import AuthTktCookiePlugin
from repoze.who.plugins.openid.identification import OpenIdIdentificationPlugin
from repdotcom.lib.auth import OpenIdMetadata, OpenIdAuthenticator
from repoze.who.classifiers import default_request_classifier
from repoze.who.plugins.openid.classifiers import openid_challenge_decider
from repoze.what.middleware import setup_auth
from repdotcom.config.environment import load_environment
def make_app(global_conf, full_stack=True, static_files=True, **app_conf):
... some code here ...
# CUSTOM MIDDLEWARE HERE (filtered by error handling middlewares)
openid = OpenIdIdentificationPlugin(
store='file',
openid_field='openid',
session_name='pylons.session',
login_handler_path='/openid_login_handler',
logout_handler_path='/logout_handler',
login_form_url='/login',
error_field='error',
logged_in_url='/welcome_back',
logged_out_url='/see_you_later',
came_from_field='came_from',
store_file_path=app_conf['cache_dir']+'/sstore',
rememberer_name='auth_tkt',
attr_ex='openid.ax.required=email openid.ax.type.email=http://axschema.org/contact/email')
auth_tkt = AuthTktCookiePlugin(secret='xxxxxxxxxx', secure=True,
timeout=86400, reissue_time=3600)
authenticator = OpenIdAuthenticator()
openidmd = OpenIdMetadata()
app = setup_auth(app, None, None,
identifiers=[('openid', openid),
('auth_tkt', auth_tkt)],
authenticators=[('authenticator', authenticator)],
challengers=[('openid', openid)],
mdproviders=[('mdproviders', openidmd)],
classifier=default_request_classifier,
challenge_decider=openid_challenge_decider,
log_stream=app_conf['who.log_file'],
log_level=app_conf['who.log_level'])
I wouldn't mind.
In this particular project I'm developing an application that uses
Google OpenId implementation since this organization is using Apps for
mail so I just need Google's openid to return the user's email (that's
why I'm using attribute exchange and trying to authenticate against the
user email). This means that the user email should exist in my database
or otherwise I cannot grant access to her/him. You might need to
implement other strategy though. Anyway, whatever you do, in
OpenIdAuthenticator you need to return the user's id or None (you cannot
raise exceptions). In OpenIdMetada you can add some extra information to
the identity dictionary, like preferred language, gender, etc.
from zope.interface import implements
from repoze.who.interfaces import IAuthenticator, IMetadataProvider
from repdotcom.model.meta import Session
from repdotcom.model.parameter import User
class OpenIdMetadata(object):
implements(IMetadataProvider)
def add_metadata( self, environ, identity ):
"""Add our stored metadata to given identity if available"""
key = identity.get('repoze.who.userid')
if key:
# as_user_values is a method that returns extra data about
# the authenticated user, such as name, surname, gender and
# language
user = as_user_values(key)
try:
identity['userdata'] = user
except AttributeError:
pass
return identity
class OpenIdAuthenticator(object):
implements(IAuthenticator)
def authenticate(self, environ, identity):
key = identity.get('repoze.who.plugins.openid.openid.ax.type.email')
if key:
try:
user = Session.query(User.id).\
filter(User.email==unicode(key[0])).\
filter(User.active==True).one()
environ['repoze.who.logger'].\
info('authenticated : %s ' % user.id)
return user.id
except NoResultFound:
return None
else:
return None