From 85968a7495c10a03be58bbfd074a2a7e6d7116d5 Mon Sep 17 00:00:00 2001 From: Steven Hardy Date: Mon, 2 Sep 2013 16:29:39 +0100 Subject: [PATCH] Add trust_id and trustor_user_id Context and DB Add trust_id and trustor_user_id to the user_creds table and related RequestContext object blueprint heat-trusts Change-Id: Ie0fdc5068475db7e84f366d1eb2b9ae56db0b3fc --- heat/common/context.py | 8 +++- heat/db/sqlalchemy/api.py | 11 +++++- .../versions/027_user_creds_trusts.py | 38 +++++++++++++++++++ heat/db/sqlalchemy/models.py | 2 + heat/tests/test_sqlalchemy_api.py | 34 +++++++++++++++++ 5 files changed, 90 insertions(+), 3 deletions(-) create mode 100644 heat/db/sqlalchemy/migrate_repo/versions/027_user_creds_trusts.py diff --git a/heat/common/context.py b/heat/common/context.py index b3711e87c4..0ee8aec0ff 100644 --- a/heat/common/context.py +++ b/heat/common/context.py @@ -38,7 +38,9 @@ class RequestContext(context.RequestContext): aws_creds=None, tenant=None, tenant_id=None, auth_url=None, roles=None, is_admin=False, read_only=False, show_deleted=False, - owner_is_tenant=True, overwrite=True, **kwargs): + owner_is_tenant=True, overwrite=True, + trust_id=None, trustor_user_id=None, + **kwargs): """ :param overwrite: Set to False to ensure that the greenthread local copy of the index is not overwritten. @@ -63,6 +65,8 @@ class RequestContext(context.RequestContext): if overwrite or not hasattr(local.store, 'context'): self.update_store() self._session = None + self.trust_id = trust_id + self.trustor_user_id = trustor_user_id def update_store(self): local.store.context = self @@ -80,6 +84,8 @@ class RequestContext(context.RequestContext): 'aws_creds': self.aws_creds, 'tenant': self.tenant, 'tenant_id': self.tenant_id, + 'trust_id': self.trust_id, + 'trustor_user_id': self.trustor_user_id, 'auth_url': self.auth_url, 'roles': self.roles, 'is_admin': self.is_admin} diff --git a/heat/db/sqlalchemy/api.py b/heat/db/sqlalchemy/api.py index 58b1999534..cc24b4c54d 100644 --- a/heat/db/sqlalchemy/api.py +++ b/heat/db/sqlalchemy/api.py @@ -259,8 +259,14 @@ def stack_delete(context, stack_id): def user_creds_create(context): values = context.to_dict() user_creds_ref = models.UserCreds() - user_creds_ref.update(values) - user_creds_ref.password = crypt.encrypt(values['password']) + if values.get('trust_id'): + user_creds_ref.trust_id = crypt.encrypt(values.get('trust_id')) + user_creds_ref.trustor_user_id = values.get('trustor_user_id') + user_creds_ref.username = None + user_creds_ref.password = None + else: + user_creds_ref.update(values) + user_creds_ref.password = crypt.encrypt(values['password']) user_creds_ref.save(_session(context)) return user_creds_ref @@ -271,6 +277,7 @@ def user_creds_get(user_creds_id): # or it can be committed back to the DB in decrypted form result = dict(db_result) result['password'] = crypt.decrypt(result['password']) + result['trust_id'] = crypt.decrypt(result['trust_id']) return result diff --git a/heat/db/sqlalchemy/migrate_repo/versions/027_user_creds_trusts.py b/heat/db/sqlalchemy/migrate_repo/versions/027_user_creds_trusts.py new file mode 100644 index 0000000000..bd974968e2 --- /dev/null +++ b/heat/db/sqlalchemy/migrate_repo/versions/027_user_creds_trusts.py @@ -0,0 +1,38 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import sqlalchemy + + +def upgrade(migrate_engine): + meta = sqlalchemy.MetaData(bind=migrate_engine) + + user_creds = sqlalchemy.Table('user_creds', meta, autoload=True) + + # keystone IDs are 32 characters long, but the keystone DB schema + # specifies varchar(64) so align with that here, for the trust_id + # we encrypt it, so align with the 255 chars allowed for password + trustor_user_id = sqlalchemy.Column('trustor_user_id', + sqlalchemy.String(length=64)) + trust_id = sqlalchemy.Column('trust_id', sqlalchemy.String(length=255)) + trustor_user_id.create(user_creds) + trust_id.create(user_creds) + + +def downgrade(migrate_engine): + meta = sqlalchemy.MetaData(bind=migrate_engine) + + user_creds = sqlalchemy.Table('user_creds', meta, autoload=True) + user_creds.c.trustor_user_id.drop() + user_creds.c.trust_id.drop() diff --git a/heat/db/sqlalchemy/models.py b/heat/db/sqlalchemy/models.py index 44c44c4d45..535f01d582 100644 --- a/heat/db/sqlalchemy/models.py +++ b/heat/db/sqlalchemy/models.py @@ -210,6 +210,8 @@ class UserCreds(BASE, HeatBase): tenant = sqlalchemy.Column(sqlalchemy.String) auth_url = sqlalchemy.Column(sqlalchemy.String) tenant_id = sqlalchemy.Column(sqlalchemy.String) + trust_id = sqlalchemy.Column(sqlalchemy.String) + trustor_user_id = sqlalchemy.Column(sqlalchemy.String) stack = relationship(Stack, backref=backref('user_creds')) diff --git a/heat/tests/test_sqlalchemy_api.py b/heat/tests/test_sqlalchemy_api.py index bba56d02c2..1efb525d01 100644 --- a/heat/tests/test_sqlalchemy_api.py +++ b/heat/tests/test_sqlalchemy_api.py @@ -261,3 +261,37 @@ class SqlAlchemyTest(HeatTestCase): self.assertEqual(2, len(events)) self.m.VerifyAll() + + def test_user_creds_password(self): + self.ctx.trust_id = None + db_creds = db_api.user_creds_create(self.ctx) + load_creds = db_api.user_creds_get(db_creds.id) + + self.assertEqual(load_creds.get('username'), 'test_username') + self.assertEqual(load_creds.get('password'), 'password') + self.assertEqual(load_creds.get('tenant'), 'test_tenant') + self.assertEqual(load_creds.get('tenant_id'), 'test_tenant_id') + self.assertIsNotNone(load_creds.get('created_at')) + self.assertIsNone(load_creds.get('updated_at')) + self.assertEqual(load_creds.get('auth_url'), + 'http://_testnoexisthost_:5000/v2.0') + self.assertIsNone(load_creds.get('trust_id')) + self.assertIsNone(load_creds.get('trustor_user_id')) + + def test_user_creds_trust(self): + self.ctx.username = None + self.ctx.password = None + self.ctx.trust_id = 'atrust123' + self.ctx.trustor_user_id = 'atrustor123' + db_creds = db_api.user_creds_create(self.ctx) + load_creds = db_api.user_creds_get(db_creds.id) + + self.assertIsNone(load_creds.get('username')) + self.assertIsNone(load_creds.get('password')) + self.assertIsNone(load_creds.get('tenant')) + self.assertIsNone(load_creds.get('tenant_id')) + self.assertIsNotNone(load_creds.get('created_at')) + self.assertIsNone(load_creds.get('updated_at')) + self.assertIsNone(load_creds.get('auth_url')) + self.assertEqual(load_creds.get('trust_id'), 'atrust123') + self.assertEqual(load_creds.get('trustor_user_id'), 'atrustor123')