launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #13603
[Merge] lp:~adeuring/launchpad/sec-adapter-projectgroup-milestone into lp:launchpad
Abel Deuring has proposed merging lp:~adeuring/launchpad/sec-adapter-projectgroup-milestone into lp:launchpad.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~adeuring/launchpad/sec-adapter-projectgroup-milestone/+merge/130800
This branch adds a security adapter for project milestones.
We want to keep data from private products completely private,
this includes also class ProjectMilestone, the "project
representation" of milestones for products.
The changes are simple:
- require the permission launchpad.View for all properties of
IProjectGroupMilestone
- delegate the authorization to the parent product.
tests:
./bin/test -vvt lp.registry.tests.test_milestone.ProjectMilestoneSecurityAdaperTestCase
no lint
--
https://code.launchpad.net/~adeuring/launchpad/sec-adapter-projectgroup-milestone/+merge/130800
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~adeuring/launchpad/sec-adapter-projectgroup-milestone into lp:launchpad.
=== modified file 'lib/lp/registry/configure.zcml'
--- lib/lp/registry/configure.zcml 2012-10-19 19:09:35 +0000
+++ lib/lp/registry/configure.zcml 2012-10-22 13:56:22 +0000
@@ -1102,7 +1102,8 @@
<class
class="lp.registry.model.milestone.ProjectMilestone">
- <allow
+ <require
+ permission="launchpad.View"
interface="lp.registry.interfaces.milestone.IProjectGroupMilestone"/>
</class>
<adapter
=== modified file 'lib/lp/registry/tests/test_milestone.py'
--- lib/lp/registry/tests/test_milestone.py 2012-10-19 14:51:41 +0000
+++ lib/lp/registry/tests/test_milestone.py 2012-10-22 13:56:22 +0000
@@ -220,7 +220,7 @@
self.assertRaises(Unauthorized, setattr, obj, name, None)
def test_access_for_anonymous(self):
- # Anonymous users have access to to public attributes of
+ # Anonymous users have access to public attributes of
# milestones for private and public products.
with person_logged_in(ANONYMOUS):
self.assertAccessAuthorized(
@@ -549,3 +549,128 @@
self.assertEqual(
IInformationType(milestone).information_type,
information_type)
+
+
+class ProjectMilestoneSecurityAdaperTestCase(TestCaseWithFactory):
+ """A TestCase for the security adapter of IProjectGroupMilestone."""
+
+ layer = DatabaseFunctionalLayer
+
+ def setUp(self):
+ super(ProjectMilestoneSecurityAdaperTestCase, self).setUp()
+ project_group = self.factory.makeProject()
+ public_product = self.factory.makeProduct(project=project_group)
+ self.factory.makeMilestone(
+ product=public_product, name='public-milestone')
+ self.proprietary_product_owner = self.factory.makePerson()
+ self.proprietary_product = self.factory.makeProduct(
+ project=project_group,
+ owner=self.proprietary_product_owner,
+ information_type=InformationType.PROPRIETARY)
+ self.factory.makeMilestone(
+ product=self.proprietary_product, name='proprietary-milestone')
+ with person_logged_in(self.proprietary_product_owner):
+ milestone_1, milestone_2 = project_group.milestones
+ if milestone_1.name == 'public-milestone':
+ self.public_projectgroup_milestone = milestone_1
+ self.proprietary_projectgroup_milestone = milestone_2
+ else:
+ self.public_projectgroup_milestone = milestone_2
+ self.proprietary_projectgroup_milestone = milestone_1
+
+ expected_get_permissions = {
+ 'launchpad.View': set((
+ '_getOfficialTagClause', 'active', 'addBugSubscription',
+ 'addBugSubscriptionFilter', 'addSubscription',
+ 'bug_subscriptions', 'bugtasks', 'closeBugsAndBlueprints',
+ 'code_name', 'createProductRelease', 'dateexpected',
+ 'destroySelf', 'displayname', 'distribution', 'distroseries',
+ 'getBugTaskWeightFunction', 'getSpecifications',
+ 'getSubscription', 'getSubscriptions',
+ 'getUsedBugTagsWithOpenCounts', 'id', 'name',
+ 'official_bug_tags', 'parent_subscription_target', 'product',
+ 'product_release', 'productseries', 'removeBugSubscription',
+ 'searchTasks', 'series_target', 'summary', 'target',
+ 'target_type_display', 'title', 'userCanAlterBugSubscription',
+ 'userCanAlterSubscription', 'userHasBugSubscriptions')),
+ }
+
+ def test_get_permissions(self):
+ checker = getChecker(self.public_projectgroup_milestone)
+ self.checkPermissions(
+ self.expected_get_permissions, checker.get_permissions, 'get')
+
+ # Project milestones are read-only objects, so no set permissions.
+ expected_set_permissions = {
+ }
+
+ def test_set_permissions(self):
+ checker = getChecker(self.public_projectgroup_milestone)
+ self.checkPermissions(
+ self.expected_set_permissions, checker.set_permissions, 'set')
+
+ def assertAccessAuthorized(self, attribute_names, obj):
+ # Try to access the given attributes of obj. No exception
+ # should be raised.
+ for name in attribute_names:
+ # class Milestone does not implement all attributes defined by
+ # class IMilestone. AttributeErrors caused by attempts to
+ # access these attribues are not relevant here: We simply
+ # want to be sure that no Unauthorized error is raised.
+ try:
+ getattr(obj, name)
+ except AttributeError:
+ pass
+
+ def assertAccessUnauthorized(self, attribute_names, obj):
+ # Try to access the given attributes of obj. Unauthorized
+ # should be raised.
+ for name in attribute_names:
+ self.assertRaises(Unauthorized, getattr, obj, name)
+
+ def test_access_for_anonymous(self):
+ # Anonymous users have access to public project group milestones.
+ with person_logged_in(ANONYMOUS):
+ self.assertAccessAuthorized(
+ self.expected_get_permissions['launchpad.View'],
+ self.public_projectgroup_milestone)
+
+ # ...but not to private project group milestones.
+ self.assertAccessUnauthorized(
+ self.expected_get_permissions['launchpad.View'],
+ self.proprietary_projectgroup_milestone)
+
+ def test_access_for_ordinary_user(self):
+ # Regular users have to public project group milestones.
+ user = self.factory.makePerson()
+ with person_logged_in(user):
+ self.assertAccessAuthorized(
+ self.expected_get_permissions['launchpad.View'],
+ self.public_projectgroup_milestone)
+
+ # ...but not to private project group milestones.
+ self.assertAccessUnauthorized(
+ self.expected_get_permissions['launchpad.View'],
+ self.proprietary_projectgroup_milestone)
+
+ def test_access_for_user_with_grant_for_private_product(self):
+ # Users with a policy grant for a private product have access
+ # to private project group milestones.
+ user = self.factory.makePerson()
+ with person_logged_in(self.proprietary_product_owner):
+ getUtility(IService, 'sharing').sharePillarInformation(
+ self.proprietary_product, user, self.proprietary_product_owner,
+ {InformationType.PROPRIETARY: SharingPermission.ALL})
+
+ with person_logged_in(user):
+ self.assertAccessAuthorized(
+ self.expected_get_permissions['launchpad.View'],
+ self.proprietary_projectgroup_milestone)
+
+ def test_access_for_product_owner(self):
+ # The owner of a private product can access a rpivate project group
+ # milestone.
+ with person_logged_in(self.proprietary_product_owner):
+ self.assertAccessAuthorized(
+ self.expected_get_permissions['launchpad.View'],
+ self.proprietary_projectgroup_milestone)
=== modified file 'lib/lp/security.py'
--- lib/lp/security.py 2012-10-19 12:58:33 +0000
+++ lib/lp/security.py 2012-10-22 13:56:22 +0000
@@ -718,6 +718,15 @@
user.in_admin)
+class ViewProjectMilestone(DelegatedAuthorization):
+ permission = 'launchpad.View'
+ usedfor = IProjectGroupMilestone
+
+ def __init__(self, obj):
+ super(ViewProjectMilestone, self).__init__(
+ obj, obj.product, 'launchpad.View')
+
+
class EditProjectMilestoneNever(AuthorizationBase):
permission = 'launchpad.Edit'
usedfor = IProjectGroupMilestone
Follow ups