view doc/security.txt @ 741:b48a19a88b65

Cleanup
author Richard Jones <richard@users.sourceforge.net>
date Thu, 23 May 2002 03:35:34 +0000
parents d341cd0e7689
children 811475894dd9
line wrap: on
line source

===================
Security Mechanisms
===================

:Version: $Revision: 1.2 $

Current situation
=================

Current logical controls:

ANONYMOUS_ACCESS = 'deny'
 Deny or allow anonymous access to the web interface
ANONYMOUS_REGISTER = 'deny'
 Deny or allow anonymous users to register through the web interface
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,
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
======

1. The current implementation is ad-hoc, and not complete for all `use cases`_.
2. Currently it is not possible to allow submission of issues through email
   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.


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.
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.

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
through the database, we can implement deny by default.

Pros:

   - easier to implement as it only affects one module
   - smaller number of permissions to worry about

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,
     having private messages)


User-interface control
----------------------

The user interfaces would have an extra layer between that which
parses the request to determine action and the action method. This layer
controls access. Since it is possible to require methods be registered
with the security mechanisms to be accessed by the user, deny by default
is possible.

Pros:

   - much more obvious at the user level what the controls are

Cons:

   - much more work to implement
   - most user interfaces have multiple uses which can't be covered by a
     single permission


Logical control
---------------

At each point that requires an action to be performed, the security mechanisms
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

Cons:

   - large number of possible permissions that may be defined, possibly
     mirroring actual user interface 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.


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


Roundup Issue Tracker: http://roundup-tracker.org/