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
_______________________________________________ Mailing list: https://launchpad.net/~launchpad-reviewers Post to : launchpad-reviewers@lists.launchpad.net Unsubscribe : https://launchpad.net/~launchpad-reviewers More help : https://help.launchpad.net/ListHelp