Merge "Add support for multiple encryption methods"

This commit is contained in:
Jenkins 2013-12-23 11:22:39 +00:00 committed by Gerrit Code Review
commit 37e74a3c06
5 changed files with 67 additions and 15 deletions

View File

@ -35,14 +35,14 @@ logger = logging.getLogger(__name__)
def encrypt(auth_info):
if auth_info is None:
return None
return None, None
iv = urandom(AES.block_size)
cipher = AES.new(cfg.CONF.auth_encryption_key[:32], AES.MODE_CFB, iv)
res = base64.b64encode(iv + cipher.encrypt(auth_info))
return res
return 'heat_decrypt', res
def decrypt(auth_info):
def heat_decrypt(auth_info):
if auth_info is None:
return None
auth = base64.b64decode(auth_info)

View File

@ -142,7 +142,7 @@ def resource_data_get_all(resource):
for res in result:
if res.redact:
ret[res.key] = _decrypt(res.value)
ret[res.key] = _decrypt(res.value, res.decrypt_method)
else:
ret[res.key] = res.value
@ -157,17 +157,22 @@ def resource_data_get(resource, key):
resource.id,
key)
if result.redact:
return _decrypt(result.value)
return _decrypt(result.value, result.decrypt_method)
return result.value
def _encrypt(value):
if value is not None:
return crypt.encrypt(value.encode('utf-8'))
else:
return None, None
def _decrypt(enc_value):
value = crypt.decrypt(enc_value)
def _decrypt(enc_value, method):
if method is None:
return None
decryptor = getattr(crypt, method)
value = decryptor(enc_value)
if value is not None:
return unicode(value, 'utf-8')
@ -188,7 +193,9 @@ def resource_data_get_by_key(context, resource_id, key):
def resource_data_set(resource, key, value, redact=False):
"""Save resource's key/value pair to database."""
if redact:
value = _encrypt(value)
method, value = _encrypt(value)
else:
method = ''
try:
current = resource_data_get_by_key(resource.context, resource.id, key)
except exception.NotFound:
@ -197,6 +204,7 @@ def resource_data_set(resource, key, value, redact=False):
current.resource_id = resource.id
current.redact = redact
current.value = value
current.decrypt_method = method
current.save(session=resource.context.session)
return current
@ -425,7 +433,9 @@ def user_creds_create(context):
values = context.to_dict()
user_creds_ref = models.UserCreds()
if values.get('trust_id'):
user_creds_ref.trust_id = _encrypt(values.get('trust_id'))
method, trust_id = _encrypt(values.get('trust_id'))
user_creds_ref.trust_id = trust_id
user_creds_ref.decrypt_method = method
user_creds_ref.trustor_user_id = values.get('trustor_user_id')
user_creds_ref.username = None
user_creds_ref.password = None
@ -433,7 +443,9 @@ def user_creds_create(context):
user_creds_ref.tenant_id = values.get('tenant_id')
else:
user_creds_ref.update(values)
user_creds_ref.password = _encrypt(values['password'])
method, password = _encrypt(values['password'])
user_creds_ref.password = password
user_creds_ref.decrypt_method = method
user_creds_ref.save(_session(context))
return user_creds_ref
@ -443,8 +455,9 @@ def user_creds_get(user_creds_id):
# Return a dict copy of db results, do not decrypt details into db_result
# or it can be committed back to the DB in decrypted form
result = dict(db_result)
result['password'] = _decrypt(result['password'])
result['trust_id'] = _decrypt(result['trust_id'])
del result['decrypt_method']
result['password'] = _decrypt(result['password'], db_result.decrypt_method)
result['trust_id'] = _decrypt(result['trust_id'], db_result.decrypt_method)
return result

View File

@ -0,0 +1,33 @@
# 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()
meta.bind = migrate_engine
for table in ('user_creds', 'resource_data'):
table = sqlalchemy.Table(table, meta, autoload=True)
method = sqlalchemy.Column('decrypt_method',
sqlalchemy.String(length=64),
default='heat_decrypt')
method.create(table)
def downgrade(migrate_engine):
meta = sqlalchemy.MetaData(bind=migrate_engine)
for table in ('user_creds', 'resource_data'):
table = sqlalchemy.Table(table, meta, autoload=True)
table.c.decrypt_method.drop()

View File

@ -166,6 +166,7 @@ class UserCreds(BASE, HeatBase):
id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True)
username = sqlalchemy.Column(sqlalchemy.String(255))
password = sqlalchemy.Column(sqlalchemy.String(255))
decrypt_method = sqlalchemy.Column(sqlalchemy.String(64))
tenant = sqlalchemy.Column(sqlalchemy.String(1024))
auth_url = sqlalchemy.Column(sqlalchemy.String)
tenant_id = sqlalchemy.Column(sqlalchemy.String(256))
@ -207,6 +208,7 @@ class ResourceData(BASE, HeatBase):
key = sqlalchemy.Column('key', sqlalchemy.String(255))
value = sqlalchemy.Column('value', sqlalchemy.String)
redact = sqlalchemy.Column('redact', sqlalchemy.Boolean)
decrypt_method = sqlalchemy.Column(sqlalchemy.String(64))
resource_id = sqlalchemy.Column('resource_id',
sqlalchemy.String(36),
sqlalchemy.ForeignKey('resource.id'),

View File

@ -637,7 +637,9 @@ class DBAPIUserCredsTest(HeatTestCase):
user_creds = create_user_creds(self.ctx, trust_id='test_trust_id',
trustor_user_id='trustor_id')
self.assertIsNotNone(user_creds.id)
self.assertEqual('test_trust_id', db_api._decrypt(user_creds.trust_id))
self.assertEqual('test_trust_id',
db_api._decrypt(user_creds.trust_id,
user_creds.decrypt_method))
self.assertEqual('trustor_id', user_creds.trustor_user_id)
self.assertIsNone(user_creds.username)
self.assertIsNone(user_creds.password)
@ -648,12 +650,14 @@ class DBAPIUserCredsTest(HeatTestCase):
user_creds = create_user_creds(self.ctx)
self.assertIsNotNone(user_creds.id)
self.assertEqual(self.ctx.password,
db_api._decrypt(user_creds.password))
db_api._decrypt(user_creds.password,
user_creds.decrypt_method))
def test_user_creds_get(self):
user_creds = create_user_creds(self.ctx)
ret_user_creds = db_api.user_creds_get(user_creds.id)
self.assertEqual(db_api._decrypt(user_creds.password),
self.assertEqual(db_api._decrypt(user_creds.password,
user_creds.decrypt_method),
ret_user_creds['password'])