def test_keys_cached(self): secrets = {None: os.urandom(32), '22': os.urandom(33), 'my_secret_id': os.urandom(50)} conf = {} for secret_id, secret in secrets.items(): opt = ('encryption_root_secret%s' % (('_%s' % secret_id) if secret_id else '')) conf[opt] = base64.b64encode(secret) conf['active_root_secret_id'] = '22' self.app = keymaster.KeyMaster(self.swift, conf) orig_create_key = self.app.create_key calls = [] def mock_create_key(path, secret_id=None): calls.append((path, secret_id)) return orig_create_key(path, secret_id) context = keymaster.KeyMasterContext(self.app, 'a', 'c', 'o') with mock.patch.object(self.app, 'create_key', mock_create_key): keys = context.fetch_crypto_keys() expected_keys = { 'container': hmac.new(secrets['22'], b'/a/c', digestmod=hashlib.sha256).digest(), 'object': hmac.new(secrets['22'], b'/a/c/o', digestmod=hashlib.sha256).digest(), 'id': {'path': '/a/c/o', 'secret_id': '22', 'v': '1'}, 'all_ids': [ {'path': '/a/c/o', 'v': '1'}, {'path': '/a/c/o', 'secret_id': '22', 'v': '1'}, {'path': '/a/c/o', 'secret_id': 'my_secret_id', 'v': '1'}]} self.assertEqual(expected_keys, keys) self.assertEqual([('/a/c', '22'), ('/a/c/o', '22')], calls) with mock.patch.object(self.app, 'create_key', mock_create_key): keys = context.fetch_crypto_keys() # no more calls to create_key self.assertEqual([('/a/c', '22'), ('/a/c/o', '22')], calls) self.assertEqual(expected_keys, keys) with mock.patch.object(self.app, 'create_key', mock_create_key): keys = context.fetch_crypto_keys(key_id={'secret_id': None}) expected_keys = { 'container': hmac.new(secrets[None], b'/a/c', digestmod=hashlib.sha256).digest(), 'object': hmac.new(secrets[None], b'/a/c/o', digestmod=hashlib.sha256).digest(), 'id': {'path': '/a/c/o', 'v': '1'}, 'all_ids': [ {'path': '/a/c/o', 'v': '1'}, {'path': '/a/c/o', 'secret_id': '22', 'v': '1'}, {'path': '/a/c/o', 'secret_id': 'my_secret_id', 'v': '1'}]} self.assertEqual(expected_keys, keys) self.assertEqual([('/a/c', '22'), ('/a/c/o', '22'), ('/a/c', None), ('/a/c/o', None)], calls)
def test_v1_keys_with_weird_paths(self): secrets = {None: os.urandom(32), '22': os.urandom(33)} conf = {} for secret_id, secret in secrets.items(): opt = ('encryption_root_secret%s' % (('_%s' % secret_id) if secret_id else '')) conf[opt] = base64.b64encode(secret) conf['active_root_secret_id'] = '22' self.app = keymaster.KeyMaster(self.swift, conf) orig_create_key = self.app.create_key calls = [] def mock_create_key(path, secret_id=None): calls.append((path, secret_id)) return orig_create_key(path, secret_id) # request path doesn't match stored path -- this could happen if you # misconfigured your proxy to have copy right of encryption context = keymaster.KeyMasterContext(self.app, 'a', 'not-c', 'not-o') for version in ('1', '2'): with mock.patch.object(self.app, 'create_key', mock_create_key): keys = context.fetch_crypto_keys(key_id={ 'v': version, 'path': '/a/c/o' }) expected_keys = { 'container': hmac.new(secrets[None], b'/a/c', digestmod=hashlib.sha256).digest(), 'object': hmac.new(secrets[None], b'/a/c/o', digestmod=hashlib.sha256).digest(), 'id': { 'path': '/a/c/o', 'v': version }, 'all_ids': [{ 'path': '/a/c/o', 'v': version }, { 'path': '/a/c/o', 'secret_id': '22', 'v': version }] } self.assertEqual(expected_keys, keys) self.assertEqual([('/a/c', None), ('/a/c/o', None)], calls) del calls[:] context = keymaster.KeyMasterContext(self.app, 'not-a', 'not-c', '/not-o') with mock.patch.object(self.app, 'create_key', mock_create_key): keys = context.fetch_crypto_keys(key_id={'v': '1', 'path': '/o'}) expected_keys = { 'container': hmac.new(secrets[None], b'/not-a/not-c', digestmod=hashlib.sha256).digest(), 'object': hmac.new(secrets[None], b'/o', digestmod=hashlib.sha256).digest(), 'id': { 'path': '/o', 'v': '1' }, 'all_ids': [{ 'path': '/o', 'v': '1' }, { 'path': '/o', 'secret_id': '22', 'v': '1' }] } self.assertEqual(expected_keys, keys) self.assertEqual([('/not-a/not-c', None), ('/o', None)], calls) del calls[:] context = keymaster.KeyMasterContext(self.app, 'not-a', 'not-c', '/not-o') with mock.patch.object(self.app, 'create_key', mock_create_key): keys = context.fetch_crypto_keys(key_id={ 'v': '2', 'path': '/a/c//o' }) expected_keys = { 'container': hmac.new(secrets[None], b'/a/c', digestmod=hashlib.sha256).digest(), 'object': hmac.new(secrets[None], b'/a/c//o', digestmod=hashlib.sha256).digest(), 'id': { 'path': '/a/c//o', 'v': '2' }, 'all_ids': [{ 'path': '/a/c//o', 'v': '2' }, { 'path': '/a/c//o', 'secret_id': '22', 'v': '2' }] } self.assertEqual(expected_keys, keys) self.assertEqual([('/a/c', None), ('/a/c//o', None)], calls)
def test_v2_keys(self): secrets = {None: os.urandom(32), '22': os.urandom(33)} conf = {} for secret_id, secret in secrets.items(): opt = ('encryption_root_secret%s' % (('_%s' % secret_id) if secret_id else '')) conf[opt] = base64.b64encode(secret) conf['active_root_secret_id'] = '22' self.app = keymaster.KeyMaster(self.swift, conf) orig_create_key = self.app.create_key calls = [] def mock_create_key(path, secret_id=None): calls.append((path, secret_id)) return orig_create_key(path, secret_id) container = u'\N{SNOWMAN}' obj = u'\N{SNOWFLAKE}' if six.PY2: container = container.encode('utf-8') obj = obj.encode('utf-8') good_con_path = '/a/%s' % container good_path = '/a/%s/%s' % (container, obj) if six.PY2: mangled_con_path = ('/a/%s' % container).decode('latin-1').encode('utf-8') mangled_path = ('/a/%s/%s' % (container, obj)).decode('latin-1').encode('utf-8') else: mangled_con_path = ('/a/%s' % container).encode('utf-8').decode('latin-1') mangled_path = ('/a/%s/%s' % (container, obj)).encode('utf-8').decode('latin-1') context = keymaster.KeyMasterContext(self.app, 'a', container, obj) for version in ('1', '2', '3'): with mock.patch.object(self.app, 'create_key', mock_create_key): keys = context.fetch_crypto_keys(key_id={ 'v': version, 'path': good_path }) key_id_path = (good_path if version == '3' or six.PY2 else mangled_path) expected_keys = { 'container': hmac.new(secrets[None], b'/a/\xe2\x98\x83', digestmod=hashlib.sha256).digest(), 'object': hmac.new(secrets[None], b'/a/\xe2\x98\x83/\xe2\x9d\x84', digestmod=hashlib.sha256).digest(), 'id': { 'path': key_id_path, 'v': version }, 'all_ids': [{ 'path': key_id_path, 'v': version }, { 'path': key_id_path, 'secret_id': '22', 'v': version }] } self.assertEqual(expected_keys, keys) self.assertEqual([(good_con_path, None), (good_path, None)], calls) del calls[:] context = keymaster.KeyMasterContext(self.app, 'a', container, obj) for version in ('1', '2'): with mock.patch.object(self.app, 'create_key', mock_create_key): keys = context.fetch_crypto_keys(key_id={ 'v': version, 'path': mangled_path }) key_id_path = (good_path if six.PY2 else mangled_path) expected_keys = { 'container': hmac.new(secrets[None], b'/a/\xe2\x98\x83', digestmod=hashlib.sha256).digest(), 'object': hmac.new(secrets[None], b'/a/\xe2\x98\x83/\xe2\x9d\x84', digestmod=hashlib.sha256).digest(), 'id': { 'path': key_id_path, 'v': version }, 'all_ids': [{ 'path': key_id_path, 'v': version }, { 'path': key_id_path, 'secret_id': '22', 'v': version }] } self.assertEqual(expected_keys, keys) self.assertEqual([(good_con_path, None), (good_path, None)], calls) del calls[:] # If v3, we know to trust the meta -- presumably, data was PUT with # the mojibake path then COPYed to the right path (but with bad # pipeline placement for copy) with mock.patch.object(self.app, 'create_key', mock_create_key): keys = context.fetch_crypto_keys(key_id={ 'v': '3', 'path': mangled_path }) expected_keys = { 'container': hmac.new(secrets[None], b'/a/\xc3\xa2\xc2\x98\xc2\x83', digestmod=hashlib.sha256).digest(), 'object': hmac.new(secrets[None], b'/a/\xc3\xa2\xc2\x98\xc2\x83/\xc3\xa2\xc2\x9d\xc2\x84', digestmod=hashlib.sha256).digest(), 'id': { 'path': mangled_path, 'v': '3' }, 'all_ids': [{ 'path': mangled_path, 'v': '3' }, { 'path': mangled_path, 'secret_id': '22', 'v': '3' }] } self.assertEqual(expected_keys, keys) self.assertEqual([(mangled_con_path, None), (mangled_path, None)], calls) del calls[:]