diff --git a/doc/security.txt b/doc/security.txt
index c36540eb6db394b2c34f629ef675b5871c7a098a..93c64f9e852adddee22018f301bd9dc8b71fc6a7 100644 (file)
--- a/doc/security.txt
+++ b/doc/security.txt
Security Mechanisms
===================
Security Mechanisms
===================
-:Version: $Revision: 1.10 $
+:Version: $Revision: 1.15 $
Current situation
=================
Current situation
=================
than the From address. Support for strong identification through digital
signatures should be added.
5. The command-line tool has no logical controls.
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
Possible approaches
- most user interfaces have multiple uses which can't be covered by a
single permission
- most user interfaces have multiple uses which can't be covered by a
single permission
-
Logical control
---------------
Logical control
---------------
that implements the logical controls.
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, <permission> which has the form::
-
- <permission require=name,name,name node=assignedto>
- HTML to display if the user has the permission.
- <else>
- HTML to display if the user does not have the permission.
- </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 ``<else>`` 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
======
Action
======
- implement htmltemplate tests on permissions
- switch all code over from using config vars for permission checks to using
permissions
- 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
- include config vars for initial Roles for anonymous web, new web and new
email users
access by admin users, and read-only by everyone else)
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
-