Hi Gustavo,

Thanks for that, I've checked through the attached files and can't see
much wrong with what I've done so far?

I've attached my config.middleware and model.auth as requested. The
only difference I can see is that I'm using 'users' and 'groups' as
the table names in place of 'user' and 'group', but I've declared
those changes in the model.

Also, here's the full traceback I receive when POSTing the login
information. I'm running Pylons 0.9.7rc4

line 428 in respond
  app_iter = self.application(environ, detect_start_response)
line 81 in __call__
  return self.app(environ, start_response)
line 159 in __call__
  return self.wrap_app(environ, session_start_response)
line 118 in __call__
  response = self.app(environ, start_response)
line 69 in __call__
  auth_ids = self.authenticate(environ, classification, ids)
line 193 in authenticate
  userid = plugin.authenticate(environ, identity)
line 112 in authenticate
  user = self.get_user(identity['login'])
line 52 in get_user
  query = self.dbsession.query(self.user_class)
AttributeError: 'NoneType' object has no attribute 'query'

Many thanks,


2009/2/16 Gustavo Narea <m...@gustavonarea.net>:
> Hello, Iain.
> Can you please paste the contents of {app}.config.middleware, and the file
> where you define auth-related models?
> Just in case, I've attached the model package from a fake Pylons project I use
> to test this plugin.
> Cheers.
> On Saturday February 14, 2009 11:55:13 Iain Campbell wrote:
>> Hi all,
>> I've set up repoze.who & repoze.what using the new quickstart.
>> Everything's defined as per the tutorial, with the exception of the
>> relevant table names which have been updated in the model. All column,
>> property and class names are the same.
>> When I submit the login form, I get:
>> > Module repoze.who.plugins.sa:52 in get_user
>> > query = self.dbsession.query(self.user_class)
>> > AttributeError: 'NoneType' object has no attribute 'query'
>> dbsession isn't initialised for some reason but I can't work out why...
>> Any help/pointers appreciated. If there's anything more I can post
>> that may help, please shout.
>> Thanks,
>> Iain
> --
> Gustavo Narea <http://gustavonarea.net/>.
> Get rid of unethical constraints! Get freedomware:
> http://www.getgnulinux.org/


web | iptv | mobile
development & consultancy

t: +44 (0) 203 051 7792
m: +44 (0) 7815 821 678
gtalk: i...@kandaba.com
"""Pylons middleware initialization"""
from beaker.middleware import CacheMiddleware, SessionMiddleware
from paste.cascade import Cascade
from paste.registry import RegistryManager
from paste.urlparser import StaticURLParser
from paste.deploy.converters import asbool
from pylons import config
from pylons.middleware import ErrorHandler, StatusCodeRedirect
from pylons.wsgiapp import PylonsApp
from routes.middleware import RoutesMiddleware
from amberweb.lib.auth import add_auth
from amberweb.config.environment import load_environment

def make_app(global_conf, full_stack=True, **app_conf):
    """Create a Pylons WSGI application and return it

        The inherited configuration for this application. Normally from
        the [DEFAULT] section of the Paste ini file.

        Whether or not this application provides a full WSGI stack (by
        default, meaning it handles its own exceptions and errors).
        Disable full_stack when this application is "managed" by
        another WSGI middleware.

        The application's local configuration. Normally specified in
        the [app:<name>] section of the Paste ini file (where <name>
        defaults to main).

    # Configure the Pylons environment
    load_environment(global_conf, app_conf)

    # The Pylons WSGI app
    app = PylonsApp()
    # CUSTOM MIDDLEWARE HERE (filtered by error handling middlewares)
    app = add_auth(app)
    # Routing/Session/Cache Middleware
    app = RoutesMiddleware(app, config['routes.map'])
    app = SessionMiddleware(app, config)
    app = CacheMiddleware(app, config)
    if asbool(full_stack):
        # Handle Python exceptions
        app = ErrorHandler(app, global_conf, **config['pylons.errorware'])

        # Display error documents for 401, 403, 404 status codes (and
        # 500 when debug is disabled)
        if asbool(config['debug']):
            app = StatusCodeRedirect(app)
            app = StatusCodeRedirect(app, [400, 401, 403, 404, 500])
    # Establish the Registry for this application
    app = RegistryManager(app)

    # Static files (If running in production, and Apache or another web 
    # server is handling this static content, remove the following 2 lines)
    static_app = StaticURLParser(config['pylons.paths']['static_files'])
    import os
    root = config['pylons.paths']['root']
    overroot = os.path.dirname(root)
    appcelerator_static = StaticURLParser(
    app = Cascade([appcelerator_static, static_app, app])
    return app
import os
from hashlib import sha1
from datetime import datetime
from sqlalchemy import Table, ForeignKey, Column, schema
from sqlalchemy.types import String, Unicode, UnicodeText, Integer, DateTime, Boolean, Float
from sqlalchemy.orm import relation, backref, synonym
from amberweb.model.meta import DeclarativeBase, metadata

# This is the association table for the many-to-many relationship between
# groups and permissions.
group_permission_table = Table('group_permission', metadata,
    Column('group_id', Integer, ForeignKey('groups.group_id',
        onupdate="CASCADE", ondelete="CASCADE")),
    Column('permission_id', Integer, ForeignKey('permission.permission_id',
        onupdate="CASCADE", ondelete="CASCADE"))

# This is the association table for the many-to-many relationship between
# groups and members - this is, the memberships.
user_group_table = Table('user_group', metadata,
    Column('user_id', Integer, ForeignKey('users.user_id',
        onupdate="CASCADE", ondelete="CASCADE")),
    Column('group_id', Integer, ForeignKey('groups.group_id',
        onupdate="CASCADE", ondelete="CASCADE"))

class Group(DeclarativeBase):
    """An ultra-simple group definition.
    __tablename__ = 'groups'

    group_id = Column(Integer, autoincrement=True, primary_key=True)

    group_name = Column(Unicode(16), unique=True)

    users = relation('User', secondary=user_group_table, backref='groups')

class Permission(DeclarativeBase):
    """A relationship that determines what each Group can do"""
    __tablename__ = 'permission'

    permission_id = Column(Integer, autoincrement=True, primary_key=True)

    permission_name = Column(Unicode(16), unique=True)

    groups = relation(Group, secondary=group_permission_table,

class User(DeclarativeBase):
    """Reasonably basic User definition. Probably would want additional
    __tablename__ = 'users'

    user_id = Column(Integer, autoincrement=True, primary_key=True)
    user_name = Column(Unicode(255), unique=True)

    fullname = Column(Unicode(30), unique=True)

    _password = Column('password', Unicode(255))

    def _set_password(self, password):
        """Hash password on the fly."""
        hashed_password = password

        if isinstance(password, unicode):
            password_8bit = password.encode('UTF-8')
            password_8bit = password
        salt = sha1()
        hash = sha1()
        hash.update(password_8bit + salt.hexdigest())
        hashed_password = salt.hexdigest() + hash.hexdigest()

        # make sure the hashed password is an UTF-8 object at the end of the
        # process because SQLAlchemy _wants_ a unicode object for Unicode columns
        if not isinstance(hashed_password, unicode):
            hashed_password = hashed_password.decode('UTF-8')

        self._password = hashed_password

    def _get_password(self):
        """returns password
        return self._password

    password = synonym('_password', descriptor=property(_get_password,

    def validate_password(self, password):
        """Check the password against existing credentials.

        :param password: the password that was provided by the user to
            try and authenticate. This is the clear text version that we will
            need to match against the hashed one in the database.
        :type password: unicode object.
        :return: Whether the password is valid.
        :rtype: bool
        hashed_pass = sha1()
        hashed_pass.update(password + self.password[:40])
        return self.password[40:] == hashed_pass.hexdigest()
Repoze-dev mailing list

Reply via email to