launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #28781
[Merge] ~lgp171188/launchpad:split-security.py-charms-oci-snappy into launchpad:master
Guruprasad has proposed merging ~lgp171188/launchpad:split-security.py-charms-oci-snappy into launchpad:master.
Commit message:
Split and move the security adapters for charms, oci, security packages
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~lgp171188/launchpad/+git/launchpad/+merge/426643
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~lgp171188/launchpad:split-security.py-charms-oci-snappy into launchpad:master.
diff --git a/lib/lp/charms/configure.zcml b/lib/lp/charms/configure.zcml
index 330a72d..74d490d 100644
--- a/lib/lp/charms/configure.zcml
+++ b/lib/lp/charms/configure.zcml
@@ -11,6 +11,7 @@
xmlns:xmlrpc="http://namespaces.zope.org/xmlrpc"
i18n_domain="launchpad">
+ <authorizations module=".security" />
<include package=".browser" />
<lp:help-folder folder="help" name="+help-charms" />
diff --git a/lib/lp/charms/security.py b/lib/lp/charms/security.py
new file mode 100644
index 0000000..9d8dad2
--- /dev/null
+++ b/lib/lp/charms/security.py
@@ -0,0 +1,112 @@
+# 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 charms package."""
+
+__all__ = []
+
+from lp.app.security import (
+ AnonymousAuthorization,
+ AuthorizationBase,
+ DelegatedAuthorization,
+)
+from lp.charms.interfaces.charmbase import ICharmBase, ICharmBaseSet
+from lp.charms.interfaces.charmrecipe import (
+ ICharmRecipe,
+ ICharmRecipeBuildRequest,
+)
+from lp.charms.interfaces.charmrecipebuild import ICharmRecipeBuild
+from lp.security import AdminByBuilddAdmin, EditByRegistryExpertsOrAdmins
+
+
+class ViewCharmRecipe(AuthorizationBase):
+ """Private charm recipes are only visible to their owners and admins."""
+
+ permission = "launchpad.View"
+ usedfor = ICharmRecipe
+
+ def checkAuthenticated(self, user):
+ return self.obj.visibleByUser(user.person)
+
+ def checkUnauthenticated(self):
+ return self.obj.visibleByUser(None)
+
+
+class EditCharmRecipe(AuthorizationBase):
+ permission = "launchpad.Edit"
+ usedfor = ICharmRecipe
+
+ def checkAuthenticated(self, user):
+ return (
+ user.isOwner(self.obj) or user.in_commercial_admin or user.in_admin
+ )
+
+
+class AdminCharmRecipe(AuthorizationBase):
+ """Restrict changing build settings on charm recipes.
+
+ The security of the non-virtualised build farm depends on these
+ settings, so they can only be changed by "PPA"/commercial admins, or by
+ "PPA" self admins on charm recipes that they can already edit.
+ """
+
+ permission = "launchpad.Admin"
+ usedfor = ICharmRecipe
+
+ def checkAuthenticated(self, user):
+ if user.in_ppa_admin or user.in_commercial_admin or user.in_admin:
+ return True
+ return user.in_ppa_self_admins and EditCharmRecipe(
+ self.obj
+ ).checkAuthenticated(user)
+
+
+class ViewCharmRecipeBuildRequest(DelegatedAuthorization):
+ permission = "launchpad.View"
+ usedfor = ICharmRecipeBuildRequest
+
+ def __init__(self, obj):
+ super().__init__(obj, obj.recipe, "launchpad.View")
+
+
+class ViewCharmRecipeBuild(DelegatedAuthorization):
+ permission = "launchpad.View"
+ usedfor = ICharmRecipeBuild
+
+ def iter_objects(self):
+ yield self.obj.recipe
+
+
+class EditCharmRecipeBuild(AdminByBuilddAdmin):
+ permission = "launchpad.Edit"
+ usedfor = ICharmRecipeBuild
+
+ def checkAuthenticated(self, user):
+ """Check edit access for snap package builds.
+
+ Allow admins, buildd admins, and the owner of the charm recipe.
+ (Note that the requester of the build is required to be in the team
+ that owns the charm recipe.)
+ """
+ auth_recipe = EditCharmRecipe(self.obj.recipe)
+ if auth_recipe.checkAuthenticated(user):
+ return True
+ return super().checkAuthenticated(user)
+
+
+class AdminCharmRecipeBuild(AdminByBuilddAdmin):
+ usedfor = ICharmRecipeBuild
+
+
+class ViewCharmBase(AnonymousAuthorization):
+ """Anyone can view an `ICharmBase`."""
+
+ usedfor = ICharmBase
+
+
+class EditCharmBase(EditByRegistryExpertsOrAdmins):
+ usedfor = ICharmBase
+
+
+class EditCharmBaseSet(EditByRegistryExpertsOrAdmins):
+ usedfor = ICharmBaseSet
diff --git a/lib/lp/oci/configure.zcml b/lib/lp/oci/configure.zcml
index 82cf7ff..098a26d 100644
--- a/lib/lp/oci/configure.zcml
+++ b/lib/lp/oci/configure.zcml
@@ -8,6 +8,7 @@
xmlns:webservice="http://namespaces.canonical.com/webservice"
i18n_domain="launchpad">
+ <authorizations module=".security" />
<include package=".browser" />
<include file="vocabularies.zcml" />
diff --git a/lib/lp/oci/security.py b/lib/lp/oci/security.py
new file mode 100644
index 0000000..fd3d429
--- /dev/null
+++ b/lib/lp/oci/security.py
@@ -0,0 +1,158 @@
+# 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 oci package."""
+
+__all__ = []
+
+from lp.app.security import (
+ AnonymousAuthorization,
+ AuthorizationBase,
+ DelegatedAuthorization,
+ )
+from lp.oci.interfaces.ocipushrule import IOCIPushRule
+from lp.oci.interfaces.ocirecipe import (
+ IOCIRecipe,
+ IOCIRecipeBuildRequest,
+ )
+from lp.oci.interfaces.ocirecipebuild import IOCIRecipeBuild
+from lp.oci.interfaces.ocirecipesubscription import IOCIRecipeSubscription
+from lp.oci.interfaces.ociregistrycredentials import IOCIRegistryCredentials
+from lp.security import AdminByBuilddAdmin
+from lp.snappy.security import EditSnap
+
+
+class ViewOCIRecipeBuildRequest(DelegatedAuthorization):
+ permission = 'launchpad.View'
+ usedfor = IOCIRecipeBuildRequest
+
+ def __init__(self, obj):
+ super().__init__(obj, obj.recipe, 'launchpad.View')
+
+
+class ViewOCIRecipe(AnonymousAuthorization):
+ """Anyone can view public `IOCIRecipe`, but only subscribers can view
+ private ones.
+ """
+ usedfor = IOCIRecipe
+
+ def checkUnauthenticated(self):
+ return self.obj.visibleByUser(None)
+
+ def checkAuthenticated(self, user):
+ return self.obj.visibleByUser(user.person)
+
+
+class EditOCIRecipe(AuthorizationBase):
+ permission = 'launchpad.Edit'
+ usedfor = IOCIRecipe
+
+ def checkAuthenticated(self, user):
+ return (
+ user.isOwner(self.obj) or
+ user.in_commercial_admin or user.in_admin)
+
+
+class AdminOCIRecipe(AuthorizationBase):
+ """Restrict changing build settings on OCI recipes.
+
+ The security of the non-virtualised build farm depends on these
+ settings, so they can only be changed by "PPA"/commercial admins, or by
+ "PPA" self admins on OCI recipes that they can already edit.
+ """
+ permission = 'launchpad.Admin'
+ usedfor = IOCIRecipe
+
+ def checkAuthenticated(self, user):
+ if user.in_ppa_admin or user.in_commercial_admin or user.in_admin:
+ return True
+ return (
+ user.in_ppa_self_admins
+ and EditSnap(self.obj).checkAuthenticated(user))
+
+
+class OCIRecipeSubscriptionEdit(AuthorizationBase):
+ permission = 'launchpad.Edit'
+ usedfor = IOCIRecipeSubscription
+
+ def checkAuthenticated(self, user):
+ """Is the user able to edit an OCI recipe subscription?
+
+ Any team member can edit a OCI recipe subscription for their
+ team.
+ Launchpad Admins can also edit any OCI recipe subscription.
+ The owner of the subscribed OCI recipe can edit the subscription. If
+ the OCI recipe owner is a team, then members of the team can edit
+ the subscription.
+ """
+ return (user.inTeam(self.obj.recipe.owner) or
+ user.inTeam(self.obj.person) or
+ user.inTeam(self.obj.subscribed_by) or
+ user.in_admin)
+
+
+class OCIRecipeSubscriptionView(AuthorizationBase):
+ permission = 'launchpad.View'
+ usedfor = IOCIRecipeSubscription
+
+ def checkUnauthenticated(self):
+ return self.obj.recipe.visibleByUser(None)
+
+ def checkAuthenticated(self, user):
+ return self.obj.recipe.visibleByUser(user.person)
+
+
+class ViewOCIRecipeBuild(DelegatedAuthorization):
+ permission = 'launchpad.View'
+ usedfor = IOCIRecipeBuild
+
+ def iter_objects(self):
+ yield self.obj.recipe
+
+
+class EditOCIRecipeBuild(AdminByBuilddAdmin):
+ permission = 'launchpad.Edit'
+ usedfor = IOCIRecipeBuild
+
+ def checkAuthenticated(self, user):
+ """Check edit access for OCI recipe builds.
+
+ Allow admins, buildd admins, and the owner of the OCI recipe.
+ (Note that the requester of the build is required to be in the team
+ that owns the OCI recipe.)
+ """
+ auth_recipe = EditOCIRecipe(self.obj.recipe)
+ if auth_recipe.checkAuthenticated(user):
+ return True
+ return super().checkAuthenticated(user)
+
+
+class AdminOCIRecipeBuild(AdminByBuilddAdmin):
+ usedfor = IOCIRecipeBuild
+
+
+class ViewOCIRegistryCredentials(AuthorizationBase):
+ permission = 'launchpad.View'
+ usedfor = IOCIRegistryCredentials
+
+ def checkAuthenticated(self, user):
+ # This must be kept in sync with user_can_edit_credentials_for_owner
+ # in lp.oci.interfaces.ociregistrycredentials.
+ return (
+ user.isOwner(self.obj) or
+ user.in_admin)
+
+
+class ViewOCIPushRule(AnonymousAuthorization):
+ """Anyone can view an `IOCIPushRule`."""
+ usedfor = IOCIPushRule
+
+
+class OCIPushRuleEdit(AuthorizationBase):
+ permission = 'launchpad.Edit'
+ usedfor = IOCIPushRule
+
+ def checkAuthenticated(self, user):
+ return (
+ user.isOwner(self.obj.recipe) or
+ user.in_commercial_admin or user.in_admin)
diff --git a/lib/lp/security.py b/lib/lp/security.py
index a87f341..71c71e8 100644
--- a/lib/lp/security.py
+++ b/lib/lp/security.py
@@ -26,11 +26,7 @@ from datetime import (
import pytz
from zope.interface import Interface
-from lp.app.security import (
- AnonymousAuthorization,
- AuthorizationBase,
- DelegatedAuthorization,
- )
+from lp.app.security import AuthorizationBase
from lp.archivepublisher.interfaces.publisherconfig import IPublisherConfig
from lp.bugs.interfaces.bugtarget import IOfficialBugTagTargetRestricted
from lp.bugs.interfaces.structuralsubscription import IStructuralSubscription
@@ -40,40 +36,9 @@ from lp.buildmaster.interfaces.builder import (
)
from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJob
from lp.buildmaster.interfaces.packagebuild import IPackageBuild
-from lp.charms.interfaces.charmbase import (
- ICharmBase,
- ICharmBaseSet,
- )
-from lp.charms.interfaces.charmrecipe import (
- ICharmRecipe,
- ICharmRecipeBuildRequest,
- )
-from lp.charms.interfaces.charmrecipebuild import ICharmRecipeBuild
-from lp.oci.interfaces.ocipushrule import IOCIPushRule
-from lp.oci.interfaces.ocirecipe import (
- IOCIRecipe,
- IOCIRecipeBuildRequest,
- )
-from lp.oci.interfaces.ocirecipebuild import IOCIRecipeBuild
-from lp.oci.interfaces.ocirecipesubscription import IOCIRecipeSubscription
-from lp.oci.interfaces.ociregistrycredentials import IOCIRegistryCredentials
from lp.registry.interfaces.role import IHasOwner
from lp.services.config import config
from lp.services.webapp.interfaces import ILaunchpadRoot
-from lp.snappy.interfaces.snap import (
- ISnap,
- ISnapBuildRequest,
- )
-from lp.snappy.interfaces.snapbase import (
- ISnapBase,
- ISnapBaseSet,
- )
-from lp.snappy.interfaces.snapbuild import ISnapBuild
-from lp.snappy.interfaces.snappyseries import (
- ISnappySeries,
- ISnappySeriesSet,
- )
-from lp.snappy.interfaces.snapsubscription import ISnapSubscription
def is_commercial_case(obj, user):
@@ -312,364 +277,3 @@ class EditPackageBuild(EditBuildFarmJob):
class ViewPublisherConfig(AdminByAdminsTeam):
usedfor = IPublisherConfig
-
-
-class ViewSnap(AuthorizationBase):
- """Private snaps are only visible to their owners and admins."""
- permission = 'launchpad.View'
- usedfor = ISnap
-
- def checkAuthenticated(self, user):
- return self.obj.visibleByUser(user.person)
-
- def checkUnauthenticated(self):
- return self.obj.visibleByUser(None)
-
-
-class EditSnap(AuthorizationBase):
- permission = 'launchpad.Edit'
- usedfor = ISnap
-
- def checkAuthenticated(self, user):
- return (
- user.isOwner(self.obj) or
- user.in_commercial_admin or user.in_admin)
-
-
-class AdminSnap(AuthorizationBase):
- """Restrict changing build settings on snap packages.
-
- The security of the non-virtualised build farm depends on these
- settings, so they can only be changed by "PPA"/commercial admins, or by
- "PPA" self admins on snap packages that they can already edit.
- """
- permission = 'launchpad.Admin'
- usedfor = ISnap
-
- def checkAuthenticated(self, user):
- if user.in_ppa_admin or user.in_commercial_admin or user.in_admin:
- return True
- return (
- user.in_ppa_self_admins
- and EditSnap(self.obj).checkAuthenticated(user))
-
-
-class SnapSubscriptionEdit(AuthorizationBase):
- permission = 'launchpad.Edit'
- usedfor = ISnapSubscription
-
- def checkAuthenticated(self, user):
- """Is the user able to edit a Snap recipe subscription?
-
- Any team member can edit a Snap recipe subscription for their
- team.
- Launchpad Admins can also edit any Snap recipe subscription.
- The owner of the subscribed Snap can edit the subscription. If
- the Snap owner is a team, then members of the team can edit
- the subscription.
- """
- return (user.inTeam(self.obj.snap.owner) or
- user.inTeam(self.obj.person) or
- user.inTeam(self.obj.subscribed_by) or
- user.in_admin)
-
-
-class SnapSubscriptionView(AuthorizationBase):
- permission = 'launchpad.View'
- usedfor = ISnapSubscription
-
- def checkUnauthenticated(self):
- return self.obj.snap.visibleByUser(None)
-
- def checkAuthenticated(self, user):
- return self.obj.snap.visibleByUser(user.person)
-
-
-class ViewSnapBuildRequest(DelegatedAuthorization):
- permission = 'launchpad.View'
- usedfor = ISnapBuildRequest
-
- def __init__(self, obj):
- super().__init__(obj, obj.snap, 'launchpad.View')
-
-
-class ViewSnapBuild(DelegatedAuthorization):
- permission = 'launchpad.View'
- usedfor = ISnapBuild
-
- def iter_objects(self):
- yield self.obj.snap
- yield self.obj.archive
-
-
-class EditSnapBuild(AdminByBuilddAdmin):
- permission = 'launchpad.Edit'
- usedfor = ISnapBuild
-
- def checkAuthenticated(self, user):
- """Check edit access for snap package builds.
-
- Allow admins, buildd admins, and the owner of the snap package.
- (Note that the requester of the build is required to be in the team
- that owns the snap package.)
- """
- auth_snap = EditSnap(self.obj.snap)
- if auth_snap.checkAuthenticated(user):
- return True
- return super().checkAuthenticated(user)
-
-
-class AdminSnapBuild(AdminByBuilddAdmin):
- usedfor = ISnapBuild
-
-
-class ViewSnappySeries(AnonymousAuthorization):
- """Anyone can view an `ISnappySeries`."""
- usedfor = ISnappySeries
-
-
-class EditSnappySeries(EditByRegistryExpertsOrAdmins):
- usedfor = ISnappySeries
-
-
-class EditSnappySeriesSet(EditByRegistryExpertsOrAdmins):
- usedfor = ISnappySeriesSet
-
-
-class ViewSnapBase(AnonymousAuthorization):
- """Anyone can view an `ISnapBase`."""
- usedfor = ISnapBase
-
-
-class EditSnapBase(EditByRegistryExpertsOrAdmins):
- usedfor = ISnapBase
-
-
-class EditSnapBaseSet(EditByRegistryExpertsOrAdmins):
- usedfor = ISnapBaseSet
-
-
-class ViewOCIRecipeBuildRequest(DelegatedAuthorization):
- permission = 'launchpad.View'
- usedfor = IOCIRecipeBuildRequest
-
- def __init__(self, obj):
- super().__init__(obj, obj.recipe, 'launchpad.View')
-
-
-class ViewOCIRecipe(AnonymousAuthorization):
- """Anyone can view public `IOCIRecipe`, but only subscribers can view
- private ones.
- """
- usedfor = IOCIRecipe
-
- def checkUnauthenticated(self):
- return self.obj.visibleByUser(None)
-
- def checkAuthenticated(self, user):
- return self.obj.visibleByUser(user.person)
-
-
-class EditOCIRecipe(AuthorizationBase):
- permission = 'launchpad.Edit'
- usedfor = IOCIRecipe
-
- def checkAuthenticated(self, user):
- return (
- user.isOwner(self.obj) or
- user.in_commercial_admin or user.in_admin)
-
-
-class AdminOCIRecipe(AuthorizationBase):
- """Restrict changing build settings on OCI recipes.
-
- The security of the non-virtualised build farm depends on these
- settings, so they can only be changed by "PPA"/commercial admins, or by
- "PPA" self admins on OCI recipes that they can already edit.
- """
- permission = 'launchpad.Admin'
- usedfor = IOCIRecipe
-
- def checkAuthenticated(self, user):
- if user.in_ppa_admin or user.in_commercial_admin or user.in_admin:
- return True
- return (
- user.in_ppa_self_admins
- and EditSnap(self.obj).checkAuthenticated(user))
-
-
-class OCIRecipeSubscriptionEdit(AuthorizationBase):
- permission = 'launchpad.Edit'
- usedfor = IOCIRecipeSubscription
-
- def checkAuthenticated(self, user):
- """Is the user able to edit an OCI recipe subscription?
-
- Any team member can edit a OCI recipe subscription for their
- team.
- Launchpad Admins can also edit any OCI recipe subscription.
- The owner of the subscribed OCI recipe can edit the subscription. If
- the OCI recipe owner is a team, then members of the team can edit
- the subscription.
- """
- return (user.inTeam(self.obj.recipe.owner) or
- user.inTeam(self.obj.person) or
- user.inTeam(self.obj.subscribed_by) or
- user.in_admin)
-
-
-class OCIRecipeSubscriptionView(AuthorizationBase):
- permission = 'launchpad.View'
- usedfor = IOCIRecipeSubscription
-
- def checkUnauthenticated(self):
- return self.obj.recipe.visibleByUser(None)
-
- def checkAuthenticated(self, user):
- return self.obj.recipe.visibleByUser(user.person)
-
-
-class ViewOCIRecipeBuild(DelegatedAuthorization):
- permission = 'launchpad.View'
- usedfor = IOCIRecipeBuild
-
- def iter_objects(self):
- yield self.obj.recipe
-
-
-class EditOCIRecipeBuild(AdminByBuilddAdmin):
- permission = 'launchpad.Edit'
- usedfor = IOCIRecipeBuild
-
- def checkAuthenticated(self, user):
- """Check edit access for OCI recipe builds.
-
- Allow admins, buildd admins, and the owner of the OCI recipe.
- (Note that the requester of the build is required to be in the team
- that owns the OCI recipe.)
- """
- auth_recipe = EditOCIRecipe(self.obj.recipe)
- if auth_recipe.checkAuthenticated(user):
- return True
- return super().checkAuthenticated(user)
-
-
-class AdminOCIRecipeBuild(AdminByBuilddAdmin):
- usedfor = IOCIRecipeBuild
-
-
-class ViewOCIRegistryCredentials(AuthorizationBase):
- permission = 'launchpad.View'
- usedfor = IOCIRegistryCredentials
-
- def checkAuthenticated(self, user):
- # This must be kept in sync with user_can_edit_credentials_for_owner
- # in lp.oci.interfaces.ociregistrycredentials.
- return (
- user.isOwner(self.obj) or
- user.in_admin)
-
-
-class ViewOCIPushRule(AnonymousAuthorization):
- """Anyone can view an `IOCIPushRule`."""
- usedfor = IOCIPushRule
-
-
-class OCIPushRuleEdit(AuthorizationBase):
- permission = 'launchpad.Edit'
- usedfor = IOCIPushRule
-
- def checkAuthenticated(self, user):
- return (
- user.isOwner(self.obj.recipe) or
- user.in_commercial_admin or user.in_admin)
-
-
-class ViewCharmRecipe(AuthorizationBase):
- """Private charm recipes are only visible to their owners and admins."""
- permission = 'launchpad.View'
- usedfor = ICharmRecipe
-
- def checkAuthenticated(self, user):
- return self.obj.visibleByUser(user.person)
-
- def checkUnauthenticated(self):
- return self.obj.visibleByUser(None)
-
-
-class EditCharmRecipe(AuthorizationBase):
- permission = 'launchpad.Edit'
- usedfor = ICharmRecipe
-
- def checkAuthenticated(self, user):
- return (
- user.isOwner(self.obj) or
- user.in_commercial_admin or user.in_admin)
-
-
-class AdminCharmRecipe(AuthorizationBase):
- """Restrict changing build settings on charm recipes.
-
- The security of the non-virtualised build farm depends on these
- settings, so they can only be changed by "PPA"/commercial admins, or by
- "PPA" self admins on charm recipes that they can already edit.
- """
- permission = 'launchpad.Admin'
- usedfor = ICharmRecipe
-
- def checkAuthenticated(self, user):
- if user.in_ppa_admin or user.in_commercial_admin or user.in_admin:
- return True
- return (
- user.in_ppa_self_admins
- and EditCharmRecipe(self.obj).checkAuthenticated(user))
-
-
-class ViewCharmRecipeBuildRequest(DelegatedAuthorization):
- permission = 'launchpad.View'
- usedfor = ICharmRecipeBuildRequest
-
- def __init__(self, obj):
- super().__init__(obj, obj.recipe, 'launchpad.View')
-
-
-class ViewCharmRecipeBuild(DelegatedAuthorization):
- permission = 'launchpad.View'
- usedfor = ICharmRecipeBuild
-
- def iter_objects(self):
- yield self.obj.recipe
-
-
-class EditCharmRecipeBuild(AdminByBuilddAdmin):
- permission = 'launchpad.Edit'
- usedfor = ICharmRecipeBuild
-
- def checkAuthenticated(self, user):
- """Check edit access for snap package builds.
-
- Allow admins, buildd admins, and the owner of the charm recipe.
- (Note that the requester of the build is required to be in the team
- that owns the charm recipe.)
- """
- auth_recipe = EditCharmRecipe(self.obj.recipe)
- if auth_recipe.checkAuthenticated(user):
- return True
- return super().checkAuthenticated(user)
-
-
-class AdminCharmRecipeBuild(AdminByBuilddAdmin):
- usedfor = ICharmRecipeBuild
-
-
-class ViewCharmBase(AnonymousAuthorization):
- """Anyone can view an `ICharmBase`."""
- usedfor = ICharmBase
-
-
-class EditCharmBase(EditByRegistryExpertsOrAdmins):
- usedfor = ICharmBase
-
-
-class EditCharmBaseSet(EditByRegistryExpertsOrAdmins):
- usedfor = ICharmBaseSet
diff --git a/lib/lp/snappy/configure.zcml b/lib/lp/snappy/configure.zcml
index 3dcc7cc..5f8081a 100644
--- a/lib/lp/snappy/configure.zcml
+++ b/lib/lp/snappy/configure.zcml
@@ -11,6 +11,7 @@
xmlns:xmlrpc="http://namespaces.zope.org/xmlrpc"
i18n_domain="launchpad">
+ <authorizations module=".security" />
<include package=".browser" />
<include file="vocabularies.zcml" />
diff --git a/lib/lp/snappy/security.py b/lib/lp/snappy/security.py
new file mode 100644
index 0000000..1c24258
--- /dev/null
+++ b/lib/lp/snappy/security.py
@@ -0,0 +1,165 @@
+# 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 snappy package."""
+
+__all__ = []
+
+from lp.app.security import (
+ AnonymousAuthorization,
+ AuthorizationBase,
+ DelegatedAuthorization,
+ )
+from lp.security import (
+ AdminByBuilddAdmin,
+ EditByRegistryExpertsOrAdmins,
+ )
+from lp.snappy.interfaces.snap import (
+ ISnap,
+ ISnapBuildRequest,
+ )
+from lp.snappy.interfaces.snapbase import (
+ ISnapBase,
+ ISnapBaseSet,
+ )
+from lp.snappy.interfaces.snapbuild import ISnapBuild
+from lp.snappy.interfaces.snappyseries import (
+ ISnappySeries,
+ ISnappySeriesSet,
+ )
+from lp.snappy.interfaces.snapsubscription import ISnapSubscription
+
+
+class ViewSnap(AuthorizationBase):
+ """Private snaps are only visible to their owners and admins."""
+ permission = 'launchpad.View'
+ usedfor = ISnap
+
+ def checkAuthenticated(self, user):
+ return self.obj.visibleByUser(user.person)
+
+ def checkUnauthenticated(self):
+ return self.obj.visibleByUser(None)
+
+
+class EditSnap(AuthorizationBase):
+ permission = 'launchpad.Edit'
+ usedfor = ISnap
+
+ def checkAuthenticated(self, user):
+ return (
+ user.isOwner(self.obj) or
+ user.in_commercial_admin or user.in_admin)
+
+
+class AdminSnap(AuthorizationBase):
+ """Restrict changing build settings on snap packages.
+
+ The security of the non-virtualised build farm depends on these
+ settings, so they can only be changed by "PPA"/commercial admins, or by
+ "PPA" self admins on snap packages that they can already edit.
+ """
+ permission = 'launchpad.Admin'
+ usedfor = ISnap
+
+ def checkAuthenticated(self, user):
+ if user.in_ppa_admin or user.in_commercial_admin or user.in_admin:
+ return True
+ return (
+ user.in_ppa_self_admins
+ and EditSnap(self.obj).checkAuthenticated(user))
+
+
+class SnapSubscriptionEdit(AuthorizationBase):
+ permission = 'launchpad.Edit'
+ usedfor = ISnapSubscription
+
+ def checkAuthenticated(self, user):
+ """Is the user able to edit a Snap recipe subscription?
+
+ Any team member can edit a Snap recipe subscription for their
+ team.
+ Launchpad Admins can also edit any Snap recipe subscription.
+ The owner of the subscribed Snap can edit the subscription. If
+ the Snap owner is a team, then members of the team can edit
+ the subscription.
+ """
+ return (user.inTeam(self.obj.snap.owner) or
+ user.inTeam(self.obj.person) or
+ user.inTeam(self.obj.subscribed_by) or
+ user.in_admin)
+
+
+class SnapSubscriptionView(AuthorizationBase):
+ permission = 'launchpad.View'
+ usedfor = ISnapSubscription
+
+ def checkUnauthenticated(self):
+ return self.obj.snap.visibleByUser(None)
+
+ def checkAuthenticated(self, user):
+ return self.obj.snap.visibleByUser(user.person)
+
+
+class ViewSnapBuildRequest(DelegatedAuthorization):
+ permission = 'launchpad.View'
+ usedfor = ISnapBuildRequest
+
+ def __init__(self, obj):
+ super().__init__(obj, obj.snap, 'launchpad.View')
+
+
+class ViewSnapBuild(DelegatedAuthorization):
+ permission = 'launchpad.View'
+ usedfor = ISnapBuild
+
+ def iter_objects(self):
+ yield self.obj.snap
+ yield self.obj.archive
+
+
+class EditSnapBuild(AdminByBuilddAdmin):
+ permission = 'launchpad.Edit'
+ usedfor = ISnapBuild
+
+ def checkAuthenticated(self, user):
+ """Check edit access for snap package builds.
+
+ Allow admins, buildd admins, and the owner of the snap package.
+ (Note that the requester of the build is required to be in the team
+ that owns the snap package.)
+ """
+ auth_snap = EditSnap(self.obj.snap)
+ if auth_snap.checkAuthenticated(user):
+ return True
+ return super().checkAuthenticated(user)
+
+
+class AdminSnapBuild(AdminByBuilddAdmin):
+ usedfor = ISnapBuild
+
+
+class ViewSnappySeries(AnonymousAuthorization):
+ """Anyone can view an `ISnappySeries`."""
+ usedfor = ISnappySeries
+
+
+class EditSnappySeries(EditByRegistryExpertsOrAdmins):
+ usedfor = ISnappySeries
+
+
+class EditSnappySeriesSet(EditByRegistryExpertsOrAdmins):
+ usedfor = ISnappySeriesSet
+
+
+class ViewSnapBase(AnonymousAuthorization):
+ """Anyone can view an `ISnapBase`."""
+ usedfor = ISnapBase
+
+
+class EditSnapBase(EditByRegistryExpertsOrAdmins):
+ usedfor = ISnapBase
+
+
+class EditSnapBaseSet(EditByRegistryExpertsOrAdmins):
+ usedfor = ISnapBaseSet
Follow ups