Code

Removed the unnecessary volatiledb and the related complications. Security
[roundup.git] / roundup / security.py
1 import weakref
3 from roundup import hyperdb
5 class Permission:
6     ''' Defines a Permission with the attributes
7         - name
8         - description
9         - klass (optional)
11         The klass may be unset, indicating that this permission is not
12         locked to a particular class. That means there may be multiple
13         Permissions for the same name for different classes.
14     '''
15     def __init__(self, name='', description='', klass=None):
16         self.name = name
17         self.description = description
18         self.klass = klass
20     def __repr__(self):
21         return '<Permission 0x%x %r,%r>'%(id(self), self.name, self.klass)
23 class Role:
24     ''' Defines a Role with the attributes
25         - name
26         - description
27         - permissions
28     '''
29     def __init__(self, name='', description='', permissions=None):
30         self.name = name
31         self.description = description
32         if permissions is None:
33             permissions = []
34         self.permissions = permissions
36     def __repr__(self):
37         return '<Role 0x%x %r,%r>'%(id(self), self.name, self.permissions)
39 class Security:
40     def __init__(self, db):
41         ''' Initialise the permission and role classes, and add in the
42             base roles (for admin user).
43         '''
44         self.db = weakref.proxy(db)       # use a weak ref to avoid circularity
46         # permssions are mapped by name to a list of Permissions by class
47         self.permission = {}
49         # roles are mapped by name to the Role
50         self.role = {}
52         # the default Roles
53         self.addRole(name="User", description="A regular user, no privs")
54         self.addRole(name="Admin", description="An admin user, full privs")
55         self.addRole(name="Anonymous", description="An anonymous user")
57         ee = self.addPermission(name="Edit",
58             description="User may edit everthing")
59         self.addPermissionToRole('Admin', ee)
60         ae = self.addPermission(name="View",
61             description="User may access everything")
62         self.addPermissionToRole('Admin', ae)
63         reg = self.addPermission(name="Register Web",
64             description="User may register through the web")
65         reg = self.addPermission(name="Register Email",
66             description="User may register through the email")
68         # initialise the permissions and roles needed for the UIs
69         from roundup import cgi_client, mailgw
70         cgi_client.initialiseSecurity(self)
71         mailgw.initialiseSecurity(self)
73     def getPermission(self, permission, classname=None):
74         ''' Find the Permission matching the name and for the class, if the
75             classname is specified.
77             Raise ValueError if there is no exact match.
78         '''
79         if not self.permission.has_key(permission):
80             raise ValueError, 'No permission "%s" defined'%permission
81         for perm in self.permission[permission]:
82             if perm.klass is not None and perm.klass == classname:
83                 return perm
84             elif not perm.klass and not classname:
85                 return perm
86         raise ValueError, 'No permission "%s" defined for "%s"'%(permission,
87             classname)
89     def hasPermission(self, permission, userid, classname=None):
90         ''' Look through all the Roles, and hence Permissions, and see if
91             "permission" is there for the specified classname.
92         '''
93         roles = self.db.user.get(userid, 'roles')
94         if roles is None:
95             return 0
96         for rolename in roles.split(','):
97             if not rolename:
98                 continue
99             for perm in self.role[rolename].permissions:
100                 if perm.klass is None or perm.klass == classname:
101                     return 1
102         return 0
104     def hasNodePermission(self, classname, nodeid, **propspec):
105         ''' Check the named properties of the given node to see if the
106             userid appears in them. If it does, then the user is granted
107             this permission check.
109             'propspec' consists of a set of properties and values that
110             must be present on the given node for access to be granted.
112             If a property is a Link, the value must match the property
113             value. If a property is a Multilink, the value must appear
114             in the Multilink list.
115         '''
116         klass = self.db.getclass(classname)
117         properties = klass.getprops()
118         for k,v in propspec.items():
119             value = klass.get(nodeid, k)
120             if isinstance(properties[k], hyperdb.Multilink):
121                 if v not in value:
122                     return 0
123             else:
124                 if v != value:
125                     return 0
126         return 1
128     def addPermission(self, **propspec):
129         ''' Create a new Permission with the properties defined in
130             'propspec'
131         '''
132         perm = Permission(**propspec)
133         self.permission.setdefault(perm.name, []).append(perm)
134         return perm
136     def addRole(self, **propspec):
137         ''' Create a new Role with the properties defined in 'propspec'
138         '''
139         role = Role(**propspec)
140         self.role[role.name] = role
141         return role
143     def addPermissionToRole(self, rolename, permission):
144         ''' Add the permission to the role's permission list.
146             'rolename' is the name of the role to add the permission to.
147         '''
148         role = self.role[rolename]
149         role.permissions.append(permission)