view roundup/security.py @ 905:502a5ae11cc5

Very close now. The cgi and mailgw now use the new security API. The two templates have been migrated to that setup. Lots of unit tests. Still some issue in the web form for editing Roles assigned to users.
author Richard Jones <richard@users.sourceforge.net>
date Fri, 26 Jul 2002 08:27:00 +0000
parents b0d3d3535998
children a8d80ffe37cc
line wrap: on
line source

import weakref

from roundup import hyperdb, volatiledb

class PermissionClass(volatiledb.VolatileClass):
    ''' Include the default attributes:
        - name (String)
        - classname (String)
        - description (String)

        The classname 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.
    '''
    def __init__(self, db, classname, **properties):
        """ set up the default properties
        """
        if not properties.has_key('name'):
            properties['name'] = hyperdb.String()
        if not properties.has_key('klass'):
            properties['klass'] = hyperdb.String()
        if not properties.has_key('description'):
            properties['description'] = hyperdb.String()
        volatiledb.VolatileClass.__init__(self, db, classname, **properties)

class RoleClass(volatiledb.VolatileClass):
    ''' Include the default attributes:
        - name (String, key)
        - description (String)
        - permissions (PermissionClass Multilink)
    '''
    def __init__(self, db, classname, **properties):
        """ set up the default properties
        """
        if not properties.has_key('name'):
            properties['name'] = hyperdb.String()
        if not properties.has_key('description'):
            properties['description'] = hyperdb.String()
        if not properties.has_key('permissions'):
            properties['permissions'] = hyperdb.Multilink('permission')
        volatiledb.VolatileClass.__init__(self, db, classname, **properties)
        self.setkey('name')

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

        # create the permission class instance (we only need one))
        self.permission = PermissionClass(db, "permission")

        # create the role class instance (we only need one)
        self.role = RoleClass(db, "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")

        ee = self.addPermission(name="Edit",
            description="User may edit everthing")
        self.addPermissionToRole('Admin', ee)
        ae = self.addPermission(name="View",
            description="User may access everything")
        self.addPermissionToRole('Admin', ae)
        reg = self.addPermission(name="Register Web",
            description="User may register through the web")
        reg = self.addPermission(name="Register Email",
            description="User may register through the email")

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

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

            Raise ValueError if there is no exact match.
        '''
        perm = self.db.permission
        for permissionid in perm.stringFind(name=permission):
            klass = perm.get(permissionid, 'klass')
            if classname is not None and classname == klass:
                return permissionid
            elif not classname and not klass:
                return permissionid
        if not classname:
            raise ValueError, 'No permission "%s" defined'%permission
        raise ValueError, 'No permission "%s" defined for "%s"'%(permission,
            classname)

    def hasPermission(self, permission, userid, classname=None):
        ''' Look through all the Roles, and hence Permissions, and see if
            "permission" is there for the specified classname.

        '''
        roles = self.db.user.get(userid, 'roles')
        if roles is None:
            return 0
        for rolename in roles.split(','):
            if not rolename:
                continue
            roleid = self.db.role.lookup(rolename)
            for permissionid in self.db.role.get(roleid, 'permissions'):
                if self.db.permission.get(permissionid, 'name') != permission:
                    continue
                klass = self.db.permission.get(permissionid, 'klass')
                if klass is None or klass == classname:
                    return 1
        return 0

    def hasNodePermission(self, classname, nodeid, **propspec):
        ''' Check the named properties of the given node to see if the
            userid appears in them. If it does, then the user is granted
            this permission check.

            'propspec' consists of a set of properties and values that
            must be present on the given node for access to be granted.

            If a property is a Link, the value must match the property
            value. If a property is a Multilink, the value must appear
            in the Multilink list.
        '''
        klass = self.db.getclass(classname)
        properties = klass.getprops()
        for k,v in propspec.items():
            value = klass.get(nodeid, k)
            if isinstance(properties[k], hyperdb.Multilink):
                if v not in value:
                    return 0
            else:
                if v != value:
                    return 0
        return 1

    def addPermission(self, **propspec):
        ''' Create a new Permission with the properties defined in
            'propspec'
        '''
        return self.db.permission.create(**propspec)

    def addRole(self, **propspec):
        ''' Create a new Role with the properties defined in 'propspec'
        '''
        return self.db.role.create(**propspec)

    def addPermissionToRole(self, rolename, permissionid):
        ''' Add the permission to the role's permission list.

            'rolename' is the name of the role to add 'permissionid'.
        '''
        roleid = self.db.role.lookup(rolename)
        permissions = self.db.role.get(roleid, 'permissions')
        permissions.append(permissionid)
        self.db.role.set(roleid, permissions=permissions)


Roundup Issue Tracker: http://roundup-tracker.org/