/shabti/templates/humanoid/+package+/model/identity.py_tmpl
Unknown | 155 lines | 130 code | 25 blank | 0 comment | 0 complexity | f2626d706e472e10e8a499099a423bd3 MD5 | raw file
1""" Sample SQLAlchemy-powered model definition for the repoze.what SQL plugin.
2
3From published Pylons + repoze.what example:
4http://wiki.pylonshq.com/display/pylonscookbook/Authorization+with+repoze.what
5"""
6import logging
7import os
8import bcrypt
9import datetime
10from sqlalchemy import Table, ForeignKey, Column
11from sqlalchemy.types import String, Unicode, UnicodeText, Integer, DateTime,\
12 Boolean, Float
13from sqlalchemy.orm import relation, backref, synonym
14from sqlalchemy.ext.declarative import synonym_for
15from {{package}}.model.meta import Base, Session
16
17log = logging.getLogger(__name__)
18
19# This is the association table for the many-to-many relationship between
20# groups and permissions.
21group_permission_table = Table(
22 'group_permission', Base.metadata,
23 Column('group_id', Integer, ForeignKey('group.group_id',
24 onupdate="CASCADE", ondelete="CASCADE")),
25 Column('permission_id', Integer, ForeignKey('permission.permission_id',
26 onupdate="CASCADE", ondelete="CASCADE"))
27)
28
29# This is the association table for the many-to-many relationship between
30# groups and members - this is, the memberships.
31user_group_table = Table(
32 'user_group', Base.metadata,
33 Column('user_id', Integer, ForeignKey('user.user_id',
34 onupdate="CASCADE", ondelete="CASCADE")),
35 Column('group_id', Integer, ForeignKey('group.group_id',
36 onupdate="CASCADE", ondelete="CASCADE"))
37)
38
39# auth model
40class NotAuthenticated(Exception):pass
41class Group(Base):
42 """An ultra-simple group definition."""
43 __tablename__ = 'group'
44 group_id = Column(Integer, autoincrement=True, primary_key=True)
45 name = Column(Unicode(16), unique=True)
46 description = Column(Unicode(255))
47 active = Column(Boolean(), default=False)
48 created = Column(DateTime(), default=datetime.datetime.utcnow())
49 users = relation('User', secondary=user_group_table, backref='groups')
50 @synonym_for('group_id')
51 @property
52 def id(self):
53 return self.group_id
54 def __repr__(self):
55 return self.name
56
57 __unicode__ = __repr__
58
59
60class User(Base):
61 """
62 Reasonably basic User definition. Probably would want additional
63 attributes."""
64 __tablename__ = 'user'
65 user_id = Column(Integer, autoincrement=True, primary_key=True)
66 username = Column(Unicode(16), unique=True)
67 displayname = Column(Unicode(255))
68 email = Column(Unicode(255))
69 _password = Column('password', Unicode(80))
70 password_check = Column(Unicode(80))
71 active = Column(Boolean(), default=False)
72 created = Column(DateTime(), default=datetime.datetime.utcnow())
73 def _set_password(self, password):
74 """Hash password on the fly."""
75 hashed_password = password
76
77 if isinstance(password, unicode):
78 password_8bit = password.encode('UTF-8')
79 else:
80 password_8bit = password
81
82 hashed_password = bcrypt.hashpw(password_8bit, bcrypt.gensalt())
83
84 # Make sure the hashed password is an UTF-8 object at the end of the
85 # process because SQLAlchemy _wants_ a unicode object for Unicode
86 # fields
87 if not isinstance(hashed_password, unicode):
88 hashed_password = hashed_password.decode('UTF-8')
89
90 self._password = hashed_password
91
92 def _get_password(self):
93 """Return the password hashed"""
94 return self._password
95 password = synonym('_password', descriptor=property(_get_password,
96 _set_password))
97 def __repr__(self):
98 return self.username
99
100 __unicode__ = __repr__
101
102 @synonym_for('user_id')
103 @property
104 def id(self):
105 return self.user_id
106
107 @classmethod
108 def authenticate(cls, username, password):
109 try:
110 user = Session.query(cls).filter_by(
111 username=username, active=True).one()
112 if user and bcrypt.hashpw(password, user.password) == user.password:
113 log.debug("Authentication succeeded")
114 return user
115 except Exception, emsg:
116 log.debug("Authentication failed: %s" % str(emsg))
117 raise NotAuthenticated
118 raise NotAuthenticated
119
120 # def validate_password(self, user, password):
121 # return bcrypt.hashpw(password, user.password) == user.password
122 def validate_password(self, password):
123 """
124 Check the password against existing credentials.
125
126 :param password: the password that was provided by the user to
127 try and authenticate. This is the clear text version that we will
128 need to match against the hashed one in the database.
129 :type password: unicode object.
130 :return: Whether the password is valid.
131 :rtype: bool
132
133 """
134 return bcrypt.hashpw(password, self.password) == self.password
135
136
137class Permission(Base):
138 """A relationship that determines what each Group can do"""
139 __tablename__ = 'permission'
140 permission_id = Column(Integer, autoincrement=True, primary_key=True)
141 name = Column(Unicode(16), unique=True)
142 description = Column(Unicode(255))
143 groups = relation(Group, secondary=group_permission_table,
144 backref='permissions')
145 def __repr__(self):
146 return self.name
147
148 __unicode__ = __repr__
149 @synonym_for('permission_id')
150 @property
151 def id(self):
152 return self.permission_id
153
154
155