Code

various updates
[roundup.git] / doc / security.txt
index c25fca89287081c26a47658e9780316a475b08b6..10dedbab868494510de25ac9f981dd1d27ac26b4 100644 (file)
@@ -2,7 +2,7 @@
 Security Mechanisms
 ===================
 
-:Version: $Revision: 1.2 $
+:Version: $Revision: 1.16 $
 
 Current situation
 =================
@@ -16,14 +16,20 @@ ANONYMOUS_REGISTER = 'deny'
 ANONYMOUS_REGISTER_MAIL = 'deny'
  Deny or allow anonymous users to register through the mail interface
 
-The web interface implements another level of user-interface security,
+Current user interface authentication and controls:
+
+- command-line tool access controlled with passwords, but no logical controls
+- CGI access is by username and password and has some logical controls
+- mailgw access is through identification using sender email address, with
+  limited functionality available
+
+The web interface implements has specific logical controls,
 preventing non-admin users from accessing:
 
  - other user's details pages
  - listing the base classes (not issues or their user page)
  - editing base classes
 
-
 Issues
 ======
 
@@ -32,7 +38,12 @@ Issues
    but restrict those users from accessing the web interface.
 3. Only one user may perform admin functions.
 4. There is no verification of users in the mail gateway by any means other
-   than the From address. Support for strong signatures should be added.
+   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
@@ -40,8 +51,8 @@ Possible approaches
 
 Security controls in Roundup could be approached in three ways:
 
-1) at the hyperdb level, with read/write/modify permissions on classes, nodes
-   and node properties for all or specific transitions.
+1) at the hyperdb level, with read/write/modify permissions on classes, items
+   and item properties for all or specific transitions.
 2) at the user interface level, with access permissions on CGI interface
    methods, mailgw methods, roundup-admin methods, and so on.
 3) at a logical permission level, checked as needed.
@@ -50,11 +61,12 @@ In all cases, the security built into roundup assumes restricted access to the
 hyperdatabase itself, through Operating System controls such as user or group
 permissions.
 
+
 Hyperdb-level control
 ---------------------
 
 Control is implemented at the Class.get, Class.set and Class.create level. All
-other methods must access nodes through these methods. Since all accesses go
+other methods must access items through these methods. Since all accesses go
 through the database, we can implement deny by default.
 
 Pros:
@@ -67,7 +79,7 @@ Cons:
    - harder to determine the relationship between user interaction and hyperdb
      permission.
    - a lot of work to define
-   - must special-case to handle by-node permissions (editing user details,
+   - must special-case to handle by-item permissions (editing user details,
      having private messages)
 
 
@@ -90,7 +102,6 @@ Cons:
    - most user interfaces have multiple uses which can't be covered by a
      single permission
 
-
 Logical control
 ---------------
 
@@ -99,123 +110,50 @@ are asked if the current user has permission. Since code must call the
 check function to raise a denial, there is no possibility to have automatic
 default of deny in this situation.
 
-In practice, this is implemented as:
-
-1. there's a mapping of user -> role          (in hyperdb)
-2. there's a mapping of role -> permission    (in code)
-3. there's a function that's available to all roundup code that can ask
-   whether a particular user has a particular permission.
-
 Pros:
 
    - quite obvious what is going on
-   - is the current system
+   - is very similar to the current system
 
 Cons:
 
    - large number of possible permissions that may be defined, possibly
      mirroring actual user interface controls.
+   - access to the hyperdb must be strictly controlled through program code
+     that implements the logical controls.
+
+
+Action
+======
+
+The CGI interface must be changed to:
+
+- authenticate over a secure connection
+- use unique tokens as a result of authentication, rather than pass the user's
+  real credentials (username/password) around for each request (this means
+  sessions and hence a session database)
+- use the new logical control mechanisms
+
+  - implement the permission module
+  - implement a Role editing interface for users
+  - 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
+
+The mail gateway must be changed to:
+
+- use digital signatures
+- use the new logical control mechanisms
+
+  - switch all code over from using config vars for permission checks to using
+    permissions
+
+The command-line tool must be changed to:
 
+- use the new logical control mechanisms (only allowing write
+  access by admin users, and read-only by everyone else)
 
-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.
-
-
-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, key)
-            - description (String)
-        '''
-
-    class RoleClass(InMemoryImmutableClass):
-        ''' Include the default attributes:
-            - name (String, key)
-            - description (String)
-            - permissions (PermissionClass Multilink)
-        '''
-
-    def hasPermission(db, userid, permission):
-        ''' Look through all the Roles, and hence Permissions, and see if
-            "permission" is there
-        '''
-
-
-The instance dbinit module then has::
-
-  in open():
-
-    perm = permission.PermissionClass(db, "permission")
-    role = permission.RoleClass(db, "role")
-
-    wa = perm.create(name="Web Access",
-                    description="User may log in through the web")
-    wr = perm.create(name="Web Registration",
-                    description="User may register through the web")
-    ma = perm.create(name="Mail Access",
-                    description="User may log in through email")
-    mr = perm.create(name="Mail Registration",
-                    description="User may register through email")
-    aa = perm.create(name="Access Everything",
-                    description="User may access everthing")
-    role.create(name="User", description="A regular user, no privs",
-                permissions=[wa, wr, ma, mr])
-    role.create(name="Admin", description="An admin user, full privs",
-                permissions=[aa])
-    ro = role.create(name="No Rego", description="A user who can't register",
-                     permissions=[wa, ma])
-
-  in init():
-
-    r = db.getclass('role').find('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').find('No Rego')
-    r = db.getclass('role').find('User')
-    user.create(username="anonymous", roles=[r])
-
-    
-
-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