Browse Source

Merge "Move list_roles_for_trust enforcement to policies"

changes/22/678322/10
Zuul 1 week ago
parent
commit
9b18691edf

+ 37
- 2
keystone/api/trusts.py View File

@@ -340,13 +340,48 @@ class TrustResource(ks_flask.ResourceBase):
340 340
 # URL additions and does not have a collection key/member_key, we use
341 341
 # the flask-restful Resource, not the keystone ResourceBase
342 342
 class RolesForTrustListResource(flask_restful.Resource):
343
+
344
+    @property
345
+    def oslo_context(self):
346
+        return flask.request.environ.get(context.REQUEST_CONTEXT_ENV, None)
347
+
343 348
     def get(self, trust_id):
344
-        ENFORCER.enforce_call(action='identity:list_roles_for_trust')
349
+        ENFORCER.enforce_call(action='identity:list_roles_for_trust',
350
+                              build_target=_build_trust_target_enforcement)
351
+
345 352
         # NOTE(morgan): This duplicates a little of the .get_trust from the
346 353
         # main resource, as it needs some of the same logic. However, due to
347 354
         # how flask-restful works, this should be fully encapsulated
355
+
356
+        if self.oslo_context.is_admin:
357
+            # policies are not loaded for the is_admin context, so need to
358
+            # block access here
359
+            raise exception.ForbiddenAction(
360
+                action=_('Requested user has no relation to this trust'))
361
+
348 362
         trust = PROVIDERS.trust_api.get_trust(trust_id)
349
-        _trustor_trustee_only(trust)
363
+
364
+        # NOTE(cmurphy) As of Train, the default policies enforce the
365
+        # identity:list_roles_for_trust rule. However, in case the
366
+        # identity:list_roles_for_trust rule has been locally overridden by the
367
+        # default that would have been produced by the sample config, we need
368
+        # to enforce it again and warn that the behavior is changing.
369
+        rules = policy._ENFORCER._enforcer.rules.get(
370
+            'identity:list_roles_for_trust')
371
+        # rule check_str is ""
372
+        if isinstance(rules, op_checks.TrueCheck):
373
+            LOG.warning(
374
+                "The policy check string for rule "
375
+                "\"identity:list_roles_for_trust\" has been overridden to "
376
+                "\"always true\". In the next release, this will cause the "
377
+                "\"identity:list_roles_for_trust\" action to be fully "
378
+                "permissive as hardcoded enforcement will be removed. To "
379
+                "correct this issue, either stop overriding the "
380
+                "\"identity:get_trust\" rule in config to accept the "
381
+                "defaults, or explicitly set a rule that is not empty."
382
+            )
383
+            _trustor_trustee_only(trust)
384
+
350 385
         _normalize_trust_expires_at(trust)
351 386
         _normalize_trust_roles(trust)
352 387
         return {'roles': trust['roles'],

+ 2
- 1
keystone/cmd/status.py View File

@@ -37,7 +37,8 @@ class Checks(upgradecheck.UpgradeCommands):
37 37
         rules = [
38 38
             'identity:list_trusts',
39 39
             'identity:delete_trust',
40
-            'identity:get_trust'
40
+            'identity:get_trust',
41
+            'identity:list_roles_for_trust'
41 42
         ]
42 43
         failed_rules = []
43 44
         for rule in rules:

+ 1
- 1
keystone/common/policies/trust.py View File

@@ -57,7 +57,7 @@ trust_policies = [
57 57
                      'method': 'HEAD'}]),
58 58
     policy.DocumentedRuleDefault(
59 59
         name=base.IDENTITY % 'list_roles_for_trust',
60
-        check_str='',
60
+        check_str=RULE_TRUSTOR + ' or ' + RULE_TRUSTEE,
61 61
         scope_types=['project'],
62 62
         description='List roles delegated by a trust.',
63 63
         operations=[{'path': '/v3/OS-TRUST/trusts/{trust_id}/roles',

+ 51
- 0
keystone/tests/unit/protection/v3/test_trusts.py View File

@@ -111,6 +111,7 @@ class TrustTests(base_classes.TestCaseWithBootstrap,
111 111
                 'identity:list_trusts': '',
112 112
                 'identity:delete_trust': '',
113 113
                 'identity:get_trust': '',
114
+                'identity:list_roles_for_trust': '',
114 115
             }
115 116
             f.write(jsonutils.dumps(overridden_policies))
116 117
 
@@ -285,6 +286,18 @@ class SystemAdminTests(TrustTests, _AdminTestsMixin):
285 286
                 expected_status_code=http_client.FORBIDDEN
286 287
             )
287 288
 
289
+    def test_admin_cannot_list_roles_for_other_user_overridden_defaults(self):
290
+        self._override_policy_old_defaults()
291
+        PROVIDERS.trust_api.create_trust(
292
+            self.trust_id, **self.trust_data)
293
+
294
+        with self.test_client() as c:
295
+            c.get(
296
+                '/v3/OS-TRUST/trusts/%s/roles' % self.trust_id,
297
+                headers=self.headers,
298
+                expected_status_code=http_client.FORBIDDEN
299
+            )
300
+
288 301
 
289 302
 class ProjectUserTests(TrustTests):
290 303
     """Tests for all project users."""
@@ -682,3 +695,41 @@ class ProjectUserTests(TrustTests):
682 695
                 headers=self.trustee_headers
683 696
             )
684 697
         self.assertEqual(r.json['trust']['id'], self.trust_id)
698
+
699
+    def test_trustor_can_list_trust_roles_overridden_default(self):
700
+        self._override_policy_old_defaults()
701
+        PROVIDERS.trust_api.create_trust(
702
+            self.trust_id, **self.trust_data)
703
+
704
+        with self.test_client() as c:
705
+            r = c.get(
706
+                '/v3/OS-TRUST/trusts/%s/roles' % self.trust_id,
707
+                headers=self.trustor_headers
708
+            )
709
+        self.assertEqual(r.json['roles'][0]['id'],
710
+                         self.bootstrapper.member_role_id)
711
+
712
+    def test_trustee_can_list_trust_roles_overridden_default(self):
713
+        self._override_policy_old_defaults()
714
+        PROVIDERS.trust_api.create_trust(
715
+            self.trust_id, **self.trust_data)
716
+
717
+        with self.test_client() as c:
718
+            r = c.get(
719
+                '/v3/OS-TRUST/trusts/%s/roles' % self.trust_id,
720
+                headers=self.trustee_headers
721
+            )
722
+        self.assertEqual(r.json['roles'][0]['id'],
723
+                         self.bootstrapper.member_role_id)
724
+
725
+    def test_user_cannot_list_trust_roles_other_user_overridden_default(self):
726
+        self._override_policy_old_defaults()
727
+        PROVIDERS.trust_api.create_trust(
728
+            self.trust_id, **self.trust_data)
729
+
730
+        with self.test_client() as c:
731
+            c.get(
732
+                '/v3/OS-TRUST/trusts/%s/roles' % self.trust_id,
733
+                headers=self.other_headers,
734
+                expected_status_code=http_client.FORBIDDEN
735
+            )

+ 4
- 2
keystone/tests/unit/test_cli.py View File

@@ -1867,7 +1867,8 @@ class CliStatusTestCase(unit.SQLDriverOverrides, unit.TestCase):
1867 1867
             overridden_policies = {
1868 1868
                 'identity:list_trusts': '',
1869 1869
                 'identity:delete_trust': '',
1870
-                'identity:get_trust': ''
1870
+                'identity:get_trust': '',
1871
+                'identity:list_roles_for_trust': ''
1871 1872
             }
1872 1873
             f.write(jsonutils.dumps(overridden_policies))
1873 1874
         result = self.checks.check_trust_policies_are_not_empty()
@@ -1876,7 +1877,8 @@ class CliStatusTestCase(unit.SQLDriverOverrides, unit.TestCase):
1876 1877
             overridden_policies = {
1877 1878
                 'identity:list_trusts': 'rule:admin_required',
1878 1879
                 'identity:delete_trust': 'rule:admin_required',
1879
-                'identity:get_trust': 'rule:admin_required'
1880
+                'identity:get_trust': 'rule:admin_required',
1881
+                'identity:list_roles_for_trust': 'rule:admin_required'
1880 1882
             }
1881 1883
             f.write(jsonutils.dumps(overridden_policies))
1882 1884
         result = self.checks.check_trust_policies_are_not_empty()

Loading…
Cancel
Save