security.py :  » Issue-Tracker » Roundup-Issue-Tracker » roundup-1.4.13 » roundup » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Issue Tracker » Roundup Issue Tracker 
Roundup Issue Tracker » roundup 1.4.13 » roundup » security.py
"""Handle the security declarations used in Roundup trackers.
"""
__docformat__ = 'restructuredtext'

import weakref

from roundup import hyperdb,support

class Permission:
    ''' Defines a Permission with the attributes
        - name
        - description
        - klass (optional)
        - properties (optional)
        - check function (optional)

        The klass may be unset, indicating that this permission is not
        locked to a particular class. That means there may be multiple
        Permissions for the same name for different classes.

        If property names are set, permission is restricted to those
        properties only.

        If check function is set, permission is granted only when
        the function returns value interpreted as boolean true.
        The function is called with arguments db, userid, itemid.
    '''
    def __init__(self, name='', description='', klass=None,
            properties=None, check=None):
        self.name = name
        self.description = description
        self.klass = klass
        self.properties = properties
        self._properties_dict = support.TruthDict(properties)
        self.check = check

    def test(self, db, permission, classname, property, userid, itemid):
        if permission != self.name:
            return 0

        # are we checking the correct class
        if self.klass is not None and self.klass != classname:
            return 0

        # what about property?
        if property is not None and not self._properties_dict[property]:
            return 0

        # check code
        if itemid is not None and self.check is not None:
            if not self.check(db, userid, itemid):
                return 0

        # we have a winner
        return 1

    def __repr__(self):
        return '<Permission 0x%x %r,%r,%r,%r>'%(id(self), self.name,
            self.klass, self.properties, self.check)

    def __cmp__(self, other):
        if self.name != other.name:
            return cmp(self.name, other.name)

        if self.klass != other.klass: return 1
        if self.properties != other.properties: return 1
        if self.check != other.check: return 1

        # match
        return 0

class Role:
    ''' Defines a Role with the attributes
        - name
        - description
        - permissions
    '''
    def __init__(self, name='', description='', permissions=None):
        self.name = name.lower()
        self.description = description
        if permissions is None:
            permissions = []
        self.permissions = permissions

    def __repr__(self):
        return '<Role 0x%x %r,%r>'%(id(self), self.name, self.permissions)

class Security:
    def __init__(self, db):
        ''' Initialise the permission and role classes, and add in the
            base roles (for admin user).
        '''
        self.db = weakref.proxy(db)       # use a weak ref to avoid circularity

        # permssions are mapped by name to a list of Permissions by class
        self.permission = {}

        # roles are mapped by name to the Role
        self.role = {}

        # the default Roles
        self.addRole(name="User", description="A regular user, no privs")
        self.addRole(name="Admin", description="An admin user, full privs")
        self.addRole(name="Anonymous", description="An anonymous user")

        # default permissions - Admin may do anything
        for p in 'create edit retire view'.split():
            p = self.addPermission(name=p.title(),
                description="User may %s everthing"%p)
            self.addPermissionToRole('Admin', p)

        # initialise the permissions and roles needed for the UIs
        from roundup.cgi import client
        client.initialiseSecurity(self)
        from roundup import mailgw
        mailgw.initialiseSecurity(self)

    def getPermission(self, permission, classname=None, properties=None,
            check=None):
        ''' Find the Permission matching the name and for the class, if the
            classname is specified.

            Raise ValueError if there is no exact match.
        '''
        if not self.permission.has_key(permission):
            raise ValueError, 'No permission "%s" defined'%permission

        if classname:
            try:
                self.db.getclass(classname)
            except KeyError:
                raise ValueError, 'No class "%s" defined'%classname

        # look through all the permissions of the given name
        tester = Permission(permission, klass=classname, properties=properties,
            check=check)
        for perm in self.permission[permission]:
            if perm == tester:
                return perm
        raise ValueError, 'No permission "%s" defined for "%s"'%(permission,
            classname)

    def hasPermission(self, permission, userid, classname=None,
            property=None, itemid=None):
        '''Look through all the Roles, and hence Permissions, and
           see if "permission" exists given the constraints of
           classname, property and itemid.

           If classname is specified (and only classname) then the
           search will match if there is *any* Permission for that
           classname, even if the Permission has additional
           constraints.

           If property is specified, the Permission matched must have
           either no properties listed or the property must appear in
           the list.

           If itemid is specified, the Permission matched must have
           either no check function defined or the check function,
           when invoked, must return a True value.

           Note that this functionality is actually implemented by the
           Permission.test() method.
        '''
        if itemid and classname is None:
            raise ValueError, 'classname must accompany itemid'
        for rolename in self.db.user.get_roles(userid):
            if not rolename or not self.role.has_key(rolename):
                continue
            # for each of the user's Roles, check the permissions
            for perm in self.role[rolename].permissions:
                # permission match?
                if perm.test(self.db, permission, classname, property,
                        userid, itemid):
                    return 1
        return 0

    def addPermission(self, **propspec):
        ''' Create a new Permission with the properties defined in
            'propspec'. See the Permission class for the possible
            keyword args.
        '''
        perm = Permission(**propspec)
        self.permission.setdefault(perm.name, []).append(perm)
        return perm

    def addRole(self, **propspec):
        ''' Create a new Role with the properties defined in 'propspec'
        '''
        role = Role(**propspec)
        self.role[role.name] = role
        return role

    def addPermissionToRole(self, rolename, permission, classname=None,
            properties=None, check=None):
        ''' Add the permission to the role's permission list.

            'rolename' is the name of the role to add the permission to.

            'permission' is either a Permission *or* a permission name
            accompanied by 'classname' (thus in the second case a Permission
            is obtained by passing 'permission' and 'classname' to
            self.getPermission)
        '''
        if not isinstance(permission, Permission):
            permission = self.getPermission(permission, classname,
                properties, check)
        role = self.role[rolename.lower()]
        role.permissions.append(permission)

# vim: set filetype=python sts=4 sw=4 et si :
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.