From bb1a2d45685a3b2230f21f7f6ff0e998e666723e Mon Sep 17 00:00:00 2001 From: Tim Burke Date: Fri, 27 Jul 2018 20:03:36 +0000 Subject: [PATCH] Display crypto data/metadata details in swift-object-info Change-Id: If577c69670a10decdbbf5331b1a38d9392d12711 --- swift/cli/info.py | 14 +++++ .../common/middleware/crypto/crypto_utils.py | 10 +-- test/unit/cli/test_info.py | 63 +++++++++++++++++++ 3 files changed, 83 insertions(+), 4 deletions(-) diff --git a/swift/cli/info.py b/swift/cli/info.py index 1969435285..3f49763f26 100644 --- a/swift/cli/info.py +++ b/swift/cli/info.py @@ -12,6 +12,7 @@ from __future__ import print_function import itertools +import json import os import sqlite3 from hashlib import md5 @@ -29,6 +30,7 @@ from swift.container.backend import ContainerBroker, DATADIR as CBDATADIR from swift.obj.diskfile import get_data_dir, read_metadata, DATADIR_BASE, \ extract_policy from swift.common.storage_policy import POLICIES +from swift.common.middleware.crypto.crypto_utils import load_crypto_meta class InfoSystemExit(Exception): @@ -400,6 +402,18 @@ def print_obj_metadata(metadata, drop_prefixes=False): print_metadata('Transient System Metadata:', transient_sys_metadata) print_metadata('User Metadata:', user_metadata) print_metadata('Other Metadata:', other_metadata) + for label, meta in [ + ('Data crypto details', + sys_metadata.get('X-Object-Sysmeta-Crypto-Body-Meta')), + ('Metadata crypto details', + transient_sys_metadata.get('X-Object-Transient-Sysmeta-Crypto-Meta')), + ]: + if meta is None: + continue + print('%s: %s' % ( + label, + json.dumps(load_crypto_meta(meta, b64decode=False), indent=2, + sort_keys=True, separators=(',', ': ')))) def print_info(db_type, db_file, swift_dir='/etc/swift', stale_reads_ok=False, diff --git a/swift/common/middleware/crypto/crypto_utils.py b/swift/common/middleware/crypto/crypto_utils.py index 6592ea7b8f..874775ac7d 100644 --- a/swift/common/middleware/crypto/crypto_utils.py +++ b/swift/common/middleware/crypto/crypto_utils.py @@ -231,7 +231,7 @@ def dump_crypto_meta(crypto_meta): json.dumps(b64_encode_meta(crypto_meta), sort_keys=True)) -def load_crypto_meta(value): +def load_crypto_meta(value, b64decode=True): """ Build the crypto_meta from the json object. @@ -243,15 +243,17 @@ def load_crypto_meta(value): as native unicode strings on py3). :param value: a string serialization of a crypto meta dict + :param b64decode: decode the 'key' and 'iv' values to bytes, default True :returns: a dict containing crypto meta items :raises EncryptionException: if an error occurs while parsing the crypto meta """ def b64_decode_meta(crypto_meta): return { - str(name): (base64.b64decode(val) if name in ('iv', 'key') - else b64_decode_meta(val) if isinstance(val, dict) - else val.encode('utf8') if six.PY2 else val) + str(name): ( + base64.b64decode(val) if name in ('iv', 'key') and b64decode + else b64_decode_meta(val) if isinstance(val, dict) + else val.encode('utf8') if six.PY2 else val) for name, val in crypto_meta.items()} try: diff --git a/test/unit/cli/test_info.py b/test/unit/cli/test_info.py index 1d5c56e9f4..166a8a6d62 100644 --- a/test/unit/cli/test_info.py +++ b/test/unit/cli/test_info.py @@ -1404,6 +1404,69 @@ Other Metadata: self.assertEqual(out.getvalue().strip(), exp_out) + def test_print_obj_crypto_metadata(self): + cryto_body_meta = '%7B%22body_key%22%3A+%7B%22iv%22%3A+%22HmpwLDjlo' \ + '6JxFvOOCVyT6Q%3D%3D%22%2C+%22key%22%3A+%22dEox1dyZJPCs4mtmiQDg' \ + 'u%2Fv1RTointi%2FUhm2y%2BgB3F8%3D%22%7D%2C+%22cipher%22%3A+%22A' \ + 'ES_CTR_256%22%2C+%22iv%22%3A+%22l3W0NZekjt4PFkAJXubVYQ%3D%3D%2' \ + '2%2C+%22key_id%22%3A+%7B%22path%22%3A+%22%2FAUTH_test%2Ftest%2' \ + 'Ftest%22%2C+%22secret_id%22%3A+%222018%22%2C+%22v%22%3A+%221%2' \ + '2%7D%7D' + + crypto_meta_meta = '%7B%22cipher%22%3A+%22AES_CTR_256%22%2C+%22key_' \ + 'id%22%3A+%7B%22path%22%3A+%22%2FAUTH_test%2Ftest%2Ftest%22%2C+' \ + '%22secret_id%22%3A+%222018%22%2C+%22v%22%3A+%221%22%7D%7D' + + stub_metadata = { + 'name': '/AUTH_test/test/test', + 'Content-Type': 'application/sekret', + 'X-Timestamp': '1549899598.237075', + 'X-Object-Sysmeta-Crypto-Body-Meta': cryto_body_meta, + 'X-Object-Transient-Sysmeta-Crypto-Meta': crypto_meta_meta, + } + out = StringIO() + with mock.patch('sys.stdout', out): + print_obj_metadata(stub_metadata) + exp_out = '''Path: /AUTH_test/test/test + Account: AUTH_test + Container: test + Object: test + Object hash: dc3a7d53522b9392b0d19571a752fdfb +Content-Type: application/sekret +Timestamp: 2019-02-11T15:39:58.237080 (1549899598.23708) +System Metadata: + X-Object-Sysmeta-Crypto-Body-Meta: %s +Transient System Metadata: + X-Object-Transient-Sysmeta-Crypto-Meta: %s +User Metadata: + No metadata found +Other Metadata: + No metadata found +Data crypto details: { + "body_key": { + "iv": "HmpwLDjlo6JxFvOOCVyT6Q==", + "key": "dEox1dyZJPCs4mtmiQDgu/v1RTointi/Uhm2y+gB3F8=" + }, + "cipher": "AES_CTR_256", + "iv": "l3W0NZekjt4PFkAJXubVYQ==", + "key_id": { + "path": "/AUTH_test/test/test", + "secret_id": "2018", + "v": "1" + } +} +Metadata crypto details: { + "cipher": "AES_CTR_256", + "key_id": { + "path": "/AUTH_test/test/test", + "secret_id": "2018", + "v": "1" + } +}''' % (cryto_body_meta, crypto_meta_meta) + + self.maxDiff = None + self.assertMultiLineEqual(out.getvalue().strip(), exp_out) + class TestPrintObjWeirdPath(TestPrintObjFullMeta): def setUp(self):