summaryrefslogtreecommitdiff
blob: abf17489cd98363477cd5d75d883123bed920720 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
From 3fb363dc8331f1970e62d139d33da3f51f607ebe Mon Sep 17 00:00:00 2001
From: Boris Bobrov <breton@cynicmansion.ru>
Date: Mon, 17 Apr 2017 00:28:07 +0300
Subject: [PATCH] Do not fetch group assignments without groups

Without the change, the method fetched all assignments for a project
or domain, regardless of who has the assignment, user or group. This
led to situation when federated user without groups could scope a token
with other user's rules.

Return empty list of assignments if no groups were passed.

Closes-Bug: 1677723
Change-Id: I65f5be915bef2f979e70b043bde27064e970349d
(cherry picked from commit d61fc5b707a5209104b194d84e22eede84efccb3)
---
 keystone/assignment/core.py               |  5 +++
 keystone/tests/unit/test_v3_federation.py | 58 +++++++++++++++++++++++++++++++
 2 files changed, 63 insertions(+)

diff --git a/keystone/assignment/core.py b/keystone/assignment/core.py
index eccc22d..8fba77e 100644
--- a/keystone/assignment/core.py
+++ b/keystone/assignment/core.py
@@ -126,6 +126,11 @@ class Manager(manager.Manager):
 
     def get_roles_for_groups(self, group_ids, project_id=None, domain_id=None):
         """Get a list of roles for this group on domain and/or project."""
+        # if no group ids were passed, there are no roles. Without this check,
+        # all assignments for the project or domain will be fetched,
+        # which is not what we want.
+        if not group_ids:
+            return []
         if project_id is not None:
             self.resource_api.get_project(project_id)
             assignment_list = self.list_role_assignments(
diff --git a/keystone/tests/unit/test_v3_federation.py b/keystone/tests/unit/test_v3_federation.py
index 0f5148f..03509b8 100644
--- a/keystone/tests/unit/test_v3_federation.py
+++ b/keystone/tests/unit/test_v3_federation.py
@@ -1908,6 +1908,34 @@ class FederatedTokenTests(test_v3.RestfulTestCase, FederatedSetupMixin):
         token_groups = token_resp['token']['user']['OS-FEDERATION']['groups']
         self.assertEqual(0, len(token_groups))
 
+    def test_issue_scoped_token_no_groups(self):
+        """Verify that token without groups cannot get scoped to project.
+
+        This test is required because of bug 1677723.
+        """
+        # issue unscoped token with no groups
+        r = self._issue_unscoped_token(assertion='USER_NO_GROUPS_ASSERTION')
+        self.assertIsNotNone(r.headers.get('X-Subject-Token'))
+        token_resp = r.json_body
+        token_groups = token_resp['token']['user']['OS-FEDERATION']['groups']
+        self.assertEqual(0, len(token_groups))
+        unscoped_token = r.headers.get('X-Subject-Token')
+
+        # let admin get roles in a project
+        self.proj_employees
+        admin = unit.new_user_ref(CONF.identity.default_domain_id)
+        self.identity_api.create_user(admin)
+        self.assignment_api.create_grant(self.role_admin['id'],
+                                         user_id=admin['id'],
+                                         project_id=self.proj_employees['id'])
+
+        # try to scope the token. It should fail
+        scope = self._scope_request(
+            unscoped_token, 'project', self.proj_employees['id']
+        )
+        self.v3_create_token(
+            scope, expected_status=http_client.UNAUTHORIZED)
+
     def test_issue_unscoped_token_malformed_environment(self):
         """Test whether non string objects are filtered out.
 
@@ -3319,6 +3347,36 @@ class ShadowMappingTests(test_v3.RestfulTestCase, FederatedSetupMixin):
                 self.expected_results[project_name], roles[0]['name']
             )
 
+    def test_user_gets_only_assigned_roles(self):
+        # in bug 1677723 user could get roles outside of what was assigned
+        # to them. This test verifies that this is no longer true.
+        # Authenticate once to create the projects
+        response = self._issue_unscoped_token()
+        self.assertValidMappedUser(response.json_body['token'])
+        unscoped_token = response.headers.get('X-Subject-Token')
+
+        # Assign admin role to newly-created project to another user
+        staging_project = self.resource_api.get_project_by_name(
+            'Staging', self.idp['domain_id']
+        )
+        admin = unit.new_user_ref(CONF.identity.default_domain_id)
+        self.identity_api.create_user(admin)
+        self.assignment_api.create_grant(self.role_admin['id'],
+                                         user_id=admin['id'],
+                                         project_id=staging_project['id'])
+
+        # Authenticate again with the federated user and verify roles
+        response = self._issue_unscoped_token()
+        self.assertValidMappedUser(response.json_body['token'])
+        unscoped_token = response.headers.get('X-Subject-Token')
+        scope = self._scope_request(
+            unscoped_token, 'project', staging_project['id']
+        )
+        response = self.v3_create_token(scope)
+        roles = response.json_body['token']['roles']
+        role_ids = [r['id'] for r in roles]
+        self.assertNotIn(self.role_admin['id'], role_ids)
+
 
 class JsonHomeTests(test_v3.RestfulTestCase, test_v3.JsonHomeTestMixin):
     JSON_HOME_DATA = {
-- 
2.1.4