This is an automated email from the ASF dual-hosted git repository.

brondsem pushed a commit to branch db/8556-breaking-removal
in repository https://gitbox.apache.org/repos/asf/allura.git

commit 61d406fa8afea467efbb6478ba4e8e52d6506696
Author: Dave Brondsema <dbronds...@slashdotmedia.com>
AuthorDate: Tue Apr 2 17:44:28 2024 -0400

    [#8555] some specific checks for blocked users, when creating new forum 
threads
---
 Allura/allura/lib/security.py                      | 32 +++++++++++++++-------
 Allura/allura/model/discuss.py                     |  6 +++-
 .../forgediscussion/controllers/root.py            | 10 +++++--
 3 files changed, 34 insertions(+), 14 deletions(-)

diff --git a/Allura/allura/lib/security.py b/Allura/allura/lib/security.py
index cc874822d..3c16d05be 100644
--- a/Allura/allura/lib/security.py
+++ b/Allura/allura/lib/security.py
@@ -19,12 +19,12 @@
 This module provides the security predicates used in decorating various models.
 """
 
-import six
-import sys
+from __future__ import annotations
 import logging
 from collections import defaultdict
 import hashlib
 import requests
+import typing
 
 from tg import tmpl_context as c
 from tg import request
@@ -35,6 +35,9 @@ import tg
 
 from allura.lib.utils import TruthyCallable
 
+if typing.TYPE_CHECKING:
+    from allura.model import M
+
 log = logging.getLogger(__name__)
 
 
@@ -277,7 +280,21 @@ class RoleCache:
         return set(self.reaching_ids)
 
 
-def has_access(obj, permission, user=None, project=None):
+def is_denied(obj, permission: str, user: M.User, project: M.Project) -> bool:
+    from allura import model as M
+
+    if user != M.User.anonymous():
+        user_roles = Credentials.get().user_roles(user_id=user._id,
+                                                  
project_id=project.root_project._id)
+        for r in user_roles:
+            deny_user = M.ACE.deny(r['_id'], permission)
+            if M.ACL.contains(deny_user, obj.acl):
+                return True
+
+    return False
+
+
+def has_access(obj, permission: str, user: M.User | None = None, project: 
M.Project | None = None):
     '''Return whether the given user has the permission name on the given 
object.
 
     - First, all the roles for a user in the given project context are 
computed.
@@ -341,13 +358,8 @@ def has_access(obj, permission, user=None, project=None):
                 user_id=user._id, project_id=project._id).reaching_ids
 
         # TODO: move deny logic into loop below; see ticket [#6715]
-        if user != M.User.anonymous():
-            user_roles = Credentials.get().user_roles(user_id=user._id,
-                                                      
project_id=project.root_project._id)
-            for r in user_roles:
-                deny_user = M.ACE.deny(r['_id'], permission)
-                if M.ACL.contains(deny_user, obj.acl):
-                    return False
+        if is_denied(obj, permission, user, project):
+            return False
 
         chainable_roles = []
         for rid in roles:
diff --git a/Allura/allura/model/discuss.py b/Allura/allura/model/discuss.py
index 3ecb42907..92999e295 100644
--- a/Allura/allura/model/discuss.py
+++ b/Allura/allura/model/discuss.py
@@ -33,10 +33,11 @@ from ming.odm.property import (FieldProperty, 
RelationProperty,
                                ForeignIdProperty)
 from ming.utils import LazyProperty
 from bson import ObjectId
+from webob import exc
 
 from allura.lib import helpers as h
 from allura.lib import security
-from allura.lib.security import require_access, has_access
+from allura.lib.security import require_access, has_access, is_denied
 from allura.lib import utils
 from allura.model.notification import Notification, Mailbox
 from .artifact import Artifact, ArtifactReference, VersionedArtifact, 
Snapshot, Message, Feed, ReactableArtifact
@@ -335,6 +336,9 @@ class Thread(Artifact, ActivityObject):
              is_meta=False, subscribe=False, **kw):
         if not ignore_security:
             require_access(self, 'post')
+            # check app-level for Blocked Users, in addition to the standard 
`self` check above
+            if is_denied(self.app, 'post', c.user, self.project):
+                raise exc.HTTPForbidden
         if subscribe:
             self.primary().subscribe()
         if message_id is None:
diff --git a/ForgeDiscussion/forgediscussion/controllers/root.py 
b/ForgeDiscussion/forgediscussion/controllers/root.py
index 212245f79..251d57923 100644
--- a/ForgeDiscussion/forgediscussion/controllers/root.py
+++ b/ForgeDiscussion/forgediscussion/controllers/root.py
@@ -110,9 +110,13 @@ class RootController(BaseController, DispatchIndex, 
FeedController):
     @with_trailing_slash
     
@expose('jinja:forgediscussion:templates/discussionforums/create_topic.html')
     def create_topic(self, forum_name=None, new_forum=False, **kw):
-        forums = model.Forum.query.find(dict(app_config_id=c.app.config._id,
-                                             parent_id=None,
-                                             deleted=False))
+        # check app-level access to guarantee enforcement of Block Users.  In 
addition to per-forum checks below
+        if has_access(c.app, 'post'):
+            forums = 
model.Forum.query.find(dict(app_config_id=c.app.config._id,
+                                                 parent_id=None,
+                                                 deleted=False))
+        else:
+            forums = []
         c.new_topic = self.W.new_topic
         my_forums = []
         forum_name = h.really_unicode(unquote(forum_name)) if forum_name else 
None

Reply via email to