From f1553b591f3f774d7989b23cf574d57a2103be7f Mon Sep 17 00:00:00 2001 From: Anthony Washington Date: Wed, 7 Sep 2016 16:55:46 +0000 Subject: [PATCH] Add Keystone token validation Added Keystone benchmarking scenario to perform token validation. Change-Id: Ie84f99156c7537a2a4630e9b0778009e7121ef86 --- rally-jobs/rally-keystone-api-v2.yaml | 11 ++++++++ .../openstack/scenarios/keystone/basic.py | 20 +++++++++++++- .../openstack/scenarios/keystone/utils.py | 26 +++++++++++++++++++ .../authenticate-user-and-validate-token.json | 17 ++++++++++++ .../authenticate-user-and-validate-token.yaml | 11 ++++++++ .../scenarios/keystone/test_basic.py | 21 ++++++++++++++- .../scenarios/keystone/test_utils.py | 26 +++++++++++++++++++ 7 files changed, 130 insertions(+), 2 deletions(-) create mode 100644 samples/tasks/scenarios/keystone/authenticate-user-and-validate-token.json create mode 100644 samples/tasks/scenarios/keystone/authenticate-user-and-validate-token.yaml diff --git a/rally-jobs/rally-keystone-api-v2.yaml b/rally-jobs/rally-keystone-api-v2.yaml index 8d13231586..7b892b3624 100644 --- a/rally-jobs/rally-keystone-api-v2.yaml +++ b/rally-jobs/rally-keystone-api-v2.yaml @@ -22,6 +22,17 @@ failure_rate: max: 0 + KeystoneBasic.authenticate_user_and_validate_token: + - + args: {} + runner: + type: "constant" + times: 20 + concurrency: 5 + sla: + failure_rate: + max: 0 + KeystoneBasic.create_user_set_enabled_and_delete: - args: diff --git a/rally/plugins/openstack/scenarios/keystone/basic.py b/rally/plugins/openstack/scenarios/keystone/basic.py index 3d3d024b67..1bce4f2a84 100644 --- a/rally/plugins/openstack/scenarios/keystone/basic.py +++ b/rally/plugins/openstack/scenarios/keystone/basic.py @@ -92,6 +92,24 @@ class CreateTenant(kutils.KeystoneScenario): self._tenant_create(**kwargs) +@validation.required_openstack(admin=True) +@validation.required_api_versions(component="keystone", versions=[2.0]) +@scenario.configure(context={"admin_cleanup": ["keystone"]}, + name="KeystoneBasic.authenticate_user_and_validate_token") +class AuthenticateUserAndValidateToken(kutils.KeystoneScenario): + + def run(self): + """Authenticate and validate a keystone token.""" + name = self.context["user"]["credential"].username + password = self.context["user"]["credential"].password + tenant_id = self.context["tenant"]["id"] + tenant_name = self.context["tenant"]["name"] + + token = self._authenticate_token(name, password, tenant_id, + tenant_name, atomic_action=False) + self._token_validate(token.id) + + @validation.number("users_per_tenant", minval=1) @validation.required_openstack(admin=True) @validation.required_api_versions(component="keystone", versions=[2.0]) @@ -313,4 +331,4 @@ class CreateAndDeleteEc2Credential(kutils.KeystoneScenario): """Create and delete keystone ec2-credential.""" creds = self._create_ec2credentials(self.context["user"]["id"], self.context["tenant"]["id"]) - self._delete_ec2credential(self.context["user"]["id"], creds.access) \ No newline at end of file + self._delete_ec2credential(self.context["user"]["id"], creds.access) diff --git a/rally/plugins/openstack/scenarios/keystone/utils.py b/rally/plugins/openstack/scenarios/keystone/utils.py index fca31cd69d..76790ac2c8 100644 --- a/rally/plugins/openstack/scenarios/keystone/utils.py +++ b/rally/plugins/openstack/scenarios/keystone/utils.py @@ -49,6 +49,32 @@ class KeystoneScenario(scenario.OpenStackScenario): """ self.admin_clients("keystone").users.update_enabled(user, enabled) + @atomic.action_timer("keystone.validate_token") + def _token_validate(self, token): + """Validate a token for a user. + + :param token: The token to validate + """ + self.admin_clients("keystone").tokens.validate(token) + + @atomic.optional_action_timer("keystone.token_authenticate") + def _authenticate_token(self, name, password, tenant_id, tenant): + """Authenticate user token. + + :param name: The user username + :param password: User password for authentication + :param tenant_id: Tenant id for authentication + :param tenant: Tenant on which authentication will take place + :param atomic_action: bool, enable user authentication to be + tracked as an atomic action. added and + handled by the optional_action_timer() + decorator + """ + return self.admin_clients("keystone").tokens.authenticate(name, + tenant_id, + tenant, + password) + def _resource_delete(self, resource): """"Delete keystone resource.""" r = "keystone.delete_%s" % resource.__class__.__name__.lower() diff --git a/samples/tasks/scenarios/keystone/authenticate-user-and-validate-token.json b/samples/tasks/scenarios/keystone/authenticate-user-and-validate-token.json new file mode 100644 index 0000000000..564bc897df --- /dev/null +++ b/samples/tasks/scenarios/keystone/authenticate-user-and-validate-token.json @@ -0,0 +1,17 @@ +{ + "KeystoneBasic.authenticate_user_and_validate_token": [ + { + "args": {}, + "runner": { + "type": "constant", + "times": 20, + "concurrency": 5 + }, + "sla": { + "failure_rate": { + "max": 0 + } + } + } + ] +} diff --git a/samples/tasks/scenarios/keystone/authenticate-user-and-validate-token.yaml b/samples/tasks/scenarios/keystone/authenticate-user-and-validate-token.yaml new file mode 100644 index 0000000000..86e86ca996 --- /dev/null +++ b/samples/tasks/scenarios/keystone/authenticate-user-and-validate-token.yaml @@ -0,0 +1,11 @@ +--- + KeystoneBasic.authenticate_user_and_validate_token: + - + args: {} + runner: + type: "constant" + times: 20 + concurrency: 5 + sla: + failure_rate: + max: 0 diff --git a/tests/unit/plugins/openstack/scenarios/keystone/test_basic.py b/tests/unit/plugins/openstack/scenarios/keystone/test_basic.py index b655a129ee..aa0577ca3a 100755 --- a/tests/unit/plugins/openstack/scenarios/keystone/test_basic.py +++ b/tests/unit/plugins/openstack/scenarios/keystone/test_basic.py @@ -29,7 +29,8 @@ class KeystoneBasicTestCase(test.ScenarioTestCase): "id": "fake_user_id", "credential": mock.MagicMock() }, - "tenant": {"id": "fake_tenant_id"} + "tenant": {"id": "fake_tenant_id", + "name": "fake_tenant_name"} }) return context @@ -67,6 +68,24 @@ class KeystoneBasicTestCase(test.ScenarioTestCase): scenario._resource_delete.assert_called_once_with( scenario._user_create.return_value) + def test_user_authenticate_and_validate_token(self): + fake_token = mock.MagicMock() + context = self._get_context() + scenario = basic.AuthenticateUserAndValidateToken(context) + + fake_user = context["user"]["credential"].username + fake_paswd = context["user"]["credential"].password + fake_tenant_id = context["tenant"]["id"] + fake_tenant_name = context["tenant"]["name"] + + scenario._authenticate_token = mock.MagicMock(return_value=fake_token) + scenario._token_validate = mock.MagicMock() + scenario.run() + scenario._authenticate_token.assert_called_once_with( + fake_user, fake_paswd, fake_tenant_id, + fake_tenant_name, atomic_action=False) + scenario._token_validate.assert_called_once_with(fake_token.id) + def test_create_tenant(self): scenario = basic.CreateTenant(self.context) scenario._tenant_create = mock.MagicMock() diff --git a/tests/unit/plugins/openstack/scenarios/keystone/test_utils.py b/tests/unit/plugins/openstack/scenarios/keystone/test_utils.py index 0d207a2016..c57fa6ded2 100644 --- a/tests/unit/plugins/openstack/scenarios/keystone/test_utils.py +++ b/tests/unit/plugins/openstack/scenarios/keystone/test_utils.py @@ -55,6 +55,32 @@ class KeystoneScenarioTestCase(test.ScenarioTestCase): self._test_atomic_action_timer(scenario.atomic_actions(), "keystone.update_user_enabled") + def test_token_validate(self): + token = mock.MagicMock() + scenario = utils.KeystoneScenario(self.context) + + scenario._token_validate(token) + self.admin_clients( + "keystone").tokens.validate.assert_called_once_with(token) + + self._test_atomic_action_timer(scenario.atomic_actions(), + "keystone.validate_token") + + def test_token_authenticate(self): + name = mock.MagicMock() + psswd = "foopsswd" + tenant_id = mock.MagicMock() + tenant_name = mock.MagicMock() + + scenario = utils.KeystoneScenario(self.context) + scenario._authenticate_token(name, psswd, tenant_id, tenant_name) + self.admin_clients( + "keystone").tokens.authenticate.assert_called_once_with( + name, tenant_id, tenant_name, "foopsswd") + + self._test_atomic_action_timer(scenario.atomic_actions(), + "keystone.token_authenticate") + def test_role_create(self): scenario = utils.KeystoneScenario(self.context) scenario.generate_random_name = mock.Mock()