launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #28767
[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.
"""