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)