def get_credential(id): try: cred = Credential.get(id) except Credential.DoesNotExist: return jsonify({}), 404 if (cred.data_type != 'credential' and cred.data_type != 'archive-credential'): return jsonify({}), 404 services = [] for service in Service.data_type_date_index.query('service'): services.append(service.id) if cred.data_type == 'credential': context = id else: context = id.split('-')[0] data_key = keymanager.decrypt_key( cred.data_key, encryption_context={'id': context} ) cipher_version = cred.cipher_version cipher = CipherManager(data_key, cipher_version) _credential_pairs = cipher.decrypt(cred.credential_pairs) _credential_pairs = json.loads(_credential_pairs) return jsonify({ 'id': id, 'name': cred.name, 'credential_pairs': _credential_pairs, 'services': services, 'revision': cred.revision, 'enabled': cred.enabled, 'modified_date': cred.modified_date, 'modified_by': cred.modified_by })
def create_credential(): data = request.get_json() if not data.get('credential_pairs'): return jsonify({'error': 'credential_pairs is a required field'}), 400 if not isinstance(data.get('metadata', {}), dict): return jsonify({'error': 'metadata must be a dict'}), 400 # Ensure credential pair keys are lowercase credential_pairs = _lowercase_credential_pairs(data['credential_pairs']) _check, ret = _check_credential_pair_values(credential_pairs) if not _check: return jsonify(ret), 400 for cred in Credential.data_type_date_index.query( 'credential', name__eq=data['name']): # Conflict, the name already exists msg = 'Name already exists. See id: {0}'.format(cred.id) return jsonify({'error': msg, 'reference': cred.id}), 409 # Generate an initial stable ID to allow name changes id = str(uuid.uuid4()).replace('-', '') # Try to save to the archive revision = 1 credential_pairs = json.dumps(credential_pairs) data_key = keymanager.create_datakey(encryption_context={'id': id}) cipher = CipherManager(data_key['plaintext'], version=2) credential_pairs = cipher.encrypt(credential_pairs) cred = Credential( id='{0}-{1}'.format(id, revision), data_type='archive-credential', name=data['name'], credential_pairs=credential_pairs, metadata=data.get('metadata'), revision=revision, enabled=data.get('enabled'), data_key=data_key['ciphertext'], cipher_version=2, modified_by=authnz.get_logged_in_user() ).save(id__null=True) # Make this the current revision cred = Credential( id=id, data_type='credential', name=data['name'], credential_pairs=credential_pairs, metadata=data.get('metadata'), revision=revision, enabled=data.get('enabled'), data_key=data_key['ciphertext'], cipher_version=2, modified_by=authnz.get_logged_in_user() ) cred.save() return jsonify({ 'id': cred.id, 'name': cred.name, 'credential_pairs': json.loads(cipher.decrypt(cred.credential_pairs)), 'metadata': cred.metadata, 'revision': cred.revision, 'enabled': cred.enabled, 'modified_date': cred.modified_date, 'modified_by': cred.modified_by })
def test_cipher_version_3(self): key = Fernet.generate_key() cipher = CipherManager(key, 3) with assert_raises(CipherManagerError): cipher.encrypt("testdata") with assert_raises(CipherManagerError): cipher.decrypt("random_text")
def test_cipher_version_2(self): key = Fernet.generate_key() cipher = CipherManager(key, 2) ciphertext = cipher.encrypt("testdata") # Assert we're getting back some form of altered data self.assertNotEquals(ciphertext, "testdata") cipher = CipherManager(key, 2) plaintext = cipher.decrypt(ciphertext) # Assert that decrypting using a new cipher object with the same key # and version give back the same plaintext. self.assertEquals(plaintext, "testdata")
def _get_credentials(credential_ids): credentials = [] with stats.timer('service_batch_get_credentials'): for cred in Credential.batch_get(credential_ids): data_key = keymanager.decrypt_key( cred.data_key, encryption_context={'id': cred.id} ) cipher_version = cred.cipher_version cipher = CipherManager(data_key, cipher_version) _credential_pairs = cipher.decrypt(cred.credential_pairs) _credential_pairs = json.loads(_credential_pairs) credentials.append({ 'id': cred.id, 'name': cred.name, 'enabled': cred.enabled, 'revision': cred.revision, 'credential_pairs': _credential_pairs }) return credentials
def update_credential(id): try: _cred = Credential.get(id) except Credential.DoesNotExist: return jsonify({'error': 'Credential not found.'}), 404 if _cred.data_type != 'credential': msg = 'id provided is not a credential.' return jsonify({'error': msg}), 400 data = request.get_json() update = {} revision = _cred.revision + 1 update['name'] = data.get('name', _cred.name) if 'enabled' in data: if not isinstance(data['enabled'], bool): return jsonify({'error': 'Enabled must be a boolean.'}), 400 update['enabled'] = data['enabled'] else: update['enabled'] = _cred.enabled services = _get_services_for_credential(id) if 'credential_pairs' in data: # Ensure credential pair keys are lowercase credential_pairs = _lowercase_credential_pairs( data['credential_pairs'] ) if not _check_credential_pair_uniqueness(credential_pairs): ret = {'error': 'credential pairs must be key: value'} return jsonify(ret), 400 # Ensure credential pairs don't conflicts with pairs from other # services conflicts = _pair_key_conflicts_for_services( id, credential_pairs, services ) if conflicts: ret = { 'error': 'Conflicting key pairs in mapped service.', 'conflicts': conflicts } return jsonify(ret), 400 update['credential_pairs'] = json.dumps(credential_pairs) else: data_key = keymanager.decrypt_key( _cred.data_key, encryption_context={'id': id} ) cipher_version = _cred.cipher_version cipher = CipherManager(data_key, cipher_version) update['credential_pairs'] = cipher.decrypt(_cred.credential_pairs) data_key = keymanager.create_datakey(encryption_context={'id': id}) cipher = CipherManager(data_key['plaintext'], version=2) credential_pairs = cipher.encrypt(update['credential_pairs']) # Try to save to the archive try: Credential( id='{0}-{1}'.format(id, revision), name=update['name'], data_type='archive-credential', credential_pairs=credential_pairs, enabled=update['enabled'], revision=revision, data_key=data_key['ciphertext'], cipher_version=2, modified_by=authnz.get_logged_in_user_email() ).save(id__null=True) except PutError as e: logging.error(e) return jsonify({'error': 'Failed to add credential to archive.'}), 500 try: cred = Credential( id=id, name=update['name'], data_type='credential', credential_pairs=credential_pairs, enabled=update['enabled'], revision=revision, data_key=data_key['ciphertext'], cipher_version=2, modified_by=authnz.get_logged_in_user_email() ) cred.save() except PutError as e: logging.error(e) return jsonify({'error': 'Failed to update active credential.'}), 500 if services: service_names = [x.id for x in services] msg = 'Updated credential "{0}" ({1}); Revision {2}' msg = msg.format(cred.name, cred.id, cred.revision) graphite.send_event(service_names, msg) return jsonify({ 'id': cred.id, 'name': cred.name, 'credential_pairs': json.loads(cipher.decrypt(cred.credential_pairs)), 'revision': cred.revision, 'enabled': cred.enabled, 'modified_date': cred.modified_date, 'modified_by': cred.modified_by })