Mercurial > public > src > rhodecode
changeset 239:b18f89d6d17f
Adde draft for permissions systems, made all needed decorators, and checks. For future usage in the system.
author | Marcin Kuzminski <marcin@python-works.com> |
---|---|
date | Sun, 30 May 2010 19:49:40 +0200 |
parents | a55c17874486 |
children | 7c4fa2a66195 |
files | pylons_app/config/environment.py pylons_app/controllers/users.py pylons_app/lib/app_globals.py pylons_app/lib/auth.py pylons_app/lib/db_manage.py pylons_app/model/db.py pylons_app/templates/admin/admin.html |
diffstat | 7 files changed, 126 insertions(+), 30 deletions(-) [+] |
line wrap: on
line diff
--- a/pylons_app/config/environment.py Sun May 30 17:55:56 2010 +0200 +++ b/pylons_app/config/environment.py Sun May 30 19:49:40 2010 +0200 @@ -1,16 +1,17 @@ """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 @@ init_model(sa_engine_db1) + set_available_permissions(config) # CONFIGURATION OPTIONS HERE (note: all config options will override # any Pylons config options)
--- a/pylons_app/controllers/users.py Sun May 30 17:55:56 2010 +0200 +++ b/pylons_app/controllers/users.py Sun May 30 19:49:40 2010 +0200 @@ -4,7 +4,7 @@ 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 @@ 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')
--- a/pylons_app/lib/app_globals.py Sun May 30 17:55:56 2010 +0200 +++ b/pylons_app/lib/app_globals.py Sun May 30 19:49:40 2010 +0200 @@ -22,3 +22,4 @@ 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
--- a/pylons_app/lib/auth.py Sun May 30 17:55:56 2010 +0200 +++ b/pylons_app/lib/auth.py Sun May 30 19:49:40 2010 +0200 @@ -1,5 +1,5 @@ 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 @@ 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 @@ 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 + + +
--- a/pylons_app/lib/db_manage.py Sun May 30 17:55:56 2010 +0200 +++ b/pylons_app/lib/db_manage.py Sun May 30 19:49:40 2010 +0200 @@ -1,17 +1,16 @@ +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 @@ 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()
--- a/pylons_app/model/db.py Sun May 30 17:55:56 2010 +0200 +++ b/pylons_app/model/db.py Sun May 30 19:49:40 2010 +0200 @@ -40,6 +40,7 @@ __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)
--- a/pylons_app/templates/admin/admin.html Sun May 30 17:55:56 2010 +0200 +++ b/pylons_app/templates/admin/admin.html Sun May 30 19:49:40 2010 +0200 @@ -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