* use sha512 passwords
* more robust SQLAlchemy session handling code * implemented password change mechanism
This commit is contained in:
		
							parent
							
								
									ade660419c
								
							
						
					
					
						commit
						949e699e25
					
				
					 7 changed files with 99 additions and 28 deletions
				
			
		|  | @ -38,7 +38,7 @@ sqlalchemy.url = sqlite:///%(here)s/gvaweb.sqlite | |||
| authkit.setup.method = form, cookie | ||||
| authkit.form.authenticate.user.type = gnuviechadminweb.model:GVAUsers | ||||
| authkit.form.authenticate.user.data = gnuviechadminweb.model.meta | ||||
| authkit.form.authenticate.user.encrypt = authkit.users:md5 | ||||
| authkit.form.authenticate.user.encrypt = gnuviechadminweb.model:sha512 | ||||
| authkit.cookie.secret = really secret data | ||||
| authkit.cookie.signoutpath = /login/logout | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,6 +2,8 @@ | |||
| import logging | ||||
| 
 | ||||
| from gnuviechadminweb.lib.base import * | ||||
| from authkit.permissions import ValidAuthKitUser | ||||
| from authkit.authorize.pylons_adaptors import authorize | ||||
| 
 | ||||
| log = logging.getLogger(__name__) | ||||
| 
 | ||||
|  | @ -9,3 +11,26 @@ class GvaController(BaseController): | |||
|     def index(self): | ||||
|         # Return a rendered template | ||||
|         return render('/main.mako') | ||||
| 
 | ||||
|     @authorize(ValidAuthKitUser()) | ||||
|     def password(self): | ||||
|         return render('/chpassword.mako') | ||||
| 
 | ||||
|     @authorize(ValidAuthKitUser()) | ||||
|     def updatepassword(self): | ||||
|         users = request.environ['authkit.users'] | ||||
|         if users.user_has_password(request.environ['REMOTE_USER'], | ||||
|                                    request.params['oldpassword']): | ||||
|             if request.params['password'] != request.params['confirm']: | ||||
|                 c.messages['errors'].append("New password and confirmation don't match") | ||||
|             elif len(request.params['password']) < 8: | ||||
|                 c.messages['errors'].append("Your new password is too short. It must consist of at least 8 characters") | ||||
|             else: | ||||
|                 users.user_set_password(request.environ['REMOTE_USER'], | ||||
|                                         request.params['password']) | ||||
|                 c.messages['messages'].append("Your password has been changed.") | ||||
|         else: | ||||
|             c.messages['errors'].append("Your old password is not correct.") | ||||
|         if c.messages['errors']: | ||||
|             return render('/chpassword.mako') | ||||
|         return render('/main.mako') | ||||
|  |  | |||
|  | @ -1,3 +1,4 @@ | |||
| 
 | ||||
| # -*- coding: utf-8 -*- | ||||
| from authkit.users import Users | ||||
| from gnuviechadminweb.model.user import Group, Role, User | ||||
|  | @ -6,33 +7,33 @@ import logging | |||
| 
 | ||||
| log = logging.getLogger(__name__) | ||||
| 
 | ||||
| def needsConnection(func): | ||||
|     def wrapper(*__args, **__kw): | ||||
|         from sqlalchemy.orm import create_session | ||||
|         engine = __args[0].meta.engine | ||||
|         conn = engine.contextual_connect() | ||||
|         if conn.closed: | ||||
|             conn = engine.connect() | ||||
|             __args[0].session = create_session(bind=conn) | ||||
|             try: | ||||
|                 return func(*__args, **__kw) | ||||
|             finally: | ||||
|                 conn.close() | ||||
|         else: | ||||
|             __args[0].session = create_session(bind=conn) | ||||
|             return func(*__args, **__kw) | ||||
| def initializedSession(func): | ||||
|     def wrapper(*__args, **__kwargs): | ||||
|         meta = __args[0].meta | ||||
|         conn = meta.engine.connect() | ||||
|         meta.Session.configure(bind=conn) | ||||
|         try: | ||||
|             return func(*__args, **__kwargs) | ||||
|         finally: | ||||
|             meta.Session.remove() | ||||
|             conn.close() | ||||
|     return wrapper | ||||
| 
 | ||||
| def sha512(password, secret = ''): | ||||
|     import hashlib | ||||
|     m = hashlib.sha512() | ||||
|     m.update(password) | ||||
|     m.update(secret) | ||||
|     return m.hexdigest() | ||||
| 
 | ||||
| class GVAUsers(Users): | ||||
|     def __init__(self, data, encrypt = None): | ||||
|         Users.__init__(self, data, encrypt) | ||||
|         log.debug("in __init__") | ||||
|         self.meta = eval_import(self.data) | ||||
|         self.session = self.meta.Session | ||||
| 
 | ||||
|     @needsConnection | ||||
|     def _getSession(self): | ||||
|         return self.session | ||||
|         return self.meta.Session | ||||
| 
 | ||||
|     def _get_group(self, groupname): | ||||
|         return self._getSession().query(Group).filter_by(name=groupname).one() | ||||
|  | @ -44,6 +45,7 @@ class GVAUsers(Users): | |||
|         return self._getSession().query(Role).filter_by(name=rolename).one() | ||||
| 
 | ||||
|     # Create Methods | ||||
|     @initializedSession | ||||
|     def user_create(self, username, password, group=None): | ||||
|         n_user = User() | ||||
|         n_user.name = username | ||||
|  | @ -53,12 +55,14 @@ class GVAUsers(Users): | |||
|         self._getSession().save(n_user) | ||||
|         self._getSession().commit() | ||||
| 
 | ||||
|     @initializedSession | ||||
|     def role_create(self, role): | ||||
|         n_role = Role() | ||||
|         n_role.name = role | ||||
|         self._getSession().save(n_role) | ||||
|         self._getSession().commit() | ||||
|      | ||||
|     @initializedSession | ||||
|     def group_create(self, group): | ||||
|         n_group = Group() | ||||
|         n_group.name = group | ||||
|  | @ -66,19 +70,23 @@ class GVAUsers(Users): | |||
|         self._getSession().commit() | ||||
| 
 | ||||
|     # Delete Methods | ||||
|     @initializedSession | ||||
|     def user_delete(self, username): | ||||
|         self._getSession().delete(self._get_user(username)) | ||||
|         self._getSession().commit() | ||||
|      | ||||
|     @initializedSession | ||||
|     def role_delete(self, role): | ||||
|         self._getSession().delete(self._get_role(role)) | ||||
|         self._getSession().commit() | ||||
|      | ||||
|     @initializedSession | ||||
|     def group_delete(self, group): | ||||
|         self._getSession().delete(self._get_group()) | ||||
|         self._getSession().commit() | ||||
|      | ||||
|     # Delete Cascade Methods | ||||
|     @initializedSession | ||||
|     def role_delete_cascade(self, role): | ||||
|         n_role = self._get_role(role) | ||||
|         for user in self._getSession().query(User).roles.any(name=role).all(): | ||||
|  | @ -86,6 +94,7 @@ class GVAUsers(Users): | |||
|         self._getSession().delete(n_role) | ||||
|         self._getSession().commit() | ||||
|      | ||||
|     @initializedSession | ||||
|     def group_delete_cascade(self, group): | ||||
|         n_group = self._get_group(group) | ||||
|         self._getSession().delete(self._getSession().query(User).filter_by( | ||||
|  | @ -94,32 +103,39 @@ class GVAUsers(Users): | |||
|         self._getSession().commit() | ||||
| 
 | ||||
|     # Existence Methods | ||||
|     @initializedSession | ||||
|     def user_exists(self, username): | ||||
|         return self._getSession().query(User).filter_by( | ||||
|             name=username).count() == 1 | ||||
| 
 | ||||
|     @initializedSession | ||||
|     def role_exists(self, role): | ||||
|         return self._getSession().query(Role).filter_by( | ||||
|             name=role).count() == 1 | ||||
| 
 | ||||
|     @initializedSession | ||||
|     def group_exists(self, group): | ||||
|         return self._getSession().query(Group).filter_by( | ||||
|             name=group).count() == 1 | ||||
| 
 | ||||
|     # List Methods | ||||
|     @initializedSession | ||||
|     def list_roles(self): | ||||
|         return [role.name.lower() for role in self._getSession().query( | ||||
|                 Role).all()] | ||||
|      | ||||
|     @initializedSession | ||||
|     def list_users(self): | ||||
|         return [user.name.lower() for user in self._getSession().query( | ||||
|                 User).all()] | ||||
| 
 | ||||
|     @initializedSession | ||||
|     def list_groups(self): | ||||
|         return [group.name.lower() for group in self._getSession().query( | ||||
|                 Group).all()] | ||||
| 
 | ||||
|     # User Methods | ||||
|     @initializedSession | ||||
|     def user(self, username): | ||||
|         user = self._get_user(username) | ||||
|         roles = [role.name.lower() for role in user.roles] | ||||
|  | @ -131,40 +147,48 @@ class GVAUsers(Users): | |||
|             'roles'    : roles | ||||
|             } | ||||
| 
 | ||||
|     @initializedSession | ||||
|     def user_roles(self, username): | ||||
|         user = self._get_user(username) | ||||
|         roles = [role.name.lower() for role in user.roles] | ||||
|         roles.sort() | ||||
|         return roles | ||||
| 
 | ||||
|     @initializedSession | ||||
|     def user_group(self, username): | ||||
|         user = self._get_user(username) | ||||
|         return None if user.group is None else user.group.name | ||||
| 
 | ||||
|     @initializedSession | ||||
|     def user_password(self, username): | ||||
|         user = self._get_user(username) | ||||
|         return user.password | ||||
| 
 | ||||
|     @initializedSession | ||||
|     def user_has_role(self, username, role): | ||||
|         user = self._get_user(username) | ||||
|         return role in [role.name for role in user.roles] | ||||
| 
 | ||||
|     @initializedSession | ||||
|     def user_has_group(self, username, group): | ||||
|         user = self._get_user(username) | ||||
|         return (group is None and user.group is None) or \ | ||||
|             (group is not None and user.group is not None and \ | ||||
|                  group == user.group.name) | ||||
| 
 | ||||
|     @initializedSession | ||||
|     def user_has_password(self, username, password): | ||||
|         user = self._get_user(username) | ||||
|         return user.password == self.encrypt(password) | ||||
| 
 | ||||
|     @initializedSession | ||||
|     def user_set_username(self, username, new_username): | ||||
|         user = self._get_user(username) | ||||
|         user.name = new_username | ||||
|         self._getSession().update(user) | ||||
|         self._getSession().commit() | ||||
| 
 | ||||
|     @initializedSession | ||||
|     def user_set_group(self, username, group, add_if_necessary=False): | ||||
|         if add_if_necessary and self._getSession().query(Group).filter_by( | ||||
|             name=group).count() == 0: | ||||
|  | @ -175,6 +199,7 @@ class GVAUsers(Users): | |||
|         self._getSession().update(user) | ||||
|         self._getSession().commit() | ||||
|      | ||||
|     @initializedSession | ||||
|     def user_add_role(self, username, role, add_if_necessary=False): | ||||
|         if add_if_necessary and self._getSession().query(Role).filter_by( | ||||
|             name=role).count() == 0: | ||||
|  | @ -186,6 +211,7 @@ class GVAUsers(Users): | |||
|         self._getSession().update(user) | ||||
|         self._getSession().commit() | ||||
| 
 | ||||
|     @initializedSession | ||||
|     def user_remove_role(self, username, role): | ||||
|         roleobj = self._get_role(role) | ||||
|         user = self._get_user(username) | ||||
|  | @ -193,8 +219,16 @@ class GVAUsers(Users): | |||
|             del user.roles[roleobj.id] | ||||
|         self._getSession().commit() | ||||
| 
 | ||||
|     @initializedSession | ||||
|     def user_remove_group(self, username): | ||||
|         user = self._get_user(username) | ||||
|         user.group = None | ||||
|         self._getSession().update(user) | ||||
|         self._getSession().commit() | ||||
| 
 | ||||
|     @initializedSession | ||||
|     def user_set_password(self, username, password): | ||||
|         user = self._get_user(username) | ||||
|         user.password = self.encrypt(password) | ||||
|         self._getSession().update(user) | ||||
|         self._getSession().commit() | ||||
|  |  | |||
|  | @ -12,5 +12,5 @@ def init_model(engine): | |||
|     meta.Session = orm.scoped_session(sm) | ||||
| 
 | ||||
| from gnuviechadminweb.model.user import Group, Role, User | ||||
| from gnuviechadminweb.model.GVAUsers import GVAUsers | ||||
| from gnuviechadminweb.model.GVAUsers import GVAUsers, sha512 | ||||
| from gnuviechadminweb.model.menu import Menu | ||||
|  |  | |||
|  | @ -5,7 +5,12 @@ class Menu(object): | |||
|         ('Main page', 'gva', 'index', None), | ||||
|         ('Login', 'login', 'login', []), | ||||
|         ('Logout', 'login', 'logout', ['*']), | ||||
|         ('Admin', 'gva', 'index', ['admin']) | ||||
|         ('Manage clients', 'clients', 'index', ['admin']), | ||||
|         ('Update Profile', 'client', 'changes', ['client']), | ||||
|         ('System accounts', 'sysuser', 'index', ['admin']), | ||||
|         ('System account', 'sysuser', 'account', ['client']), | ||||
|         ('Mail accounts', 'mailaccount', 'index', ['admin', 'sysuser']), | ||||
|         ('Change password', 'gva', 'password', ['*']) | ||||
|         ] | ||||
| 
 | ||||
|     @classmethod | ||||
|  | @ -30,7 +35,3 @@ class Menu(object): | |||
|         self.title = title | ||||
|         self.controller = controller | ||||
|         self.action = action | ||||
| 
 | ||||
|              | ||||
|          | ||||
|      | ||||
|  |  | |||
							
								
								
									
										12
									
								
								gnuviechadminweb/templates/chpassword.mako
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								gnuviechadminweb/templates/chpassword.mako
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,12 @@ | |||
| # -*- coding: utf-8 -*- | ||||
| <%inherit file="site.mako" /> | ||||
| <h1>Change your password</h1> | ||||
| ${h.form(h.url(action='updatepassword'), method='post')} | ||||
| Old password: ${h.password_field('oldpassword')} | ||||
| New password:  ${h.password_field('password')} | ||||
| Confirm new password: ${h.password_field('confirm')} | ||||
| ${h.submit('Change password')} | ||||
| ${h.end_form()} | ||||
| <%def name="headlines()"> | ||||
|   <title>Change your password</title> | ||||
| </%def> | ||||
|  | @ -6,8 +6,7 @@ from pylons import config | |||
| 
 | ||||
| from gnuviechadminweb.config.environment import load_environment | ||||
| from gnuviechadminweb.model import meta, User, Group, Role | ||||
| from gnuviechadminweb.model.GVAUsers import GVAUsers | ||||
| from authkit.users import md5 | ||||
| from gnuviechadminweb.model.GVAUsers import GVAUsers, sha512 | ||||
| 
 | ||||
| log = logging.getLogger(__name__) | ||||
| 
 | ||||
|  | @ -20,7 +19,7 @@ def setup_config(command, filename, section, vars): | |||
|     meta.metadata.create_all(bind=meta.engine) | ||||
| 
 | ||||
|     log.info("Creating default admin user, role and group") | ||||
|     users = GVAUsers('gnuviechadminweb.model:meta', md5) | ||||
|     users = GVAUsers('gnuviechadminweb.model:meta', sha512) | ||||
|     users.role_create("admin") | ||||
|     users.group_create("administrators") | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue