blob: d0a8748fd2ef0dcaa8f47f6873da6c7347dc6934 [file] [log] [blame]
ZhiQiang Fan39f97222013-09-20 04:49:44 +08001# Copyright 2012 OpenStack Foundation
nayna-patelb35f7232013-06-28 07:08:44 +00002# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15
16from tempest.api.identity import base
ZhangHongtao74e1df52017-03-13 18:32:43 +080017from tempest import config
Ken'ichi Ohmichi7bd25752017-03-10 10:45:39 -080018from tempest.lib.common.utils import data_utils
Ken'ichi Ohmichieeabdd22017-01-27 17:46:00 -080019from tempest.lib import decorators
nayna-patelb35f7232013-06-28 07:08:44 +000020
ZhangHongtao74e1df52017-03-13 18:32:43 +080021CONF = config.CONF
22
nayna-patelb35f7232013-06-28 07:08:44 +000023
Masayuki Igawabe64ed32014-02-19 14:32:03 +090024class TokensV3TestJSON(base.BaseIdentityV3AdminTest):
zhufla7635d72020-04-29 14:36:41 +080025 """Test tokens"""
nayna-patelb35f7232013-06-28 07:08:44 +000026
Felipe Monteiro60ebc5d2017-07-12 04:13:37 +010027 credentials = ['primary', 'admin', 'alt']
28
Ken'ichi Ohmichieeabdd22017-01-27 17:46:00 -080029 @decorators.idempotent_id('565fa210-1da1-4563-999b-f7b5b67cf112')
Brant Knudsonc5553292014-03-15 11:06:05 -050030 def test_rescope_token(self):
Brant Knudson5ee44a42014-03-16 10:55:21 -050031 """Rescope a token.
32
33 An unscoped token can be requested, that token can be used to request a
34 scoped token. The scoped token can be revoked, and the original token
35 used to get a token in a different project.
36
Brant Knudsonc5553292014-03-15 11:06:05 -050037 """
38
39 # Create a user.
Zack Feldsteind8c5f7a2015-12-14 10:44:07 -060040 user_password = data_utils.rand_password()
Mitya_Eremeevaca819b2021-11-18 19:24:28 +030041 user = self.create_test_user(password=user_password,
42 domain_id=CONF.identity.default_domain_id)
Brant Knudsonc5553292014-03-15 11:06:05 -050043
Brant Knudson5ee44a42014-03-16 10:55:21 -050044 # Create a couple projects
Martin Kopec213d0a42023-11-30 10:28:14 +010045 project1_name = data_utils.rand_name(
46 name=self.__class__.__name__, prefix=CONF.resource_name_prefix)
Mitya_Eremeevaca819b2021-11-18 19:24:28 +030047 project1 = self.setup_test_project(
48 name=project1_name, domain_id=CONF.identity.default_domain_id)
Brant Knudson5ee44a42014-03-16 10:55:21 -050049
Martin Kopec213d0a42023-11-30 10:28:14 +010050 project2_name = data_utils.rand_name(
51 name=self.__class__.__name__, prefix=CONF.resource_name_prefix)
Mitya_Eremeevaca819b2021-11-18 19:24:28 +030052 project2 = self.setup_test_project(
53 name=project2_name, domain_id=CONF.identity.default_domain_id)
Yaroslav Lobankov47a93ab2016-02-07 16:32:49 -060054 self.addCleanup(self.projects_client.delete_project, project2['id'])
Brant Knudsonc5553292014-03-15 11:06:05 -050055
56 # Create a role
zhufl66b616a2017-04-11 15:00:32 +080057 role = self.setup_test_role()
Brant Knudsonc5553292014-03-15 11:06:05 -050058
Brant Knudson5ee44a42014-03-16 10:55:21 -050059 # Grant the user the role on both projects.
ghanshyam2e6fb562016-09-06 11:14:31 +090060 self.roles_client.create_user_role_on_project(project1['id'],
Arx Cruz24bcb882016-02-10 15:20:16 +010061 user['id'],
62 role['id'])
Brant Knudson5ee44a42014-03-16 10:55:21 -050063
ghanshyam2e6fb562016-09-06 11:14:31 +090064 self.roles_client.create_user_role_on_project(project2['id'],
Arx Cruz24bcb882016-02-10 15:20:16 +010065 user['id'],
66 role['id'])
Brant Knudsonc5553292014-03-15 11:06:05 -050067
68 # Get an unscoped token.
Jamie Lennox97504612015-02-26 16:47:06 +110069 token_auth = self.token.auth(user_id=user['id'],
David Kranzd8ccb792014-12-29 11:32:05 -050070 password=user_password)
Brant Knudsonc5553292014-03-15 11:06:05 -050071
David Kranzd8ccb792014-12-29 11:32:05 -050072 token_id = token_auth.response['x-subject-token']
Brant Knudsonc5553292014-03-15 11:06:05 -050073 orig_expires_at = token_auth['token']['expires_at']
Brant Knudsonc5553292014-03-15 11:06:05 -050074 orig_user = token_auth['token']['user']
75
likui19b70a32020-12-02 13:25:18 +080076 self.assertIsInstance(token_auth['token']['expires_at'], str)
77 self.assertIsInstance(token_auth['token']['issued_at'], str)
Brant Knudsonc5553292014-03-15 11:06:05 -050078 self.assertEqual(['password'], token_auth['token']['methods'])
79 self.assertEqual(user['id'], token_auth['token']['user']['id'])
80 self.assertEqual(user['name'], token_auth['token']['user']['name'])
gongxiao5092b812017-04-14 08:50:32 +080081 self.assertEqual(CONF.identity.default_domain_id,
Brant Knudsonc5553292014-03-15 11:06:05 -050082 token_auth['token']['user']['domain']['id'])
gongxiao5092b812017-04-14 08:50:32 +080083 self.assertIsNotNone(token_auth['token']['user']['domain']['name'])
Brant Knudsonc5553292014-03-15 11:06:05 -050084 self.assertNotIn('catalog', token_auth['token'])
85 self.assertNotIn('project', token_auth['token'])
86 self.assertNotIn('roles', token_auth['token'])
87
88 # Use the unscoped token to get a scoped token.
gongxiao5092b812017-04-14 08:50:32 +080089 token_auth = self.token.auth(
90 token=token_id,
91 project_name=project1_name,
92 project_domain_id=CONF.identity.default_domain_id)
David Kranzd8ccb792014-12-29 11:32:05 -050093 token1_id = token_auth.response['x-subject-token']
Brant Knudsonc5553292014-03-15 11:06:05 -050094
95 self.assertEqual(orig_expires_at, token_auth['token']['expires_at'],
96 'Expiration time should match original token')
likui19b70a32020-12-02 13:25:18 +080097 self.assertIsInstance(token_auth['token']['issued_at'], str)
Brant Knudsonc5553292014-03-15 11:06:05 -050098 self.assertEqual(set(['password', 'token']),
99 set(token_auth['token']['methods']))
100 self.assertEqual(orig_user, token_auth['token']['user'],
101 'User should match original token')
102 self.assertIsInstance(token_auth['token']['catalog'], list)
Brant Knudson5ee44a42014-03-16 10:55:21 -0500103 self.assertEqual(project1['id'],
Brant Knudsonc5553292014-03-15 11:06:05 -0500104 token_auth['token']['project']['id'])
Brant Knudson5ee44a42014-03-16 10:55:21 -0500105 self.assertEqual(project1['name'],
Brant Knudsonc5553292014-03-15 11:06:05 -0500106 token_auth['token']['project']['name'])
gongxiao5092b812017-04-14 08:50:32 +0800107 self.assertEqual(CONF.identity.default_domain_id,
Brant Knudsonc5553292014-03-15 11:06:05 -0500108 token_auth['token']['project']['domain']['id'])
gongxiao5092b812017-04-14 08:50:32 +0800109 self.assertIsNotNone(token_auth['token']['project']['domain']['name'])
Brant Knudsonc5553292014-03-15 11:06:05 -0500110 self.assertEqual(1, len(token_auth['token']['roles']))
111 self.assertEqual(role['id'], token_auth['token']['roles'][0]['id'])
112 self.assertEqual(role['name'], token_auth['token']['roles'][0]['name'])
113
Brant Knudson5ee44a42014-03-16 10:55:21 -0500114 # Revoke the unscoped token.
David Kranze9d2f422014-07-02 13:57:41 -0400115 self.client.delete_token(token1_id)
Brant Knudson5ee44a42014-03-16 10:55:21 -0500116
117 # Now get another scoped token using the unscoped token.
gongxiao5092b812017-04-14 08:50:32 +0800118 token_auth = self.token.auth(
119 token=token_id,
120 project_name=project2_name,
121 project_domain_id=CONF.identity.default_domain_id)
Brant Knudson5ee44a42014-03-16 10:55:21 -0500122
123 self.assertEqual(project2['id'],
124 token_auth['token']['project']['id'])
125 self.assertEqual(project2['name'],
126 token_auth['token']['project']['name'])
ZhangHongtao74e1df52017-03-13 18:32:43 +0800127
128 @decorators.idempotent_id('08ed85ce-2ba8-4864-b442-bcc61f16ae89')
129 def test_get_available_project_scopes(self):
zhufla7635d72020-04-29 14:36:41 +0800130 """Test getting available project scopes"""
jeremy.zhang0343be52017-05-25 21:29:57 +0800131 manager_project_id = self.os_primary.credentials.project_id
Jordan Pittier8160d312017-04-18 11:52:23 +0200132 admin_user_id = self.os_admin.credentials.user_id
ZhangHongtao74e1df52017-03-13 18:32:43 +0800133 admin_role_id = self.get_role_by_name(CONF.identity.admin_role)['id']
134
135 # Grant the user the role on both projects.
136 self.roles_client.create_user_role_on_project(
137 manager_project_id, admin_user_id, admin_role_id)
138 self.addCleanup(
139 self.roles_client.delete_role_from_user_on_project,
140 manager_project_id, admin_user_id, admin_role_id)
141
Jordan Pittier8160d312017-04-18 11:52:23 +0200142 assigned_project_ids = [self.os_admin.credentials.project_id,
ZhangHongtao74e1df52017-03-13 18:32:43 +0800143 manager_project_id]
144
145 # Get available project scopes
zhufl0a1f6c42017-09-08 09:12:05 +0800146 available_projects = self.client.list_auth_projects()['projects']
ZhangHongtao74e1df52017-03-13 18:32:43 +0800147
Felipe Monteiro60ebc5d2017-07-12 04:13:37 +0100148 # Create list to save fetched project IDs
ZhangHongtao74e1df52017-03-13 18:32:43 +0800149 fetched_project_ids = [i['id'] for i in available_projects]
150
151 # verifying the project ids in list
152 missing_project_ids = \
zhufl0a1f6c42017-09-08 09:12:05 +0800153 [p for p in assigned_project_ids if p not in fetched_project_ids]
ZhangHongtao74e1df52017-03-13 18:32:43 +0800154 self.assertEmpty(missing_project_ids,
Felipe Monteiro60ebc5d2017-07-12 04:13:37 +0100155 "Failed to find project_ids %s in fetched list" %
ZhangHongtao74e1df52017-03-13 18:32:43 +0800156 ', '.join(missing_project_ids))
Felipe Monteiro60ebc5d2017-07-12 04:13:37 +0100157
158 @decorators.idempotent_id('ec5ecb05-af64-4c04-ac86-4d9f6f12f185')
159 def test_get_available_domain_scopes(self):
zhufla7635d72020-04-29 14:36:41 +0800160 """Test getting available domain scopes
161
162 To verify that listing domain scopes for a user works if
163 the user has a domain role or belongs to a group that has a domain
164 role. For this test, admin client is used to add roles to alt user,
165 which performs API calls, to avoid 401 Unauthorized errors.
166 """
Felipe Monteiro60ebc5d2017-07-12 04:13:37 +0100167 alt_user_id = self.os_alt.credentials.user_id
168
169 def _create_user_domain_role_for_alt_user():
170 domain_id = self.setup_test_domain()['id']
171 role_id = self.setup_test_role()['id']
172
173 # Create a role association between the user and domain.
174 self.roles_client.create_user_role_on_domain(
175 domain_id, alt_user_id, role_id)
176 self.addCleanup(
177 self.roles_client.delete_role_from_user_on_domain,
178 domain_id, alt_user_id, role_id)
179
180 return domain_id
181
182 def _create_group_domain_role_for_alt_user():
183 domain_id = self.setup_test_domain()['id']
184 role_id = self.setup_test_role()['id']
185
186 # Create a group.
Felipe Monteirod4415072018-07-03 14:09:02 -0400187 group_id = self.setup_test_group(domain_id=domain_id)['id']
Felipe Monteiro60ebc5d2017-07-12 04:13:37 +0100188
189 # Add the alt user to the group.
190 self.groups_client.add_group_user(group_id, alt_user_id)
191 self.addCleanup(self.groups_client.delete_group_user,
192 group_id, alt_user_id)
193
194 # Create a role association between the group and domain.
195 self.roles_client.create_group_role_on_domain(
196 domain_id, group_id, role_id)
197 self.addCleanup(
198 self.roles_client.delete_role_from_group_on_domain,
199 domain_id, group_id, role_id)
200
201 return domain_id
202
203 # Add the alt user to 2 random domains and 2 random groups
204 # with randomized domains and roles.
205 assigned_domain_ids = []
206 for _ in range(2):
207 domain_id = _create_user_domain_role_for_alt_user()
208 assigned_domain_ids.append(domain_id)
209 domain_id = _create_group_domain_role_for_alt_user()
210 assigned_domain_ids.append(domain_id)
211
212 # Get available domain scopes for the alt user.
213 available_domains = self.os_alt.identity_v3_client.list_auth_domains()[
214 'domains']
215 fetched_domain_ids = [i['id'] for i in available_domains]
216
217 # Verify the expected domain IDs are in the list.
218 missing_domain_ids = \
219 [p for p in assigned_domain_ids if p not in fetched_domain_ids]
220 self.assertEmpty(missing_domain_ids,
221 "Failed to find domain_ids %s in fetched list"
222 % ", ".join(missing_domain_ids))