Changeset - b18f89d6d17f
[Not reviewed]
default
0 7 0
Marcin Kuzminski - 15 years ago 2010-05-30 19:49:40
marcin@python-works.com
Adde draft for permissions systems, made all needed decorators, and checks. For future usage in the system.
7 files changed with 126 insertions and 30 deletions:
0 comments (0 inline, 0 general)
pylons_app/config/environment.py
Show inline comments
 
"""Pylons environment configuration"""
 
import logging
 
import os
 

	
 
from mako.lookup import TemplateLookup
 
from pylons.configuration import PylonsConfig
 
from pylons.error import handle_mako_error
 
from pylons_app.config.routing import make_map
 
from pylons_app.lib.auth import set_available_permissions
 
from pylons_app.model import init_model
 
from sqlalchemy import engine_from_config
 

	
 
import logging
 
import os
 
import pylons_app.lib.app_globals as app_globals
 
import pylons_app.lib.helpers
 
from pylons_app.config.routing import make_map
 
from pylons_app.model import init_model
 

	
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 
@@ -62,6 +63,7 @@ def load_environment(global_conf, app_co
 

	
 
    init_model(sa_engine_db1)
 

	
 
    set_available_permissions(config)
 
    # CONFIGURATION OPTIONS HERE (note: all config options will override
 
    # any Pylons config options)
 
    
pylons_app/controllers/users.py
Show inline comments
 
@@ -4,7 +4,7 @@ from pylons import request, response, se
 
from pylons.i18n.translation import _
 
from pylons_app.lib import helpers as h    
 
from pylons.controllers.util import abort, redirect
 
from pylons_app.lib.auth import LoginRequired
 
from pylons_app.lib.auth import LoginRequired, CheckPermissionAll
 
from pylons_app.lib.base import BaseController, render
 
from pylons_app.model.db import User, UserLog
 
from pylons_app.model.forms import UserForm
 
@@ -26,7 +26,8 @@ class UsersController(BaseController):
 
        c.admin_user = session.get('admin_user')
 
        c.admin_username = session.get('admin_username')
 
        super(UsersController, self).__before__()
 
        
 
    
 

	
 
    def index(self, format='html'):
 
        """GET /users: All items in the collection"""
 
        # url('users')
pylons_app/lib/app_globals.py
Show inline comments
 
@@ -22,3 +22,4 @@ class Globals(object):
 
        self.paths = self.baseui.configitems('paths')
 
        self.base_path = self.paths[0][1].replace('*', '')
 
        self.changeset_annotation_colors = {}
 
        self.available_permissions = None # propagated after init_model
pylons_app/lib/auth.py
Show inline comments
 
from functools import wraps
 
from pylons import session, url
 
from pylons import session, url, app_globals as g
 
from pylons.controllers.util import abort, redirect
 
from pylons_app.model import meta
 
from pylons_app.model.db import User
 
@@ -47,7 +47,26 @@ class  AuthUser(object):
 
    
 
    def __init__(self):
 
        pass
 
    
 

	
 

	
 

	
 
def set_available_permissions(config):
 
    """
 
    This function will propagate pylons globals with all available defined
 
    permission given in db. We don't wannt to check each time from db for new 
 
    permissions since adding a new permission also requires application restart
 
    ie. to decorate new views with the newly created permission
 
    @param config:
 
    """
 
    from pylons_app.model.meta import Session
 
    from pylons_app.model.db import Permission
 
    logging.info('getting information about all available permissions')
 
    sa = Session()
 
    all_perms = sa.query(Permission).all()
 
    config['pylons.app_globals'].available_permissions = [x.permission_name for x in all_perms]
 

	
 

	
 
        
 
#===============================================================================
 
# DECORATORS
 
#===============================================================================
 
@@ -73,3 +92,62 @@ class LoginRequired(object):
 
                return redirect(url('login_home'))
 

	
 
        return _wrapper
 

	
 
class PermsDecorator(object):
 
    
 
    def __init__(self, *perms):
 
        available_perms = g.available_permissions
 
        for perm in perms:
 
            if perm not in available_perms:
 
                raise Exception("'%s' permission in not defined" % perm)
 
        self.required_perms = set(perms)
 
        self.user_perms = set([])#propagate this list from somewhere.
 
        
 
    def __call__(self, func):        
 
        @wraps(func)
 
        def _wrapper(*args, **kwargs):
 
            logging.info('checking %s permissions %s for %s',
 
               self.__class__.__name__[-3:], self.required_perms, func.__name__)            
 
            
 
            if self.check_permissions():
 
                logging.info('Permission granted for %s', func.__name__)
 
                return func(*args, **kwargs)
 
            
 
            else:
 
                logging.warning('Permission denied for %s', func.__name__)
 
                #redirect with forbidden ret code
 
                return redirect(url('access_denied'), 403) 
 
        return _wrapper
 
        
 
        
 
    def check_permissions(self):
 
        """
 
        Dummy function for overiding
 
        """
 
        raise Exception('You have to write this function in child class')
 

	
 
class CheckPermissionAll(PermsDecorator):
 
    """
 
    Checks for access permission for all given predicates. All of them have to
 
    be meet in order to fulfill the request
 
    """
 
        
 
    def check_permissions(self):
 
        if self.required_perms.issubset(self.user_perms):
 
            return True
 
        return False
 
            
 

	
 
class CheckPermissionAny(PermsDecorator):
 
    """
 
    Checks for access permission for any of given predicates. In order to 
 
    fulfill the request any of predicates must be meet
 
    """
 
    
 
    def check_permissions(self):
 
        if self.required_perms.intersection(self.user_perms):
 
            return True
 
        return False
 

	
 

	
 

	
pylons_app/lib/db_manage.py
Show inline comments
 
from os.path import dirname as dn, join as jn
 
from pylons_app.lib.auth import get_crypt_password
 
from pylons_app.model import init_model
 
from pylons_app.model.db import User, Permission
 
from pylons_app.model.meta import Session, Base
 
from sqlalchemy.engine import create_engine
 
import logging
 
from os.path import dirname as dn
 
from os.path import join as jn
 
from sqlalchemy.engine import create_engine
 
import os
 
import sys
 
ROOT = dn(dn(dn(os.path.realpath(__file__))))
 
sys.path.append(ROOT)
 

	
 
from pylons_app.model.db import User
 
from pylons_app.model.meta import Session, Base
 

	
 
from pylons_app.lib.auth import get_crypt_password
 
from pylons_app.model import init_model
 

	
 
log = logging.getLogger('db manage')
 
log.setLevel(logging.DEBUG)
 
@@ -68,9 +67,28 @@ class DbManage(object):
 
            self.sa.rollback()
 
            raise
 
    
 
    def create_permissions(self):
 
        perms = [('can_view_admin_users', 'Access to admin user view'),
 
                 
 
                 ]
 
        
 
        for p in perms:
 
            new_perm = Permission()
 
            new_perm.permission_name = p[0]
 
            new_perm.permission_longname = p[1]
 
            try:
 
                self.sa.add(new_perm)
 
                self.sa.commit()
 
            except:
 
                self.sa.rollback()
 
                raise
 
        
 
        
 
        
 
if __name__ == '__main__':
 
    dbmanage = DbManage(log_sql=True)
 
    dbmanage.create_tables(override=True)
 
    dbmanage.admin_prompt()  
 
    dbmanage.admin_prompt()
 
    dbmanage.create_permissions()  
 

	
 

	
pylons_app/model/db.py
Show inline comments
 
@@ -40,6 +40,7 @@ class Permission(Base):
 
    __table_args__ = {'useexisting':True}
 
    permission_id = Column("id", INTEGER(), nullable=False, unique=True, default=None, primary_key=1)
 
    permission_name = Column("permission_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 

	
 
    permission_longname = Column("permission_longname", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    
 
    def __repr__(self):
 
        return "<Permission('%s:%s')>" % (self.permission_id, self.permission_name)
pylons_app/templates/admin/admin.html
Show inline comments
 
@@ -12,15 +12,10 @@
 
	${self.submenu('')}
 
</%def>
 
<%def name="main()">
 
    %if c.admin_user:
 
	    <div>
 
	        <h2>Welcome ${c.admin_username}</h2>
 
			    <div id="user_log">
 
					${c.log_data}
 
				</div>
 
	    </div>
 
    %else:
 
		<h2>${_('Sorry only admin users can acces this area')}</h2>
 
    %endif
 
    
 
    <div>
 
        <h2>Welcome ${c.admin_username}</h2>
 
		    <div id="user_log">
 
				${c.log_data}
 
			</div>
 
    </div>
 
</%def>
 
\ No newline at end of file
0 comments (0 inline, 0 general)