X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=doc%2Fsecurity.txt;h=93c64f9e852adddee22018f301bd9dc8b71fc6a7;hb=3f4c0b8e3c4cd4da683b6ffa27ea58b42f2c564c;hp=c36540eb6db394b2c34f629ef675b5871c7a098a;hpb=f19e7faa0483c81c92141c84639ca8fea4d2811d;p=roundup.git diff --git a/doc/security.txt b/doc/security.txt index c36540e..93c64f9 100644 --- a/doc/security.txt +++ b/doc/security.txt @@ -2,7 +2,7 @@ Security Mechanisms =================== -:Version: $Revision: 1.10 $ +:Version: $Revision: 1.15 $ Current situation ================= @@ -41,6 +41,9 @@ Issues than the From address. Support for strong identification through digital signatures should be added. 5. The command-line tool has no logical controls. +6. The anonymous control needs revising - there should only be one way to be + an anonymous user, not two (currently there is user==None and + user=='anonymous'). Possible approaches @@ -99,7 +102,6 @@ Cons: - most user interfaces have multiple uses which can't be covered by a single permission - Logical control --------------- @@ -121,202 +123,6 @@ Cons: that implements the logical controls. -Applying controls to users -========================== - -Individual assignment of Permission to User is unwieldy. The concept of a -Role, which encompasses several Permissions and may be assigned to many Users, -is quite well developed in many projects. Roundup will take this path, and -allow the multiple assignment of Roles to Users, and multiple Permissions to -Roles. These definitions will be stored in the hyperdb. They don't need to be -pushed to the actual database though. - -There will be two levels of Permission. The Class level permissions define -logical permissions associated with all nodes of a particular class (or all -classes). The Node level permissions define logical permissions associated -with specific nodes by way of their user-linked properties. - -A permission module defines:: - - class InMemoryImmutableClass(hyperdb.Class): - ''' Don't allow changes to this class's nodes. - ''' - def __init__(self, db, classname, **properties): - ''' Set up an in-memory store for the nodes of this class - ''' - - def create(self, **propvalues): - ''' Create a new node in the in-memory store - ''' - - def get(self, nodeid, propname, default=_marker, cache=1): - ''' Get the node from the in-memory store - ''' - - def set(self, *args): - raise ValueError, "%s are immutable"%self.__class__.__name__ - - class PermissionClass(InMemoryImmutableClass): - ''' 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. - ''' - - class RoleClass(InMemoryImmutableClass): - ''' Include the default attributes: - - name (String, key) - - description (String) - - permissions (PermissionClass Multilink) - ''' - - 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="No Rego", - description="A user who can't register") - - ee = self.addPermission(name="Edit", - description="User may edit everthing") - self.addPermissionToRole('Admin', ee) - ae = self.addPermission(name="Assign", - description="User may be assigned to anything") - self.addPermissionToRole('Admin', ae) - - def hasClassPermission(self, db, classname, permission, userid): - ''' Look through all the Roles, and hence Permissions, and see if - "permission" is there for the specified classname. - - ''' - - def hasNodePermission(self, db, classname, nodeid, userid, properties): - ''' 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 list of property names. The property - names must be the name of a property of classname, or a - KeyError is raised. That property must be a Link or Multilink - property, or a TypeError is raised. - - If the property is a Link, the userid must match the property - value. If the property is a Multilink, the userid must appear - in the Multilink list. - ''' - - def addPermission(self, **propspec): - ''' Create a new Permission with the properties defined in - 'propspec' - ''' - - def addRole(self, **propspec): - ''' Create a new Role with the properties defined in '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'. - ''' - -Modules such as ``cgi_client.py`` and ``mailgw.py`` define their own -permissions like so (this example is ``cgi_client.py``):: - - # XXX GAH. If the permissions are instance-db-specific then this can't - # work! - from roundup import permission - - # create some Permissions - newid = permission.addPermission(name="Web Access", - description="User may use the web interface") - permission.addToRole('User', newid) - permission.addToRole('No Rego', newid) - newid = permission.addPermission(name="Web Registration", - description="User may register through the web") - permission.addToRole('User', newid) - # XXX GAH! - -The instance dbinit module then has in ``open()``:: - - # open the database - it must be modified to init the Security class - # from permissions.py as db.security - db = Database(instance_config, name) - - # add some extra permissions and associate them with roles - ei = db.security.addPermission(name="Edit", classname="issue", - description="User is allowed to edit issues") - db.security.addPermissionToRole('User', ei) - ai = db.security.addPermission(name="Assign", classname="issue", - description="User may be assigned to issues") - db.security.addPermissionToRole('User', ei) - -In the dbinit ``init()``:: - - r = db.getclass('role').lookup('Admin') - user.create(username="admin", password=Password(adminpw), - address=instance_config.ADMIN_EMAIL, roles=[r]) - - # choose your anonymous user access permission here - #r = db.getclass('role').lookup('No Rego') - r = db.getclass('role').lookup('User') - user.create(username="anonymous", roles=[r]) - -Then in the code that matters, calls to ``hasPermission`` are made to -determine if the user has permission to perform some action:: - - if db.security.hasClassPermission('issue', 'Edit', self.user): - # all ok - - if db.security.hasNodePermission('issue', nodeid, self.user, - ['assignedto']): - # all ok - -The htmltemplate will implement a new tag, which has the form:: - - - HTML to display if the user has the permission. - - HTML to display if the user does not have the permission. - - -where the require attribute gives a comma-separated list of permission names -which are required, and the node attribute gives a comma-separated list of -node properties whose value must match the current user's id. Either of these -tests must pass or the permission check will fail. The section of html within -the side of the ```` that fails is remove from processing. - - -Authentication of Users ------------------------ - -Users must be authenticated correctly for the above controls to work. This is -not done in the current mail gateway at all. Use of digital signing of -messages could alleviate this problem. - -The exact mechanism of registering the digital signature should be flexible, -with perhaps a level of trust. Users who supply their signature through their -first message into the tracker should be at a lower level of trust to those -who supply their signature to an admin for submission to their user details. - - Action ====== @@ -333,6 +139,7 @@ The CGI interface must be changed to: - implement htmltemplate tests on permissions - switch all code over from using config vars for permission checks to using permissions + - change all explicit admin user checks for Role checks - include config vars for initial Roles for anonymous web, new web and new email users @@ -350,19 +157,3 @@ The command-line tool must be changed to: access by admin users, and read-only by everyone else) -Use cases -========= - -public - end users that can submit bugs, request new features, request support -developer - developers that can fix bugs, implement new features provide support -manager - approvers/managers that can approve new features and signoff bug fixes -admin - administrators that can add users and set user's roles -system - automated request handlers running various report/escalation scripts -privacy - issues that are only visible to some users -