Turbogears authentication over mongodb users database

As we saw that there isn’t a lot of documentation around about how to perform authentication in turbogears over mongodb we decided to create a simple code snippet and public it here to help people trying to obtain the same thing.

This is mainly a proof of concept and is quick and dirty way to obtain it. You will probably have something like ming as your model, instead of directly accessing mongo.

This code also validates password over the clear text one, you will probably have hashed passwords in your database, so remember to change validate_password method as required

To make it work you will have to place this code inside your config.app_cfg, it also expects you to have you database exposed as db inside your model

from my_app.model import db
from zope.interface import implements
from repoze.who.interfaces import IAuthenticator, IMetadataProvider
from repoze.who.plugins.friendlyform import FriendlyFormPlugin
from repoze.who.plugins.auth_tkt import AuthTktCookiePlugin
from repoze.who.middleware import PluggableAuthenticationMiddleware
 
def validate_password(user, password):
   return user['password'] == password
 
class MongoAuthenticatorPlugin(object):
    implements(IAuthenticator)
 
    # IAuthenticator
    def authenticate(self, environ, identity):
        if not ('login' in identity and 'password' in identity):
            return None
 
        login = identity.get('login')
        user = db.users.find_one({'user_name':login})
        if user and validate_password(user, identity.get('password')):
            return identity['login']
 
class MongoUserMDPlugin(object):
    implements(IMetadataProvider)
 
    def add_metadata(self, environ, identity):
        user_data = {'user_name':identity['repoze.who.userid']}
        identity['user'] = db.users.find_one(user_data)
 
class MyAppConfig(AppConfig):
    auth_backend = 'sqlalchemy' #this is a fake, but it's needed to enable
                                #auth middleware at least on TG2.0
 
    login_url = '/login'
    login_handler = '/login_handler'
    post_login_url = None
    logout_handler = '/logout_handler'
    post_logout_url = None
    login_counter_name = None
 
    def add_auth_middleware(self, app, skip_authentication):
        cookie_secret = pylons_config.get('auth_cookie_secret', 
                                          'myapp_adsfsdfh3423')
        cookie_name = pylons_config.get('auth_cookie_name', 
                                        'myapp_auth')
 
        who_args = {}
 
        form_plugin = FriendlyFormPlugin(self.login_url,
                              self.login_handler,
                              self.post_login_url,
                              self.logout_handler,
                              self.post_logout_url,
                              login_counter_name=self.login_counter_name,
                              rememberer_name='cookie')
        challengers = [('form', form_plugin)]
 
        auth = MongoAuthenticatorPlugin()
        authenticators = [('mongoauth', auth)]
 
        cookie = AuthTktCookiePlugin(cookie_secret, cookie_name)
 
        identifiers = [('cookie', cookie), ('form', form_plugin)]
 
        provider = MongoUserMDPlugin()
        mdproviders = [('mongoprovider', provider)]
 
        from repoze.who.classifiers import default_request_classifier
        from repoze.who.classifiers import default_challenge_decider
        log_stream = None
 
        app = PluggableAuthenticationMiddleware(app,
                                          identifiers,
                                          authenticators,
                                          challengers,
                                          mdproviders,
                                          default_request_classifier,
                                          default_challenge_decider)
 
        return app
 
base_config = MyAppConfig()
base_config.renderers = []
 
base_config.package = my_app
 
#Set the default renderer
base_config.default_renderer = 'genshi'
base_config.renderers.append('genshi')
base_config.renderers.append('json')
 
#Configure the base SQLALchemy Setup
base_config.use_sqlalchemy = False
base_config.model = my_app.model

Leave a Reply

Your email address will not be published. Required fields are marked *