← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] ~lgp171188/launchpad:split-security.py-blueprints into launchpad:master

 

Guruprasad has proposed merging ~lgp171188/launchpad:split-security.py-blueprints into launchpad:master.

Commit message:
Move the blueprints-related security adapters to lp.blueprints.security

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~lgp171188/launchpad/+git/launchpad/+merge/426620
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~lgp171188/launchpad:split-security.py-blueprints into launchpad:master.
diff --git a/lib/lp/blueprints/configure.zcml b/lib/lp/blueprints/configure.zcml
index 6279e87..36b9af7 100644
--- a/lib/lp/blueprints/configure.zcml
+++ b/lib/lp/blueprints/configure.zcml
@@ -11,6 +11,7 @@
     xmlns:lp="http://namespaces.canonical.com/lp";
     i18n_domain="launchpad">
 
+  <authorizations module=".security" />
   <include package=".browser"/>
   <include package=".vocabularies"/>
 
diff --git a/lib/lp/blueprints/security.py b/lib/lp/blueprints/security.py
new file mode 100644
index 0000000..b4d8da2
--- /dev/null
+++ b/lib/lp/blueprints/security.py
@@ -0,0 +1,204 @@
+# Copyright 2009-2022 Canonical Ltd.  This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""Security adapters for the blueprints package."""
+
+__all__ = []
+
+from lp.app.security import AnonymousAuthorization, AuthorizationBase
+from lp.blueprints.interfaces.specification import (
+    ISpecification,
+    ISpecificationPublic,
+    ISpecificationView,
+)
+from lp.blueprints.interfaces.specificationbranch import ISpecificationBranch
+from lp.blueprints.interfaces.specificationsubscription import (
+    ISpecificationSubscription,
+)
+from lp.blueprints.interfaces.sprint import ISprint
+from lp.blueprints.interfaces.sprintspecification import ISprintSpecification
+from lp.security import EditByOwnersOrAdmins, ModerateByRegistryExpertsOrAdmins
+
+
+class EditSpecificationBranch(AuthorizationBase):
+
+    usedfor = ISpecificationBranch
+    permission = "launchpad.Edit"
+
+    def checkAuthenticated(self, user):
+        """See `IAuthorization.checkAuthenticated`.
+
+        :return: True or False.
+        """
+        return True
+
+
+class ViewSpecificationBranch(EditSpecificationBranch):
+
+    permission = "launchpad.View"
+
+    def checkUnauthenticated(self):
+        """See `IAuthorization.checkUnauthenticated`.
+
+        :return: True or False.
+        """
+        return True
+
+
+class AnonymousAccessToISpecificationPublic(AnonymousAuthorization):
+    """Anonymous users have launchpad.View on ISpecificationPublic.
+
+    This is only needed because lazr.restful is hard-coded to check that
+    permission before returning things in a collection.
+    """
+
+    permission = "launchpad.View"
+    usedfor = ISpecificationPublic
+
+
+class ViewSpecification(AuthorizationBase):
+
+    permission = "launchpad.LimitedView"
+    usedfor = ISpecificationView
+
+    def checkAuthenticated(self, user):
+        return self.obj.userCanView(user)
+
+    def checkUnauthenticated(self):
+        return self.obj.userCanView(None)
+
+
+class EditSpecificationByRelatedPeople(AuthorizationBase):
+    """We want everybody "related" to a specification to be able to edit it.
+    You are related if you have a role on the spec, or if you have a role on
+    the spec target (distro/product) or goal (distroseries/productseries).
+    """
+
+    permission = "launchpad.Edit"
+    usedfor = ISpecification
+
+    def checkAuthenticated(self, user):
+        assert self.obj.target
+        goal = self.obj.goal
+        if goal is not None:
+            if user.isOwner(goal) or user.isDriver(goal):
+                return True
+        return (
+            user.in_admin
+            or user.in_registry_experts
+            or user.isOwner(self.obj.target)
+            or user.isDriver(self.obj.target)
+            or user.isOneOf(
+                self.obj, ["owner", "drafter", "assignee", "approver"]
+            )
+        )
+
+
+class AdminSpecification(AuthorizationBase):
+    permission = "launchpad.Admin"
+    usedfor = ISpecification
+
+    def checkAuthenticated(self, user):
+        assert self.obj.target
+        return (
+            user.in_admin
+            or user.in_registry_experts
+            or user.isOwner(self.obj.target)
+            or user.isDriver(self.obj.target)
+        )
+
+
+class DriverSpecification(AuthorizationBase):
+    permission = "launchpad.Driver"
+    usedfor = ISpecification
+
+    def checkAuthenticated(self, user):
+        # If no goal is proposed for the spec then there can be no
+        # drivers for it - we use launchpad.Driver on a spec to decide
+        # if the person can see the page which lets you decide whether
+        # to accept the goal, and if there is no goal then this is
+        # extremely difficult to do :-)
+        return self.obj.goal and self.forwardCheckAuthenticated(
+            user, self.obj.goal
+        )
+
+
+class EditSprintSpecification(AuthorizationBase):
+    """The sprint owner or driver can say what makes it onto the agenda for
+    the sprint.
+    """
+
+    permission = "launchpad.Driver"
+    usedfor = ISprintSpecification
+
+    def checkAuthenticated(self, user):
+        sprint = self.obj.sprint
+        return user.isOwner(sprint) or user.isDriver(sprint) or user.in_admin
+
+
+class DriveSprint(AuthorizationBase):
+    """The sprint owner or driver can say what makes it onto the agenda for
+    the sprint.
+    """
+
+    permission = "launchpad.Driver"
+    usedfor = ISprint
+
+    def checkAuthenticated(self, user):
+        return (
+            user.isOwner(self.obj) or user.isDriver(self.obj) or user.in_admin
+        )
+
+
+class ViewSprint(AuthorizationBase):
+    """An attendee, owner, or driver of a sprint."""
+
+    permission = "launchpad.View"
+    usedfor = ISprint
+
+    def checkAuthenticated(self, user):
+        return (
+            user.isOwner(self.obj)
+            or user.isDriver(self.obj)
+            or user.person
+            in [attendance.attendee for attendance in self.obj.attendances]
+            or user.in_admin
+        )
+
+
+class EditSprint(EditByOwnersOrAdmins):
+    usedfor = ISprint
+
+
+class ModerateSprint(ModerateByRegistryExpertsOrAdmins):
+    """The sprint owner, registry experts, and admins can moderate sprints."""
+
+    permission = "launchpad.Moderate"
+    usedfor = ISprint
+
+    def checkAuthenticated(self, user):
+        return super().checkAuthenticated(user) or user.isOwner(self.obj)
+
+
+class EditSpecificationSubscription(AuthorizationBase):
+    """The subscriber, and people related to the spec or the target of the
+    spec can determine who is essential."""
+
+    permission = "launchpad.Edit"
+    usedfor = ISpecificationSubscription
+
+    def checkAuthenticated(self, user):
+        if self.obj.specification.goal is not None:
+            if user.isDriver(self.obj.specification.goal):
+                return True
+        else:
+            if user.isDriver(self.obj.specification.target):
+                return True
+        return (
+            user.inTeam(self.obj.person)
+            or user.isOneOf(
+                self.obj.specification,
+                ["owner", "drafter", "assignee", "approver"],
+            )
+            or user.in_admin
+        )
diff --git a/lib/lp/blueprints/tests/test_specification.py b/lib/lp/blueprints/tests/test_specification.py
index 211cb7d..bb01e66 100644
--- a/lib/lp/blueprints/tests/test_specification.py
+++ b/lib/lp/blueprints/tests/test_specification.py
@@ -34,17 +34,17 @@ from lp.blueprints.model.specification import Specification
 from lp.blueprints.model.specificationsearch import (
     get_specification_privacy_filter,
 )
+from lp.blueprints.security import (
+    AdminSpecification,
+    EditSpecificationByRelatedPeople,
+    ViewSpecification,
+)
 from lp.registry.enums import SharingPermission, SpecificationSharingPolicy
 from lp.registry.interfaces.accesspolicy import (
     IAccessArtifactGrantSource,
     IAccessPolicySource,
 )
 from lp.registry.interfaces.person import IPersonSet
-from lp.security import (
-    AdminSpecification,
-    EditSpecificationByRelatedPeople,
-    ViewSpecification,
-)
 from lp.services.propertycache import get_property_cache
 from lp.services.webapp.authorization import check_permission
 from lp.services.webapp.interaction import ANONYMOUS
diff --git a/lib/lp/security.py b/lib/lp/security.py
index bfe9868..46c0f4a 100644
--- a/lib/lp/security.py
+++ b/lib/lp/security.py
@@ -34,17 +34,6 @@ from lp.app.security import (
     DelegatedAuthorization,
     )
 from lp.archivepublisher.interfaces.publisherconfig import IPublisherConfig
-from lp.blueprints.interfaces.specification import (
-    ISpecification,
-    ISpecificationPublic,
-    ISpecificationView,
-    )
-from lp.blueprints.interfaces.specificationbranch import ISpecificationBranch
-from lp.blueprints.interfaces.specificationsubscription import (
-    ISpecificationSubscription,
-    )
-from lp.blueprints.interfaces.sprint import ISprint
-from lp.blueprints.interfaces.sprintspecification import ISprintSpecification
 from lp.bugs.interfaces.bugtarget import IOfficialBugTagTargetRestricted
 from lp.bugs.interfaces.structuralsubscription import IStructuralSubscription
 from lp.buildmaster.interfaces.builder import (
@@ -268,178 +257,6 @@ class EditByOwnersOrAdmins(AuthorizationBase):
         return user.isOwner(self.obj) or user.in_admin
 
 
-class EditSpecificationBranch(AuthorizationBase):
-
-    usedfor = ISpecificationBranch
-    permission = 'launchpad.Edit'
-
-    def checkAuthenticated(self, user):
-        """See `IAuthorization.checkAuthenticated`.
-
-        :return: True or False.
-        """
-        return True
-
-
-class ViewSpecificationBranch(EditSpecificationBranch):
-
-    permission = 'launchpad.View'
-
-    def checkUnauthenticated(self):
-        """See `IAuthorization.checkUnauthenticated`.
-
-        :return: True or False.
-        """
-        return True
-
-
-class AnonymousAccessToISpecificationPublic(AnonymousAuthorization):
-    """Anonymous users have launchpad.View on ISpecificationPublic.
-
-    This is only needed because lazr.restful is hard-coded to check that
-    permission before returning things in a collection.
-    """
-
-    permission = 'launchpad.View'
-    usedfor = ISpecificationPublic
-
-
-class ViewSpecification(AuthorizationBase):
-
-    permission = 'launchpad.LimitedView'
-    usedfor = ISpecificationView
-
-    def checkAuthenticated(self, user):
-        return self.obj.userCanView(user)
-
-    def checkUnauthenticated(self):
-        return self.obj.userCanView(None)
-
-
-class EditSpecificationByRelatedPeople(AuthorizationBase):
-    """We want everybody "related" to a specification to be able to edit it.
-    You are related if you have a role on the spec, or if you have a role on
-    the spec target (distro/product) or goal (distroseries/productseries).
-    """
-
-    permission = 'launchpad.Edit'
-    usedfor = ISpecification
-
-    def checkAuthenticated(self, user):
-        assert self.obj.target
-        goal = self.obj.goal
-        if goal is not None:
-            if user.isOwner(goal) or user.isDriver(goal):
-                return True
-        return (user.in_admin or
-                user.in_registry_experts or
-                user.isOwner(self.obj.target) or
-                user.isDriver(self.obj.target) or
-                user.isOneOf(
-                    self.obj, ['owner', 'drafter', 'assignee', 'approver']))
-
-
-class AdminSpecification(AuthorizationBase):
-    permission = 'launchpad.Admin'
-    usedfor = ISpecification
-
-    def checkAuthenticated(self, user):
-        assert self.obj.target
-        return (
-                user.in_admin or
-                user.in_registry_experts or
-                user.isOwner(self.obj.target) or
-                user.isDriver(self.obj.target))
-
-
-class DriverSpecification(AuthorizationBase):
-    permission = 'launchpad.Driver'
-    usedfor = ISpecification
-
-    def checkAuthenticated(self, user):
-        # If no goal is proposed for the spec then there can be no
-        # drivers for it - we use launchpad.Driver on a spec to decide
-        # if the person can see the page which lets you decide whether
-        # to accept the goal, and if there is no goal then this is
-        # extremely difficult to do :-)
-        return (
-            self.obj.goal and
-            self.forwardCheckAuthenticated(user, self.obj.goal))
-
-
-class EditSprintSpecification(AuthorizationBase):
-    """The sprint owner or driver can say what makes it onto the agenda for
-    the sprint.
-    """
-    permission = 'launchpad.Driver'
-    usedfor = ISprintSpecification
-
-    def checkAuthenticated(self, user):
-        sprint = self.obj.sprint
-        return user.isOwner(sprint) or user.isDriver(sprint) or user.in_admin
-
-
-class DriveSprint(AuthorizationBase):
-    """The sprint owner or driver can say what makes it onto the agenda for
-    the sprint.
-    """
-    permission = 'launchpad.Driver'
-    usedfor = ISprint
-
-    def checkAuthenticated(self, user):
-        return (user.isOwner(self.obj) or
-                user.isDriver(self.obj) or
-                user.in_admin)
-
-
-class ViewSprint(AuthorizationBase):
-    """An attendee, owner, or driver of a sprint."""
-    permission = 'launchpad.View'
-    usedfor = ISprint
-
-    def checkAuthenticated(self, user):
-        return (user.isOwner(self.obj) or
-                user.isDriver(self.obj) or
-                user.person in [attendance.attendee
-                            for attendance in self.obj.attendances] or
-                user.in_admin)
-
-
-class EditSprint(EditByOwnersOrAdmins):
-    usedfor = ISprint
-
-
-class ModerateSprint(ModerateByRegistryExpertsOrAdmins):
-    """The sprint owner, registry experts, and admins can moderate sprints."""
-    permission = 'launchpad.Moderate'
-    usedfor = ISprint
-
-    def checkAuthenticated(self, user):
-        return (
-            super().checkAuthenticated(user) or
-            user.isOwner(self.obj))
-
-
-class EditSpecificationSubscription(AuthorizationBase):
-    """The subscriber, and people related to the spec or the target of the
-    spec can determine who is essential."""
-    permission = 'launchpad.Edit'
-    usedfor = ISpecificationSubscription
-
-    def checkAuthenticated(self, user):
-        if self.obj.specification.goal is not None:
-            if user.isDriver(self.obj.specification.goal):
-                return True
-        else:
-            if user.isDriver(self.obj.specification.target):
-                return True
-        return (user.inTeam(self.obj.person) or
-                user.isOneOf(
-                    self.obj.specification,
-                    ['owner', 'drafter', 'assignee', 'approver']) or
-                user.in_admin)
-
-
 class OnlyRosettaExpertsAndAdmins(AuthorizationBase):
     """Base class that allow access to Rosetta experts and Launchpad admins.
     """