Merge "Add console auth tokens db api methods"
This commit is contained in:
commit
0871f4953d
@ -2050,3 +2050,39 @@ def instance_tag_delete_all(context, instance_uuid):
|
||||
def instance_tag_exists(context, instance_uuid, tag):
|
||||
"""Check if specified tag exist on the instance."""
|
||||
return IMPL.instance_tag_exists(context, instance_uuid, tag)
|
||||
|
||||
|
||||
####################
|
||||
|
||||
|
||||
def console_auth_token_create(context, values):
|
||||
"""Create a console authorization."""
|
||||
return IMPL.console_auth_token_create(context, values)
|
||||
|
||||
|
||||
def console_auth_token_get_valid(context, token_hash, instance_uuid):
|
||||
"""Get a valid console authorization by token_hash and instance_uuid.
|
||||
|
||||
The console authorizations expire at the time specified by their
|
||||
'expires' column. An expired console auth token will not be returned
|
||||
to the caller - it is treated as if it does not exist.
|
||||
"""
|
||||
return IMPL.console_auth_token_get_valid(context,
|
||||
token_hash,
|
||||
instance_uuid)
|
||||
|
||||
|
||||
def console_auth_token_destroy_all_by_instance(context, instance_uuid):
|
||||
"""Delete all console authorizations belonging to the instance."""
|
||||
return IMPL.console_auth_token_destroy_all_by_instance(context,
|
||||
instance_uuid)
|
||||
|
||||
|
||||
def console_auth_token_destroy_expired_by_host(context, host):
|
||||
"""Delete expired console authorizations belonging to the host.
|
||||
|
||||
The console authorizations expire at the time specified by their
|
||||
'expires' column. This function is used to garbage collect expired
|
||||
tokens associated with the given host.
|
||||
"""
|
||||
return IMPL.console_auth_token_destroy_expired_by_host(context, host)
|
||||
|
@ -6812,3 +6812,40 @@ def instance_tag_exists(context, instance_uuid, tag):
|
||||
q = context.session.query(models.Tag).filter_by(
|
||||
resource_id=instance_uuid, tag=tag)
|
||||
return context.session.query(q.exists()).scalar()
|
||||
|
||||
|
||||
####################
|
||||
|
||||
|
||||
@pick_context_manager_writer
|
||||
def console_auth_token_create(context, values):
|
||||
instance_uuid = values.get('instance_uuid')
|
||||
_check_instance_exists_in_project(context, instance_uuid)
|
||||
token_ref = models.ConsoleAuthToken()
|
||||
token_ref.update(values)
|
||||
context.session.add(token_ref)
|
||||
return token_ref
|
||||
|
||||
|
||||
@pick_context_manager_reader
|
||||
def console_auth_token_get_valid(context, token_hash, instance_uuid):
|
||||
_check_instance_exists_in_project(context, instance_uuid)
|
||||
return context.session.query(models.ConsoleAuthToken).\
|
||||
filter_by(token_hash=token_hash).\
|
||||
filter_by(instance_uuid=instance_uuid).\
|
||||
filter(models.ConsoleAuthToken.expires > timeutils.utcnow_ts()).\
|
||||
first()
|
||||
|
||||
|
||||
@pick_context_manager_writer
|
||||
def console_auth_token_destroy_all_by_instance(context, instance_uuid):
|
||||
context.session.query(models.ConsoleAuthToken).\
|
||||
filter_by(instance_uuid=instance_uuid).delete()
|
||||
|
||||
|
||||
@pick_context_manager_writer
|
||||
def console_auth_token_destroy_expired_by_host(context, host):
|
||||
context.session.query(models.ConsoleAuthToken).\
|
||||
filter_by(host=host).\
|
||||
filter(models.ConsoleAuthToken.expires <= timeutils.utcnow_ts()).\
|
||||
delete()
|
||||
|
@ -65,6 +65,7 @@ from nova import objects
|
||||
from nova.objects import fields
|
||||
from nova import quota
|
||||
from nova import test
|
||||
from nova.tests.unit import fake_console_auth_token
|
||||
from nova.tests.unit import matchers
|
||||
from nova.tests import uuidsentinel
|
||||
from nova import utils
|
||||
@ -10003,3 +10004,135 @@ class TestInstanceTagsFiltering(test.TestCase):
|
||||
'not-tags': [u't5', u't6'],
|
||||
'not-tags-any': [u't7', u't8']})
|
||||
self._assertEqualInstanceUUIDs([uuids[3], uuids[5], uuids[6]], result)
|
||||
|
||||
|
||||
class ConsoleAuthTokenTestCase(test.TestCase):
|
||||
|
||||
def _create_instances(self, uuids):
|
||||
for uuid in uuids:
|
||||
db.instance_create(self.context,
|
||||
{'uuid': uuid,
|
||||
'project_id': self.context.project_id})
|
||||
|
||||
def _create(self, token_hash, instance_uuid, expire_offset, host=None):
|
||||
t = copy.deepcopy(fake_console_auth_token.fake_token_dict)
|
||||
del t['id']
|
||||
t['token_hash'] = token_hash
|
||||
t['instance_uuid'] = instance_uuid
|
||||
t['expires'] = timeutils.utcnow_ts() + expire_offset
|
||||
if host:
|
||||
t['host'] = host
|
||||
db.console_auth_token_create(self.context, t)
|
||||
|
||||
def setUp(self):
|
||||
super(ConsoleAuthTokenTestCase, self).setUp()
|
||||
self.context = context.RequestContext('fake', 'fake')
|
||||
|
||||
def test_console_auth_token_create_no_instance(self):
|
||||
t = copy.deepcopy(fake_console_auth_token.fake_token_dict)
|
||||
del t['id']
|
||||
self.assertRaises(exception.InstanceNotFound,
|
||||
db.console_auth_token_create,
|
||||
self.context, t)
|
||||
|
||||
def test_console_auth_token_get_valid_deleted_instance(self):
|
||||
uuid1 = uuidsentinel.uuid1
|
||||
hash1 = utils.get_sha256_str(uuidsentinel.token1)
|
||||
self._create_instances([uuid1])
|
||||
self._create(hash1, uuid1, 100)
|
||||
|
||||
db_obj1 = db.console_auth_token_get_valid(self.context, hash1, uuid1)
|
||||
self.assertIsNotNone(db_obj1, "a valid token should be in database")
|
||||
|
||||
db.instance_destroy(self.context, uuid1)
|
||||
self.assertRaises(exception.InstanceNotFound,
|
||||
db.console_auth_token_get_valid,
|
||||
self.context, hash1, uuid1)
|
||||
|
||||
def test_console_auth_token_destroy_all_by_instance(self):
|
||||
uuid1 = uuidsentinel.uuid1
|
||||
uuid2 = uuidsentinel.uuid2
|
||||
hash1 = utils.get_sha256_str(uuidsentinel.token1)
|
||||
hash2 = utils.get_sha256_str(uuidsentinel.token2)
|
||||
hash3 = utils.get_sha256_str(uuidsentinel.token3)
|
||||
self._create_instances([uuid1, uuid2])
|
||||
self._create(hash1, uuid1, 100)
|
||||
self._create(hash2, uuid1, 100)
|
||||
self._create(hash3, uuid2, 100)
|
||||
|
||||
db_obj1 = db.console_auth_token_get_valid(self.context, hash1, uuid1)
|
||||
db_obj2 = db.console_auth_token_get_valid(self.context, hash2, uuid1)
|
||||
db_obj3 = db.console_auth_token_get_valid(self.context, hash3, uuid2)
|
||||
self.assertIsNotNone(db_obj1, "a valid token should be in database")
|
||||
self.assertIsNotNone(db_obj2, "a valid token should be in database")
|
||||
self.assertIsNotNone(db_obj3, "a valid token should be in database")
|
||||
|
||||
db.console_auth_token_destroy_all_by_instance(self.context, uuid1)
|
||||
|
||||
db_obj4 = db.console_auth_token_get_valid(self.context, hash1, uuid1)
|
||||
db_obj5 = db.console_auth_token_get_valid(self.context, hash2, uuid1)
|
||||
db_obj6 = db.console_auth_token_get_valid(self.context, hash3, uuid2)
|
||||
self.assertIsNone(db_obj4, "no valid token should be in database")
|
||||
self.assertIsNone(db_obj5, "no valid token should be in database")
|
||||
self.assertIsNotNone(db_obj6, "a valid token should be in database")
|
||||
|
||||
def test_console_auth_token_get_valid_by_expiry(self):
|
||||
uuid1 = uuidsentinel.uuid1
|
||||
uuid2 = uuidsentinel.uuid2
|
||||
hash1 = utils.get_sha256_str(uuidsentinel.token1)
|
||||
hash2 = utils.get_sha256_str(uuidsentinel.token2)
|
||||
self.addCleanup(timeutils.clear_time_override)
|
||||
timeutils.set_time_override(timeutils.utcnow())
|
||||
self._create_instances([uuid1, uuid2])
|
||||
|
||||
self._create(hash1, uuid1, 10)
|
||||
timeutils.advance_time_seconds(100)
|
||||
self._create(hash2, uuid2, 10)
|
||||
|
||||
db_obj1 = db.console_auth_token_get_valid(self.context, hash1, uuid1)
|
||||
db_obj2 = db.console_auth_token_get_valid(self.context, hash2, uuid2)
|
||||
self.assertIsNone(db_obj1, "the token should have expired")
|
||||
self.assertIsNotNone(db_obj2, "a valid token should be found here")
|
||||
|
||||
def test_console_auth_token_get_valid_by_uuid(self):
|
||||
uuid1 = uuidsentinel.uuid1
|
||||
uuid2 = uuidsentinel.uuid2
|
||||
hash1 = utils.get_sha256_str(uuidsentinel.token1)
|
||||
self._create_instances([uuid1, uuid2])
|
||||
|
||||
self._create(hash1, uuid1, 10)
|
||||
|
||||
db_obj1 = db.console_auth_token_get_valid(self.context, hash1, uuid1)
|
||||
db_obj2 = db.console_auth_token_get_valid(self.context, hash1, uuid2)
|
||||
self.assertIsNotNone(db_obj1, "a valid token should be found here")
|
||||
self.assertIsNone(db_obj2, "the token uuid should not match")
|
||||
|
||||
def test_console_auth_token_destroy_expired_by_host(self):
|
||||
uuid1 = uuidsentinel.uuid1
|
||||
uuid2 = uuidsentinel.uuid2
|
||||
uuid3 = uuidsentinel.uuid3
|
||||
hash1 = utils.get_sha256_str(uuidsentinel.token1)
|
||||
hash2 = utils.get_sha256_str(uuidsentinel.token2)
|
||||
hash3 = utils.get_sha256_str(uuidsentinel.token3)
|
||||
self.addCleanup(timeutils.clear_time_override)
|
||||
timeutils.set_time_override(timeutils.utcnow())
|
||||
self._create_instances([uuid1, uuid2, uuid3])
|
||||
|
||||
self._create(hash1, uuid1, 10)
|
||||
self._create(hash2, uuid2, 10, host='other-host')
|
||||
timeutils.advance_time_seconds(100)
|
||||
self._create(hash3, uuid3, 10)
|
||||
|
||||
db.console_auth_token_destroy_expired_by_host(
|
||||
self.context, 'fake-host')
|
||||
|
||||
# the api only supports getting unexpired tokens
|
||||
# but by rolling back time we can see if a token that
|
||||
# should be deleted is still there
|
||||
timeutils.advance_time_seconds(-100)
|
||||
db_obj1 = db.console_auth_token_get_valid(self.context, hash1, uuid1)
|
||||
db_obj2 = db.console_auth_token_get_valid(self.context, hash2, uuid2)
|
||||
db_obj3 = db.console_auth_token_get_valid(self.context, hash3, uuid3)
|
||||
self.assertIsNone(db_obj1, "the token should have been deleted")
|
||||
self.assertIsNotNone(db_obj2, "a valid token should be found here")
|
||||
self.assertIsNotNone(db_obj3, "a valid token should be found here")
|
||||
|
33
nova/tests/unit/fake_console_auth_token.py
Normal file
33
nova/tests/unit/fake_console_auth_token.py
Normal file
@ -0,0 +1,33 @@
|
||||
# Copyright 2016 Intel Corp.
|
||||
# Copyright 2016 Hewlett Packard Enterprise Development Company LP
|
||||
#
|
||||
# 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.
|
||||
|
||||
from nova.tests import uuidsentinel
|
||||
from nova import utils
|
||||
|
||||
fake_token = uuidsentinel.token
|
||||
fake_token_hash = utils.get_sha256_str(fake_token)
|
||||
fake_instance_uuid = uuidsentinel.instance
|
||||
fake_token_dict = {
|
||||
'created_at': None,
|
||||
'updated_at': None,
|
||||
'id': 123,
|
||||
'token_hash': fake_token_hash,
|
||||
'console_type': 'fake-type',
|
||||
'host': 'fake-host',
|
||||
'port': 1000,
|
||||
'internal_access_path': 'fake-path',
|
||||
'instance_uuid': fake_instance_uuid,
|
||||
'expires': 100,
|
||||
}
|
@ -1211,6 +1211,19 @@ def get_hash_str(base_str):
|
||||
return hashlib.md5(base_str).hexdigest()
|
||||
|
||||
|
||||
def get_sha256_str(base_str):
|
||||
"""Returns string that represents sha256 hash of base_str (in hex format).
|
||||
|
||||
sha1 and md5 are known to be breakable, so sha256 is a better option
|
||||
when the hash is being used for security purposes. If hashing passwords
|
||||
or anything else that needs to be retained for a long period a salted
|
||||
hash is better.
|
||||
"""
|
||||
if isinstance(base_str, six.text_type):
|
||||
base_str = base_str.encode('utf-8')
|
||||
return hashlib.sha256(base_str).hexdigest()
|
||||
|
||||
|
||||
def filter_and_format_resource_metadata(resource_type, resource_list,
|
||||
search_filts, metadata_type=None):
|
||||
"""Get all metadata for a list of resources after filtering.
|
||||
|
Loading…
x
Reference in New Issue
Block a user