ApproveChanges

Changeset

30:623d4bb10f11
2013-11-05 Paul Boddie raw files shortlog changelog graph Removed the ApprovalQueueUser, making use of a special security policy instead.
ApproveChangesSupport.py (file) README.txt (file) events/queue_for_review.py (file)
     1.1 --- a/ApproveChangesSupport.py	Tue Nov 05 22:18:45 2013 +0100
     1.2 +++ b/ApproveChangesSupport.py	Tue Nov 05 22:56:25 2013 +0100
     1.3 @@ -2,10 +2,6 @@
     1.4  """
     1.5      MoinMoin - ApproveChanges library
     1.6  
     1.7 -    This library relies on the existence of a user (by default
     1.8 -    "ApprovalQueueUser") who has sufficient privileges to write pages with ACLs
     1.9 -    to an approval queue (ACL permissions "write,admin").
    1.10 -
    1.11      If users other than the superuser are to be able to edit pages freely, they
    1.12      must be present in a group (by default "ApprovedGroup"), and if they are to
    1.13      be allowed to review changes, they must be present in a different group (by
    1.14 @@ -46,9 +42,6 @@
    1.15  def get_page_reviewers_group(request):
    1.16      return getattr(request.cfg, "reviewers_group", "PageReviewersGroup")
    1.17  
    1.18 -def get_queued_changes_user(request):
    1.19 -    return getattr(request.cfg, "queued_changes_user", "ApprovalQueueUser")
    1.20 -
    1.21  def is_reviewer(request):
    1.22      return request.user.valid and (
    1.23          has_member(request, get_page_reviewers_group(request), request.user.name) or \
    1.24 @@ -62,9 +55,6 @@
    1.25  def user_is_approved(request, username):
    1.26      return has_member(request, get_approved_editors_group(request), username)
    1.27  
    1.28 -def is_queued_changes_user(request):
    1.29 -    return request.user.valid and request.user.name == get_queued_changes_user(request)
    1.30 -
    1.31  def is_queued_changes_page(request, pagename):
    1.32  
    1.33      "Return whether 'pagename' is a queued changes page by testing its name."
    1.34 @@ -81,16 +71,6 @@
    1.35      extra_parts = directives.has_key(directive) and 2 or 1
    1.36      return "/".join(page.page_name.split("/")[:-extra_parts])
    1.37  
    1.38 -def get_user_for_saving(request):
    1.39 -
    1.40 -    "Return a user that can save pages with ACLs."
    1.41 -
    1.42 -    username = get_queued_changes_user(request)
    1.43 -
    1.44 -    # If the user does not exist, just return the existing user.
    1.45 -
    1.46 -    return get_user(request, username) or request.user
    1.47 -
    1.48  def get_user(request, username):
    1.49  
    1.50      "Return the user having the given 'username'."
     2.1 --- a/README.txt	Tue Nov 05 22:18:45 2013 +0100
     2.2 +++ b/README.txt	Tue Nov 05 22:56:25 2013 +0100
     2.3 @@ -16,23 +16,6 @@
     2.4  See pages/HelpOnApproveChanges for the documentation for this software and how
     2.5  to use it.
     2.6  
     2.7 -Pre-Installation Tasks
     2.8 -----------------------
     2.9 -
    2.10 -Before installing the software, create a new user who will be responsible for
    2.11 -queuing untrusted changes. This user will be used by the software internally,
    2.12 -and it should never be necessary to log in manually as this user to perform
    2.13 -tasks.
    2.14 -
    2.15 -Adding a new user can be done using the moin program as follows:
    2.16 -
    2.17 -  moin --config-dir=path-to-wikiconfig account create \
    2.18 -       --name=ApprovalQueueUser --email=... --password=...
    2.19 -
    2.20 -The ... values should be substituted with acceptable values. Beware that
    2.21 -MoinMoin insists on distinct e-mail addresses. Beware also that providing a
    2.22 -password on the command line can be a risk on multi-user systems.
    2.23 -
    2.24  Installation
    2.25  ------------
    2.26  
    2.27 @@ -107,21 +90,8 @@
    2.28  
    2.29  Once the event handler has been installed, all page saving operations will be
    2.30  affected by its operation. With no further configuration, it is most likely
    2.31 -that only superusers will be able to save changes to wiki pages, and even the
    2.32 -queuing of changes will not function properly.
    2.33 -
    2.34 -Thus, it becomes necessary to change the wiki configuration to enable the
    2.35 -successful queuing of changes by changing the acl_rights_before configuration
    2.36 -setting, adding the following rule:
    2.37 -
    2.38 -  ApprovalQueueUser:write,admin
    2.39 -
    2.40 -This will let the special internal wiki user responsible for queuing changes
    2.41 -(see "Pre-Installation Tasks") save and define an ACL on a page saved by an
    2.42 -untrusted user. See the following page for more information on access control
    2.43 -lists (ACLs):
    2.44 -
    2.45 -  http://moinmo.in/HelpOnAccessControlLists
    2.46 +that only superusers will be able to save changes to wiki pages, and the edits
    2.47 +of all other users will be queued.
    2.48  
    2.49  The configuration settings used by ApproveChanges are as follows:
    2.50  
    2.51 @@ -158,24 +128,6 @@
    2.52    This gives the name of the group page holding the names of reviewers. By
    2.53    default, it is set to PageReviewersGroup. See "Resource Pages" above.
    2.54  
    2.55 -  queued_changes_user
    2.56 -  -------------------
    2.57 -
    2.58 -  This gives the name of the user who saves unapproved changes to approval
    2.59 -  queues. By default, it is set to ApprovalQueueUser.
    2.60 -
    2.61 -Troubleshooting
    2.62 ----------------
    2.63 -
    2.64 -When a user tries to save a page, they get the following error (or
    2.65 -equivalent):
    2.66 -
    2.67 -  You can't change ACLs on this page since you have no admin rights on it!
    2.68 -
    2.69 -This is possibly caused by the absence of the ApprovalQueueUser (see
    2.70 -"Pre-Installation Tasks" above) and/or the acl_rights_before rule for that
    2.71 -user (see "Configuration" above).
    2.72 -
    2.73  Recommended Software
    2.74  --------------------
    2.75  
    2.76 @@ -204,6 +156,9 @@
    2.77  --------------------------------------------------------------
    2.78  
    2.79    * Added user-specific approval queues.
    2.80 +  * Removed the special ApprovalQueueUser. This user can be removed from
    2.81 +    existing installations since the software no longer needs it to perform
    2.82 +    the queuing of unapproved contributions.
    2.83  
    2.84  New in ApproveChanges 0.1.1 (Changes since ApproveChanges 0.1)
    2.85  --------------------------------------------------------------
     3.1 --- a/events/queue_for_review.py	Tue Nov 05 22:18:45 2013 +0100
     3.2 +++ b/events/queue_for_review.py	Tue Nov 05 22:56:25 2013 +0100
     3.3 @@ -11,8 +11,22 @@
     3.4  
     3.5  from MoinMoin.PageEditor import PageEditor
     3.6  from MoinMoin.events import PagePreSaveEvent, Abort
     3.7 +from MoinMoin.security import Permissions
     3.8  from ApproveChangesSupport import *
     3.9  
    3.10 +class SpecialPermissions(Permissions):
    3.11 +
    3.12 +    "Permit saving of ACL-enabled comment pages."
    3.13 +
    3.14 +    def __init__(self, user, pagename):
    3.15 +        Permissions.__init__(self, user)
    3.16 +        self.pagename = pagename
    3.17 +
    3.18 +    def admin(self, pagename):
    3.19 +        return pagename == self.pagename
    3.20 +
    3.21 +    write = admin
    3.22 +
    3.23  def handle_presave(event):
    3.24      request = event.request
    3.25      _ = request.getText
    3.26 @@ -31,7 +45,7 @@
    3.27          # Test the integrity of the page in order to prevent direct replacement
    3.28          # of the page. Reviewers can change the page as they please.
    3.29  
    3.30 -        if is_reviewer(request) or is_queued_changes_user(request):
    3.31 +        if is_reviewer(request) or isinstance(request.user.may, SpecialPermissions):
    3.32              return None
    3.33          else:
    3.34              return Abort(_("Queued changes may not be edited."))
    3.35 @@ -44,7 +58,8 @@
    3.36  
    3.37          # Save the page in the queue.
    3.38  
    3.39 -        new_page = PageEditor(request, "%s/%s%s" % (pagename, user_specific_queue, queued_changes_page))
    3.40 +        queued_pagename = "%s/%s%s" % (pagename, user_specific_queue, queued_changes_page)
    3.41 +        new_page = PageEditor(request, queued_pagename)
    3.42  
    3.43          # Add an ACL to prevent normal users from seeing the page anywhere.
    3.44          # Add a parent revision to the page.
    3.45 @@ -62,14 +77,20 @@
    3.46          comment = (username or _("anonymous")) + " : " +  _("Queued page edit")
    3.47  
    3.48          try:
    3.49 -            # Switch user in order to save a page with an ACL.
    3.50 +            # To add a page with an ACL, a special policy is required.
    3.51  
    3.52 -            user = request.user
    3.53 -            request.user = get_user_for_saving(request)
    3.54 +            may = request.user.may
    3.55 +            request.user.may = SpecialPermissions(request.user, queued_pagename)
    3.56 +
    3.57 +            # Save the page with the ACL.
    3.58 +
    3.59              try:
    3.60                  new_page.saveText(body, 0, comment=comment)
    3.61 +
    3.62 +            # Restore the original policy.
    3.63 +
    3.64              finally:
    3.65 -                request.user = user
    3.66 +                request.user.may = may
    3.67              
    3.68          except PageEditor.Unchanged:
    3.69              pass