summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 8a126f4)
raw | patch | inline | side by side (parent: 8a126f4)
author | richard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2> | |
Mon, 29 Jul 2002 23:30:14 +0000 (23:30 +0000) | ||
committer | richard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2> | |
Mon, 29 Jul 2002 23:30:14 +0000 (23:30 +0000) |
git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@926 57a73879-2fb5-44c3-a270-3262357dd7e2
TODO.txt | patch | blob | history | |
doc/customizing.txt | patch | blob | history | |
doc/design.txt | patch | blob | history | |
doc/security.txt | patch | blob | history | |
roundup/hyperdb.py | patch | blob | history |
diff --git a/TODO.txt b/TODO.txt
index 2a0c3069438132a56a90daa000bef97268979882..8e918a287a3c2fe5d230cd4f1f6468cf4188bce6 100644 (file)
--- a/TODO.txt
+++ b/TODO.txt
[value, value, ...] implies "in"
pending hyperdb: make creator, creation and activity available pre-commit
pending hyperdb: migrate "id" property to be Number type
-active hyperdb: modify design document to include all the changes made
pending instance: including much simpler upgrade path and the use of
non-Python configuration files (ConfigParser)
pending instance: cleanup to support config (feature request #498658)
roundup: "|roundup-mailgw /instances/dev"
vmbugs: "|roundup-mailgw /instances/dev component=voicemail"
pending project: switch to a Roundup instance for Roundup bug/feature tracking
-active security: add info from doc/security.txt to design doc
pending security: at least an LDAP user database implementation
pending security: authenticate over a secure connection
pending security: use digital signatures in mailgw
form element too, eg. how to use the nosy list edit box.
pending web: feature request #507842
pending web: clicking on a group header should filter for that type of entry
+pending web: have index page handle mid-page errors better so header and footer are
+ still visible!
ongoing any bugs
easier non-dict-like backends (eg metakit, RDB) (RJ)
done hyperdb: fix the journal bloat (RJ)
done hyperdb: add Boolean and Number types (GM)
+done hyperdb: update design document (RJ)
done mailgw: better help message (feature request #558562) (RJ)
+done security: add info from doc/security.txt to design doc (RJ)
done security: switch to sessions for web authentication (RJ)
done security: implement and use the new logical control mechanisms
done web: saving of named queries (GM)
diff --git a/doc/customizing.txt b/doc/customizing.txt
index 2f4b9dce9585124fc98e2f005f77bc3a28add531..a2ad95e8affdbbffdda9d1fc5e94ccb8befa3d78 100644 (file)
--- a/doc/customizing.txt
+++ b/doc/customizing.txt
Customising Roundup
===================
-:Version: $Revision: 1.13 $
+:Version: $Revision: 1.14 $
.. contents::
</tr>
</property>
+
+Security
+--------
+
+A set of Permissions are built in to the security module by default:
+
+- Edit (everything)
+- View (everything)
+
+The default interfaces define:
+
+- Web Registration
+- Email Registration
+
+These are hooked into the default Roles:
+
+- Admin (Edit everything, View everything)
+- User ()
+- Anonymous (Web Registration, Email Registration)
+
+And finally, the "admin" user gets the "Admin" Role, and the "anonymous" user
+gets the "Anonymous" assigned when the database is initialised on installation.
+The two default schemas then define:
+
+- Edit issue, View issue (both)
+- Edit file, View file (both)
+- Edit msg, View msg (both)
+- Edit support, View support (extended only)
+
+and assign those Permissions to the "User" Role. New users are assigned the
+Roles defined in the config file as:
+
+- NEW_WEB_USER_ROLES
+- NEW_EMAIL_USER_ROLES
+
+You may alter the configuration variables to change the Role that new web or
+email users get, for example to not give them access to the web interface if
+they register through email.
+
+
-----------------
Back to `Table of Contents`_
diff --git a/doc/design.txt b/doc/design.txt
index 69eb1aee5740293966d5fc174e9ec073b4cfd61b..2fd2ae9743d3c50183fe3b06d17760398d2caed5 100644 (file)
--- a/doc/design.txt
+++ b/doc/design.txt
Hyperdb Interface Specification
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+TODO: replace the Interface Specifications with links to the pydoc
+
The hyperdb module provides property objects to designate
the different kinds of properties. These objects are used when
specifying what properties belong in classes::
class Database:
"""A database for storing records containing flexible data types."""
- def __init__(self, storagelocator, journaltag):
+ def __init__(self, config, journaltag=None):
"""Open a hyperdatabase given a specifier to some storage.
+ The 'storagelocator' is obtained from config.DATABASE.
The meaning of 'storagelocator' depends on the particular
implementation of the hyperdatabase. It could be a file name,
a directory path, a socket descriptor for a connection to a
"""
def find(self, propname, nodeid):
- """Get the ids of nodes in this class which link to a given node.
-
+ """Get the ids of nodes in this class which link to the given nodes.
+
+ 'propspec' consists of keyword args propname={nodeid:1,}
'propname' must be the name of a property in this class, or a
KeyError is raised. That property must be a Link or Multilink
- property, or a TypeError is raised. 'nodeid' must be the id of
- an existing node in the class linked to by the given property,
- or an IndexError is raised.
+ property, or a TypeError is raised.
+
+ Any node in this class whose 'propname' property links to any of the
+ nodeids will be returned. Used by the full text indexing, which
+ knows that "foo" occurs in msg1, msg3 and file7, so we have hits
+ on these issues:
+
+ db.issue.find(messages={'1':1,'3':1}, files={'7':1})
"""
+ def filter(self, search_matches, filterspec, sort, group):
+ ''' Return a list of the ids of the active nodes in this class that
+ match the 'filter' spec, sorted by the group spec and then the
+ sort spec.
+ '''
+
def list(self):
"""Return a list of the ids of the active nodes in this class."""
is raised before any properties have been added.
"""
-TODO: additional methods
+ def getnode(self, nodeid, cache=1):
+ ''' Return a Node convenience wrapper for the node.
+
+ 'nodeid' must be the id of an existing node of this class or an
+ IndexError is raised.
+
+ 'cache' indicates whether the transaction cache should be queried
+ for the node. If the node has been modified and you need to
+ determine what its values prior to modification are, you need to
+ set cache=0.
+ '''
+
+ class Node:
+ ''' A convenience wrapper for the given node. It provides a mapping
+ interface to a single node's properties
+ '''
Hyperdatabase Implementations
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
over an existing storage mechanism. Examples are relational databases,
\*dbm key-value databases, and so on.
-TODO: finish
+Several implementations are provided - they belong in the roundup.backends
+package.
Application Example
The Roundup database layer adds detectors and user nodes,
and on issues it provides mail spools, nosy lists, and superseders.
-TODO: where functionality is implemented.
-
Reserved Classes
~~~~~~~~~~~~~~~~
of nodes that are not issues.
Users
-""""""""""""
+"""""
Users are stored in the hyperdatabase as nodes of
class "user". The "user" class has the definition::
db.user.setkey("username")
Messages
-"""""""""""""""
+""""""""
E-mail messages are represented by hyperdatabase nodes of class "msg".
The actual text content of the messages is stored in separate files.
in a message index.
Files
-""""""""""""
+"""""
Submitted files are represented by hyperdatabase
nodes of class "file". Like e-mail messages, the file content
priority=hyperdb.Link("priority"),
status=hyperdb.Link("status"))
-
(The "order" property hasn't been explained yet. It
gets used by the Web user interface for sorting.)
A single command, roundup, provides basic access to
the hyperdatabase from the command line::
- roundup get [-list] designator[, designator,...] propname
- roundup set designator[, designator,...] propname=value ...
- roundup find [-list] classname propname=value ...
+ roundup-admin help
+ roundup-admin get [-list] designator[, designator,...] propname
+ roundup-admin set designator[, designator,...] propname=value ...
+ roundup-admin find [-list] classname propname=value ...
-TODO: more stuff here
+See ``roundup-admin help commands`` for a complete list of commands.
Property values are represented as strings in command arguments
and in the printed results:
display checkboxes for the available choices to permit filtering
========= ====================================================================
+TODO: See the htmltemplate pydoc for a complete list of the functions
+
Index Views
~~~~~~~~~~~
/issue?status=unread,in-progress,resolved&
topic=security,ui&
- :group=+priority&
+ :group=priority&
:sort=-activity&
:filters=status,topic&
:columns=title,status,fixer
</tr>
Sorting
-""""""""""""""
+"""""""
String and Date values are sorted in the natural way.
Link properties are sorted according to the value of the
and "summary" properties on the message nodes, and selecting a
message takes you to its content.
+Access Control
+--------------
+
+At each point that requires an action to be performed, the security mechanisms
+are asked if the current user has permission. This permission is defined as a
+Permission.
+
+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 are not persistent - they're defined when the
+application initialises.
+
+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.
+
+
+Access Control Interface Specification
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The security module defines::
+
+ class Permission:
+ ''' Defines a Permission with the attributes
+ - name
+ - description
+ - klass (optional)
+
+ The klass may be unset, indicating that this permission is not
+ locked to a particular hyperdb class. There may be multiple
+ Permissions for the same name for different classes.
+ '''
+
+ class Role:
+ ''' Defines a Role with the attributes
+ - name
+ - description
+ - permissions
+ '''
+
+ class Security:
+ def __init__(self, db):
+ ''' Initialise the permission and role stores, and add in the
+ base roles (for admin user).
+ '''
+
+ def getPermission(self, permission, classname=None):
+ ''' Find the Permission matching the name and for the class, if the
+ classname is specified.
+
+ Raise ValueError if there is no exact match.
+ '''
+
+ def hasPermission(self, permission, userid, classname=None):
+ ''' Look through all the Roles, and hence Permissions, and see if
+ "permission" is there for the specified classname.
+ '''
+
+ def hasNodePermission(self, classname, nodeid, **propspec):
+ ''' 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 set of properties and values that
+ must be present on the given node for access to be granted.
+
+ If a property is a Link, the value must match the property
+ value. If a property is a Multilink, the value 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, permission):
+ ''' Add the permission to the role's permission list.
+
+ 'rolename' is the name of the role to add permission to.
+ '''
+
+Modules such as ``cgi_client.py`` and ``mailgw.py`` define their own
+permissions like so (this example is ``cgi_client.py``)::
+
+ def initialiseSecurity(security):
+ ''' Create some Permissions and Roles on the security object
+
+ This function is directly invoked by security.Security.__init__()
+ as a part of the Security object instantiation.
+ '''
+ p = security.addPermission(name="Web Registration",
+ description="Anonymous users may register through the web")
+ security.addToRole('Anonymous', p)
+
+Detectors may also define roles in their init() function::
+
+ def init(db):
+ # register an auditor that checks that a user has the "May Resolve"
+ # Permission before allowing them to set an issue status to "resolved"
+ db.issue.audit('set', checkresolvedok)
+ p = db.security.addPermission(name="May Resolve", klass="issue")
+ security.addToRole('Manager', p)
+
+The instance dbinit module then has in ``open()``::
+
+ # open the database - it must be modified to init the Security class
+ # from security.py as db.security
+ db = Database(instance_config, name)
+
+ # add some extra permissions and associate them with roles
+ ei = db.security.addPermission(name="Edit", klass="issue",
+ description="User is allowed to edit issues")
+ db.security.addPermissionToRole('User', ei)
+ ai = db.security.addPermission(name="View", klass="issue",
+ description="User is allowed to access issues")
+ db.security.addPermissionToRole('User', ai)
+
+In the dbinit ``init()``::
+
+ # create the two default users
+ user.create(username="admin", password=Password(adminpw),
+ address=instance_config.ADMIN_EMAIL, roles='Admin')
+ user.create(username="anonymous", roles='Anonymous')
+
+Then in the code that matters, calls to ``hasPermission`` and
+``hasNodePermission`` are made to determine if the user has permission
+to perform some action::
+
+ if db.security.hasPermission('issue', 'Edit', userid):
+ # all ok
+
+ if db.security.hasNodePermission('issue', nodeid, assignedto=userid):
+ # all ok
+
+Code in the core will make use of these methods, as should code in auditors in
+custom templates. The htmltemplate will implement a new tag, ``<require>``
+which has the form::
+
+ <require permission="name,name,name" assignedto="$userid" status="open">
+ HTML to display if the user has the permission.
+ <else>
+ HTML to display if the user does not have the permission.
+ </require>
+
+where:
+
+- the permission attribute gives a comma-separated list of permission names.
+ These are checked in turn using ``hasPermission`` and requires one to
+ be OK.
+- the other attributes are lookups on the node using ``hasNodePermission``. If
+ the attribute value is "$userid" then the current user's userid is tested.
+
+Any of these tests must pass or the ``<require>`` 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.
+
+
+Anonymous Users
+~~~~~~~~~~~~~~~
+
+The "anonymous" user must always exist, and defines the access permissions for
+anonymous users. Unknown users accessing Roundup through the web or email
+interfaces will be logged in as the "anonymous" user.
+
+
+Use Cases
+~~~~~~~~~
+
+public - end users can submit bugs, request new features, request support
+ The Users would be given the default "User" Role which gives "View" and
+ "Edit" Permission to the "issue" class.
+developer - developers can fix bugs, implement new features, provide support
+ A new Role "Developer" is created with the Permission "Fixer" which is
+ checked for in custom auditors that see whether the issue is being
+ resolved with a particular resolution ("fixed", "implemented",
+ "supported") and allows that resolution only if the permission is
+ available.
+manager - approvers/managers can approve new features and signoff bug fixes
+ A new Role "Manager" is created with the Permission "Signoff" which is
+ checked for in custom auditors that see whether the issue status is being
+ changed similar to the developer example.
+admin - administrators can add users and set user's roles
+ The existing Role "Admin" has the Permissions "Edit" for all classes
+ (including "user") and "Web Roles" which allow the desired actions.
+system - automated request handlers running various report/escalation scripts
+ A combination of existing and new Roles, Permissions and auditors could
+ be used here.
+privacy - issues that are only visible to some users
+ A new property is added to the issue which marks the user or group of
+ users who are allowed to view and edit the issue. An auditor will check
+ for edit access, and the htmltemplate <require> tag can check for view
+ access.
+
Deployment Scenarios
--------------------
diff --git a/doc/security.txt b/doc/security.txt
index 8c4ae79f4c9da16b40568f24d3a8423c68ea7c6e..93c64f9e852adddee22018f301bd9dc8b71fc6a7 100644 (file)
--- a/doc/security.txt
+++ b/doc/security.txt
Security Mechanisms
===================
-:Version: $Revision: 1.14 $
+:Version: $Revision: 1.15 $
Current situation
=================
- most user interfaces have multiple uses which can't be covered by a
single permission
-
Logical control
---------------
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 are not persistent - they're defined when the
-application initialises.
-
-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.
-
-The security module defines::
-
- class Permission:
- ''' Defines a Permission with the attributes
- - name
- - description
- - klass (optional)
-
- The klass may be unset, indicating that this permission is not
- locked to a particular hyperdb class. There may be multiple
- Permissions for the same name for different classes.
- '''
-
- class Role:
- ''' Defines a Role with the attributes
- - name
- - description
- - permissions
- '''
-
- class Security:
- def __init__(self, db):
- ''' Initialise the permission and role stores, and add in the
- base roles (for admin user).
- '''
-
- def getPermission(self, permission, classname=None):
- ''' Find the Permission matching the name and for the class, if the
- classname is specified.
-
- Raise ValueError if there is no exact match.
- '''
-
- def hasPermission(self, permission, userid, classname=None):
- ''' Look through all the Roles, and hence Permissions, and see if
- "permission" is there for the specified classname.
- '''
-
- def hasNodePermission(self, classname, nodeid, **propspec):
- ''' 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 set of properties and values that
- must be present on the given node for access to be granted.
-
- If a property is a Link, the value must match the property
- value. If a property is a Multilink, the value 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, permission):
- ''' Add the permission to the role's permission list.
-
- 'rolename' is the name of the role to add permission to.
- '''
-
-Modules such as ``cgi_client.py`` and ``mailgw.py`` define their own
-permissions like so (this example is ``cgi_client.py``)::
-
- def initialiseSecurity(security):
- ''' Create some Permissions and Roles on the security object
-
- This function is directly invoked by security.Security.__init__()
- as a part of the Security object instantiation.
- '''
- newid = security.addPermission(name="Web Registration",
- description="Anonymous users may register through the web")
- security.addToRole('Anonymous', newid)
-
-The instance dbinit module then has in ``open()``::
-
- # open the database - it must be modified to init the Security class
- # from security.py as db.security
- db = Database(instance_config, name)
-
- # add some extra permissions and associate them with roles
- ei = db.security.addPermission(name="Edit", klass="issue",
- description="User is allowed to edit issues")
- db.security.addPermissionToRole('User', ei)
- ai = db.security.addPermission(name="View", klass="issue",
- description="User is allowed to access issues")
- db.security.addPermissionToRole('User', ai)
-
-In the dbinit ``init()``::
-
- # create the two default users
- user.create(username="admin", password=Password(adminpw),
- address=instance_config.ADMIN_EMAIL, roles='Admin')
- user.create(username="anonymous", roles='Anonymous')
-
-Then in the code that matters, calls to ``hasPermission`` and
-``hasNodePermission`` are made to determine if the user has permission
-to perform some action::
-
- if db.security.hasPermission('issue', 'Edit', userid):
- # all ok
-
- if db.security.hasNodePermission('issue', nodeid, assignedto=userid):
- # all ok
-
-Code in the core will make use of these methods, as should code in auditors in
-custom templates. The htmltemplate will implement a new tag, ``<require>``
-which has the form::
-
- <require permission="name,name,name" assignedto="$userid" status="open">
- HTML to display if the user has the permission.
- <else>
- HTML to display if the user does not have the permission.
- </require>
-
-where:
-
-- the permission attribute gives a comma-separated list of permission names.
- These are checked in turn using ``hasPermission`` and requires one to
- be OK.
-- the other attributes are lookups on the node using ``hasNodePermission``. If
- the attribute value is "$userid" then the current user's userid is tested.
-
-Any of these tests must pass or the ``<require>`` check will fail. The section
-of html within the side of the ``<else>`` that fails is remove from processing.
-
-Implementation as shipped
--------------------------
-
-A set of Permissions are built in to the security module by default:
-
-- Edit (everything)
-- View (everything)
-
-The default interfaces define:
-
-- Web Registration
-- Email Registration
-
-These are hooked into the default Roles:
-
-- Admin (Edit everything, View everything)
-- User ()
-- Anonymous (Web Registration, Email Registration)
-
-And finally, the "admin" user gets the "Admin" Role, and the "anonymous" user
-gets the "Anonymous" assigned when the database is initialised on installation.
-The two default schemas then define:
-
-- Edit issue, View issue (both)
-- Edit file, View file (both)
-- Edit msg, View msg (both)
-- Edit support, View support (extended only)
-
-and assign those Permissions to the "User" Role. New users are assigned the
-Roles defined in the config file as:
-
-- NEW_WEB_USER_ROLES
-- NEW_EMAIL_USER_ROLES
-
-
-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.
-
-
-Anonymous Users
----------------
-
-The "anonymous" user must always exist, and defines the access permissions for
-anonymous users. The three ``ANONYMOUS_`` configuration variables are
-subsumed by this new functionality.
-
-
Action
======
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
-
diff --git a/roundup/hyperdb.py b/roundup/hyperdb.py
index 71285a6cb0e01056be52285ff25b9006b7b83362..0ac911b4e2ea5c400a88433338f9dc2f73993587 100644 (file)
--- a/roundup/hyperdb.py
+++ b/roundup/hyperdb.py
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
-# $Id: hyperdb.py,v 1.78 2002-07-21 03:26:37 richard Exp $
+# $Id: hyperdb.py,v 1.79 2002-07-29 23:30:14 richard Exp $
__doc__ = """
Hyperdatabase implementation, especially field types.
# flag to set on retired entries
RETIRED_FLAG = '__hyperdb_retired'
- # XXX deviates from spec: storagelocator is obtained from the config
def __init__(self, config, journaltag=None):
"""Open a hyperdatabase given a specifier to some storage.
"""
raise NotImplementedError
- # XXX not in spec
def getnode(self, nodeid, cache=1):
''' Return a convenience wrapper for the node.
"""
raise NotImplementedError
- # XXX: change from spec - allows multiple props to match
def find(self, **propspec):
"""Get the ids of nodes in this class which link to the given nodes.
"""
raise NotImplementedError
- # XXX not in spec
def filter(self, search_matches, filterspec, sort, group,
num_re = re.compile('^\d+$')):
''' Return a list of the ids of the active nodes in this class that
'''
raise NotImplementedError
-# XXX not in spec
class Node:
''' A convenience wrapper for the given node
'''
#
# $Log: not supported by cvs2svn $
+# Revision 1.78 2002/07/21 03:26:37 richard
+# Gordon, does this help?
+#
# Revision 1.77 2002/07/18 11:27:47 richard
# ws
#