Code

f34892ee9701716868545540820c70bc2ed59705
[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
82         # look through all the permissions of the given name
83         for perm in self.permission[permission]:
84             # if we're passed a classname, the permission must match
85             if perm.klass is not None and perm.klass == classname:
86                 return perm
87             # otherwise the permission klass must be unset
88             elif not perm.klass and not classname:
89                 return perm
90         raise ValueError, 'No permission "%s" defined for "%s"'%(permission,
91             classname)
93     def hasPermission(self, permission, userid, classname=None):
94         ''' Look through all the Roles, and hence Permissions, and see if
95             "permission" is there for the specified classname.
96         '''
97         roles = self.db.user.get(userid, 'roles')
98         if roles is None:
99             return 0
100         for rolename in roles.split(','):
101             if not rolename:
102                 continue
103             # for each of the user's Roles, check the permissions
104             for perm in self.role[rolename].permissions:
105                 # permission name match?
106                 if perm.name == permission:
107                     # permission klass match?
108                     if perm.klass is None or perm.klass == classname:
109                         # we have a winner
110                         return 1
111         return 0
113     def hasNodePermission(self, classname, nodeid, **propspec):
114         ''' Check the named properties of the given node to see if the
115             userid appears in them. If it does, then the user is granted
116             this permission check.
118             'propspec' consists of a set of properties and values that
119             must be present on the given node for access to be granted.
121             If a property is a Link, the value must match the property
122             value. If a property is a Multilink, the value must appear
123             in the Multilink list.
124         '''
125         klass = self.db.getclass(classname)
126         properties = klass.getprops()
127         for k,v in propspec.items():
128             value = klass.get(nodeid, k)
129             if isinstance(properties[k], hyperdb.Multilink):
130                 if v not in value:
131                     return 0
132             else:
133                 if v != value:
134                     return 0
135         return 1
137     def addPermission(self, **propspec):
138         ''' Create a new Permission with the properties defined in
139             'propspec'
140         '''
141         perm = Permission(**propspec)
142         self.permission.setdefault(perm.name, []).append(perm)
143         return perm
145     def addRole(self, **propspec):
146         ''' Create a new Role with the properties defined in 'propspec'
147         '''
148         role = Role(**propspec)
149         self.role[role.name] = role
150         return role
152     def addPermissionToRole(self, rolename, permission):
153         ''' Add the permission to the role's permission list.
155             'rolename' is the name of the role to add the permission to.
156         '''
157         role = self.role[rolename]
158         role.permissions.append(permission)