Skip to content

Commit 3a6b418

Browse files
author
Richard Jones
committed
Removed the unnecessary volatiledb and the related complications.
Security much simpler and self-contained now.
1 parent 0879fd4 commit 3a6b418

File tree

5 files changed

+71
-72
lines changed

5 files changed

+71
-72
lines changed

COPYING.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
Copyright (c) 2002 eKit.com Inc (http://www.ekit.com/)
32

43
Permission is hereby granted, free of charge, to any person obtaining a copy

TODO.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ pending hyperdb: range searching of values (dates in particular)
1212
[value, value, ...] implies "in"
1313
pending hyperdb: make creator, creation and activity available pre-commit
1414
pending hyperdb: migrate "id" property to be Number type
15+
active hyperdb: modify design document to include all the changes made
1516
pending instance: including much simpler upgrade path and the use of
1617
non-Python configuration files (ConfigParser)
1718
pending instance: cleanup to support config (feature request #498658)
@@ -29,8 +30,7 @@ pending mailgw: Allow multiple email addresses at one gw with different default
2930
roundup: "|roundup-mailgw /instances/dev"
3031
vmbugs: "|roundup-mailgw /instances/dev component=voicemail"
3132
pending project: switch to a Roundup instance for Roundup bug/feature tracking
32-
active security: finish doc/security.txt
33-
active security: implement and use the new logical control mechanisms
33+
active security: add info from doc/security.txt to design doc
3434
pending security: at least an LDAP user database implementation
3535
pending security: authenticate over a secure connection
3636
pending security: use digital signatures in mailgw
@@ -54,5 +54,6 @@ done hyperdb: fix the journal bloat (RJ)
5454
done hyperdb: add Boolean and Number types (GM)
5555
done mailgw: better help message (feature request #558562) (RJ)
5656
done security: switch to sessions for web authentication (RJ)
57+
done security: implement and use the new logical control mechanisms
5758
done web: saving of named queries (GM)
5859

roundup/security.py

Lines changed: 52 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,53 @@
11
import weakref
22

3-
from roundup import hyperdb, volatiledb
3+
from roundup import hyperdb
44

5-
class PermissionClass(volatiledb.VolatileClass):
6-
''' Include the default attributes:
7-
- name (String)
8-
- classname (String)
9-
- description (String)
5+
class Permission:
6+
''' Defines a Permission with the attributes
7+
- name
8+
- description
9+
- klass (optional)
1010
11-
The classname may be unset, indicating that this permission is not
11+
The klass may be unset, indicating that this permission is not
1212
locked to a particular class. That means there may be multiple
1313
Permissions for the same name for different classes.
1414
'''
15-
def __init__(self, db, classname, **properties):
16-
""" set up the default properties
17-
"""
18-
if not properties.has_key('name'):
19-
properties['name'] = hyperdb.String()
20-
if not properties.has_key('klass'):
21-
properties['klass'] = hyperdb.String()
22-
if not properties.has_key('description'):
23-
properties['description'] = hyperdb.String()
24-
volatiledb.VolatileClass.__init__(self, db, classname, **properties)
25-
26-
class RoleClass(volatiledb.VolatileClass):
27-
''' Include the default attributes:
28-
- name (String, key)
29-
- description (String)
30-
- permissions (PermissionClass Multilink)
15+
def __init__(self, name='', description='', klass=None):
16+
self.name = name
17+
self.description = description
18+
self.klass = klass
19+
20+
def __repr__(self):
21+
return '<Permission 0x%x %r,%r>'%(id(self), self.name, self.klass)
22+
23+
class Role:
24+
''' Defines a Role with the attributes
25+
- name
26+
- description
27+
- permissions
3128
'''
32-
def __init__(self, db, classname, **properties):
33-
""" set up the default properties
34-
"""
35-
if not properties.has_key('name'):
36-
properties['name'] = hyperdb.String()
37-
if not properties.has_key('description'):
38-
properties['description'] = hyperdb.String()
39-
if not properties.has_key('permissions'):
40-
properties['permissions'] = hyperdb.Multilink('permission')
41-
volatiledb.VolatileClass.__init__(self, db, classname, **properties)
42-
self.setkey('name')
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
35+
36+
def __repr__(self):
37+
return '<Role 0x%x %r,%r>'%(id(self), self.name, self.permissions)
4338

4439
class Security:
4540
def __init__(self, db):
4641
''' Initialise the permission and role classes, and add in the
4742
base roles (for admin user).
4843
'''
49-
# use a weak ref to avoid circularity
50-
self.db = weakref.proxy(db)
44+
self.db = weakref.proxy(db) # use a weak ref to avoid circularity
5145

52-
# create the permission class instance (we only need one))
53-
self.permission = PermissionClass(db, "permission")
46+
# permssions are mapped by name to a list of Permissions by class
47+
self.permission = {}
5448

55-
# create the role class instance (we only need one)
56-
self.role = RoleClass(db, "role")
49+
# roles are mapped by name to the Role
50+
self.role = {}
5751

5852
# the default Roles
5953
self.addRole(name="User", description="A regular user, no privs")
@@ -82,35 +76,28 @@ def getPermission(self, permission, classname=None):
8276
8377
Raise ValueError if there is no exact match.
8478
'''
85-
perm = self.db.permission
86-
for permissionid in perm.stringFind(name=permission):
87-
klass = perm.get(permissionid, 'klass')
88-
if classname is not None and classname == klass:
89-
return permissionid
90-
elif not classname and not klass:
91-
return permissionid
92-
if not classname:
79+
if not self.permission.has_key(permission):
9380
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
9486
raise ValueError, 'No permission "%s" defined for "%s"'%(permission,
9587
classname)
9688

9789
def hasPermission(self, permission, userid, classname=None):
9890
''' Look through all the Roles, and hence Permissions, and see if
9991
"permission" is there for the specified classname.
100-
10192
'''
10293
roles = self.db.user.get(userid, 'roles')
10394
if roles is None:
10495
return 0
10596
for rolename in roles.split(','):
10697
if not rolename:
10798
continue
108-
roleid = self.db.role.lookup(rolename)
109-
for permissionid in self.db.role.get(roleid, 'permissions'):
110-
if self.db.permission.get(permissionid, 'name') != permission:
111-
continue
112-
klass = self.db.permission.get(permissionid, 'klass')
113-
if klass is None or klass == classname:
99+
for perm in self.role[rolename].permissions:
100+
if perm.klass is None or perm.klass == classname:
114101
return 1
115102
return 0
116103

@@ -142,20 +129,22 @@ def addPermission(self, **propspec):
142129
''' Create a new Permission with the properties defined in
143130
'propspec'
144131
'''
145-
return self.db.permission.create(**propspec)
132+
perm = Permission(**propspec)
133+
self.permission.setdefault(perm.name, []).append(perm)
134+
return perm
146135

147136
def addRole(self, **propspec):
148137
''' Create a new Role with the properties defined in 'propspec'
149138
'''
150-
return self.db.role.create(**propspec)
139+
role = Role(**propspec)
140+
self.role[role.name] = role
141+
return role
151142

152-
def addPermissionToRole(self, rolename, permissionid):
143+
def addPermissionToRole(self, rolename, permission):
153144
''' Add the permission to the role's permission list.
154145
155-
'rolename' is the name of the role to add 'permissionid'.
146+
'rolename' is the name of the role to add the permission to.
156147
'''
157-
roleid = self.db.role.lookup(rolename)
158-
permissions = self.db.role.get(roleid, 'permissions')
159-
permissions.append(permissionid)
160-
self.db.role.set(roleid, permissions=permissions)
148+
role = self.role[rolename]
149+
role.permissions.append(permission)
161150

test/test_init.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
1616
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
1717
#
18-
# $Id: test_init.py,v 1.14 2002-07-26 08:27:00 richard Exp $
18+
# $Id: test_init.py,v 1.15 2002-07-29 00:56:06 richard Exp $
1919

2020
import unittest, os, shutil, errno, imp, sys
2121

@@ -91,7 +91,7 @@ def testCreation(self):
9191
l = db.keyword.list()
9292
ae(l, [])
9393
l = db.user.list()
94-
ae(l, ['1'])
94+
ae(l, ['1', '2'])
9595
l = db.msg.list()
9696
ae(l, [])
9797
l = db.file.list()
@@ -155,6 +155,11 @@ def suite():
155155

156156
#
157157
# $Log: not supported by cvs2svn $
158+
# Revision 1.14 2002/07/26 08:27:00 richard
159+
# Very close now. The cgi and mailgw now use the new security API. The two
160+
# templates have been migrated to that setup. Lots of unit tests. Still some
161+
# issue in the web form for editing Roles assigned to users.
162+
#
158163
# Revision 1.13 2002/07/14 02:05:54 richard
159164
# . all storage-specific code (ie. backend) is now implemented by the backends
160165
#

test/test_mailgw.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
# but WITHOUT ANY WARRANTY; without even the implied warranty of
99
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1010
#
11-
# $Id: test_mailgw.py,v 1.24 2002-07-26 08:27:00 richard Exp $
11+
# $Id: test_mailgw.py,v 1.25 2002-07-29 00:56:06 richard Exp $
1212

1313
import unittest, cStringIO, tempfile, os, shutil, errno, imp, sys, difflib
1414

@@ -633,8 +633,8 @@ def testNosyRemove(self):
633633

634634
def testNewUserAuthor(self):
635635
# first without the permission
636-
Anonid = self.db.role.lookup('Anonymous')
637-
self.db.role.set(Anonid, permissions=[])
636+
# heh... just ignore the API for a second ;)
637+
self.db.security.role['Anonymous'].permissions=[]
638638
anonid = self.db.user.lookup('anonymous')
639639
self.db.user.set(anonid, roles='Anonymous')
640640

@@ -660,7 +660,7 @@ def testNewUserAuthor(self):
660660

661661
# now with the permission
662662
p = self.db.security.getPermission('Email Registration')
663-
self.db.role.set(Anonid, permissions=[p])
663+
self.db.security.role['Anonymous'].permissions=[p]
664664
handler = self.instance.MailGW(self.instance, self.db)
665665
handler.trapExceptions = 0
666666
message = cStringIO.StringIO(s)
@@ -781,6 +781,11 @@ def suite():
781781

782782
#
783783
# $Log: not supported by cvs2svn $
784+
# Revision 1.24 2002/07/26 08:27:00 richard
785+
# Very close now. The cgi and mailgw now use the new security API. The two
786+
# templates have been migrated to that setup. Lots of unit tests. Still some
787+
# issue in the web form for editing Roles assigned to users.
788+
#
784789
# Revision 1.23 2002/07/14 02:02:43 richard
785790
# Fixed the unit tests for the new multilist controls in the mailgw
786791
#

0 commit comments

Comments
 (0)