annotate pylons_app/lib/auth.py @ 190:d8eb7ee27b4c

Added LoginRequired decorator, empty User data container, hash functions
author Marcin Kuzminski <marcin@python-works.com>
date Sat, 22 May 2010 01:43:42 +0200
parents f24b9a2934cf
children 3d1dd13887f9
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
41
71ffa932799d Added app basic auth.
Marcin Kuzminski <marcin@python-blog.com>
parents:
diff changeset
1 from datetime import datetime
190
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
2 from decorator import decorator
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
3 from functools import wraps
52
25e516447a33 implemented autentication
marcink
parents: 48
diff changeset
4 from pylons import session, url
25e516447a33 implemented autentication
marcink
parents: 48
diff changeset
5 from pylons.controllers.util import abort, redirect
64
08707974eae4 Changed auth lib for sqlalchemy
Marcin Kuzminski <marcin@python-blog.com>
parents: 52
diff changeset
6 from pylons_app.model import meta
08707974eae4 Changed auth lib for sqlalchemy
Marcin Kuzminski <marcin@python-blog.com>
parents: 52
diff changeset
7 from pylons_app.model.db import Users, UserLogs
190
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
8 from sqlalchemy.exc import OperationalError
64
08707974eae4 Changed auth lib for sqlalchemy
Marcin Kuzminski <marcin@python-blog.com>
parents: 52
diff changeset
9 from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound
190
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
10 import crypt
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
11 import logging
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
12 log = logging.getLogger(__name__)
41
71ffa932799d Added app basic auth.
Marcin Kuzminski <marcin@python-blog.com>
parents:
diff changeset
13
64
08707974eae4 Changed auth lib for sqlalchemy
Marcin Kuzminski <marcin@python-blog.com>
parents: 52
diff changeset
14 def get_crypt_password(password):
190
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
15 """
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
16 Cryptographic function used for password hashing
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
17 @param password: password to hash
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
18 """
64
08707974eae4 Changed auth lib for sqlalchemy
Marcin Kuzminski <marcin@python-blog.com>
parents: 52
diff changeset
19 return crypt.crypt(password, '6a')
46
9db7782727b3 Static files for production fixed
Marcin Kuzminski <marcin@python-blog.com>
parents: 45
diff changeset
20
41
71ffa932799d Added app basic auth.
Marcin Kuzminski <marcin@python-blog.com>
parents:
diff changeset
21 def authfunc(environ, username, password):
64
08707974eae4 Changed auth lib for sqlalchemy
Marcin Kuzminski <marcin@python-blog.com>
parents: 52
diff changeset
22 sa = meta.Session
08707974eae4 Changed auth lib for sqlalchemy
Marcin Kuzminski <marcin@python-blog.com>
parents: 52
diff changeset
23 password_crypt = get_crypt_password(password)
42
b2bc08f2974b try except error on non existing user table
marcink
parents: 41
diff changeset
24 try:
64
08707974eae4 Changed auth lib for sqlalchemy
Marcin Kuzminski <marcin@python-blog.com>
parents: 52
diff changeset
25 user = sa.query(Users).filter(Users.username == username).one()
08707974eae4 Changed auth lib for sqlalchemy
Marcin Kuzminski <marcin@python-blog.com>
parents: 52
diff changeset
26 except (NoResultFound, MultipleResultsFound, OperationalError) as e:
42
b2bc08f2974b try except error on non existing user table
marcink
parents: 41
diff changeset
27 log.error(e)
64
08707974eae4 Changed auth lib for sqlalchemy
Marcin Kuzminski <marcin@python-blog.com>
parents: 52
diff changeset
28 user = None
08707974eae4 Changed auth lib for sqlalchemy
Marcin Kuzminski <marcin@python-blog.com>
parents: 52
diff changeset
29
08707974eae4 Changed auth lib for sqlalchemy
Marcin Kuzminski <marcin@python-blog.com>
parents: 52
diff changeset
30 if user:
08707974eae4 Changed auth lib for sqlalchemy
Marcin Kuzminski <marcin@python-blog.com>
parents: 52
diff changeset
31 if user.active:
08707974eae4 Changed auth lib for sqlalchemy
Marcin Kuzminski <marcin@python-blog.com>
parents: 52
diff changeset
32 if user.username == username and user.password == password_crypt:
41
71ffa932799d Added app basic auth.
Marcin Kuzminski <marcin@python-blog.com>
parents:
diff changeset
33 log.info('user %s authenticated correctly', username)
45
a886f5eba757 implemented admin page login
marcink
parents: 44
diff changeset
34 if environ:
a886f5eba757 implemented admin page login
marcink
parents: 44
diff changeset
35 http_accept = environ.get('HTTP_ACCEPT')
a886f5eba757 implemented admin page login
marcink
parents: 44
diff changeset
36
a886f5eba757 implemented admin page login
marcink
parents: 44
diff changeset
37 if http_accept.startswith('application/mercurial') or \
a886f5eba757 implemented admin page login
marcink
parents: 44
diff changeset
38 environ['PATH_INFO'].find('raw-file') != -1:
64
08707974eae4 Changed auth lib for sqlalchemy
Marcin Kuzminski <marcin@python-blog.com>
parents: 52
diff changeset
39 repo = environ['PATH_INFO']
45
a886f5eba757 implemented admin page login
marcink
parents: 44
diff changeset
40 for qry in environ['QUERY_STRING'].split('&'):
a886f5eba757 implemented admin page login
marcink
parents: 44
diff changeset
41 if qry.startswith('cmd'):
41
71ffa932799d Added app basic auth.
Marcin Kuzminski <marcin@python-blog.com>
parents:
diff changeset
42
45
a886f5eba757 implemented admin page login
marcink
parents: 44
diff changeset
43 try:
64
08707974eae4 Changed auth lib for sqlalchemy
Marcin Kuzminski <marcin@python-blog.com>
parents: 52
diff changeset
44 user_log = UserLogs()
08707974eae4 Changed auth lib for sqlalchemy
Marcin Kuzminski <marcin@python-blog.com>
parents: 52
diff changeset
45 user_log.user_id = user.user_id
08707974eae4 Changed auth lib for sqlalchemy
Marcin Kuzminski <marcin@python-blog.com>
parents: 52
diff changeset
46 user_log.action = qry
08707974eae4 Changed auth lib for sqlalchemy
Marcin Kuzminski <marcin@python-blog.com>
parents: 52
diff changeset
47 user_log.repository = repo
08707974eae4 Changed auth lib for sqlalchemy
Marcin Kuzminski <marcin@python-blog.com>
parents: 52
diff changeset
48 user_log.action_date = datetime.now()
08707974eae4 Changed auth lib for sqlalchemy
Marcin Kuzminski <marcin@python-blog.com>
parents: 52
diff changeset
49 sa.add(user_log)
08707974eae4 Changed auth lib for sqlalchemy
Marcin Kuzminski <marcin@python-blog.com>
parents: 52
diff changeset
50 sa.commit()
08707974eae4 Changed auth lib for sqlalchemy
Marcin Kuzminski <marcin@python-blog.com>
parents: 52
diff changeset
51 log.info('Adding user %s, action %s', username, qry)
45
a886f5eba757 implemented admin page login
marcink
parents: 44
diff changeset
52 except Exception as e:
64
08707974eae4 Changed auth lib for sqlalchemy
Marcin Kuzminski <marcin@python-blog.com>
parents: 52
diff changeset
53 sa.rollback()
45
a886f5eba757 implemented admin page login
marcink
parents: 44
diff changeset
54 log.error(e)
a886f5eba757 implemented admin page login
marcink
parents: 44
diff changeset
55
41
71ffa932799d Added app basic auth.
Marcin Kuzminski <marcin@python-blog.com>
parents:
diff changeset
56 return True
71ffa932799d Added app basic auth.
Marcin Kuzminski <marcin@python-blog.com>
parents:
diff changeset
57 else:
71ffa932799d Added app basic auth.
Marcin Kuzminski <marcin@python-blog.com>
parents:
diff changeset
58 log.error('user %s is disabled', username)
71ffa932799d Added app basic auth.
Marcin Kuzminski <marcin@python-blog.com>
parents:
diff changeset
59
71ffa932799d Added app basic auth.
Marcin Kuzminski <marcin@python-blog.com>
parents:
diff changeset
60 return False
71ffa932799d Added app basic auth.
Marcin Kuzminski <marcin@python-blog.com>
parents:
diff changeset
61
190
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
62 class AuthUser(object):
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
63 """
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
64 A simple object that handles a mercurial username for authentication
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
65 """
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
66 username = 'Empty'
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
67 is_authenticated = False
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
68 is_admin = False
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
69 permissions = set()
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
70 group = set()
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
71
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
72 def __init__(self):
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
73 pass
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
74
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
75 #===============================================================================
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
76 # DECORATORS
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
77 #===============================================================================
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
78 class LoginRequired(object):
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
79 """
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
80 Must be logged in to execute this function else redirect to login page
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
81 """
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
82 def __init__(self):
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
83 pass
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
84
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
85 def __call__(self, func):
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
86 log.info('Checking login required')
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
87
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
88 @wraps(func)
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
89 def _wrapper(*fargs, **fkwargs):
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
90 user = session.get('hg_app_user', AuthUser())
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
91 if user.is_authenticated:
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
92 log.info('user %s is authenticated', user.username)
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
93 func(*fargs)
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
94 else:
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
95 logging.info('user %s not authenticated', user.username)
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
96 return redirect(url('login_home'))
52
25e516447a33 implemented autentication
marcink
parents: 48
diff changeset
97
190
d8eb7ee27b4c Added LoginRequired decorator, empty User data container, hash functions
Marcin Kuzminski <marcin@python-works.com>
parents: 96
diff changeset
98 return _wrapper