Skip to content
This repository has been archived by the owner on Feb 14, 2025. It is now read-only.

Commit

Permalink
Use marshmallow for serializing responses (#238)
Browse files Browse the repository at this point in the history
* Add dependencies and auto schema

* Add schemas and update routes to use them

* Lock marshmallow to handle webargs requirement

* Use expanded response in services endpoints

* Fixes for changes to get_credential functions

* Set defaults in DTO

* Remove import used for debugging

* Fixes for blind_credential responses
  • Loading branch information
Ryan Lane authored Jan 3, 2020
1 parent 9380e87 commit 7f18aed
Show file tree
Hide file tree
Showing 13 changed files with 737 additions and 277 deletions.
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,7 @@ test: test_unit
test_unit:
mkdir -p build
nosetests --with-coverage --with-path=confidant tests/unit

.PHONY: compile_deps # freeze requirements.in to requirements3.txt
compile_deps:
./pip-compile.sh
163 changes: 52 additions & 111 deletions confidant/routes/credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,14 @@
from confidant import authnz, clients, settings
from confidant.app import app
from confidant.models.credential import Credential
from confidant.models.service import Service
from confidant.schema.credentials import (
CredentialResponse,
CredentialsResponse,
credential_response_schema,
credentials_response_schema,
RevisionsResponse,
revisions_response_schema,
)
from confidant.services import (
credentialmanager,
graphite,
Expand All @@ -20,10 +27,7 @@
)
from confidant.services.ciphermanager import CipherManager
from confidant.utils import maintenance, misc
from confidant.utils.dynamodb import (
decode_last_evaluated_key,
encode_last_evaluated_key,
)
from confidant.utils.dynamodb import decode_last_evaluated_key


acl_module_check = misc.load_module(settings.ACL_MODULE)
Expand All @@ -40,20 +44,11 @@ def get_credential_list():
error_msg = {'error': msg}
return jsonify(error_msg), 403

credentials = []
for cred in Credential.data_type_date_index.query('credential'):
credentials.append({
'id': cred.id,
'name': cred.name,
'revision': cred.revision,
'enabled': cred.enabled,
'modified_date': cred.modified_date,
'modified_by': cred.modified_by,
'documentation': cred.documentation
})

credentials = sorted(credentials, key=lambda k: k['name'].lower())
return jsonify({'credentials': credentials})
credentials_response = CredentialsResponse.from_credentials([
credential
for credential in Credential.data_type_date_index.query('credential')
])
return credentials_response_schema.dumps(credentials_response)


@app.route('/v1/credentials/<id>', methods=['GET'])
Expand All @@ -70,41 +65,33 @@ def get_credential(id):
return jsonify(error_msg), 403

try:
cred = Credential.get(id)
credential = Credential.get(id)
except DoesNotExist:
logging.warning(
'Item with id {0} does not exist.'.format(id)
)
return jsonify({}), 404
if (cred.data_type != 'credential' and
cred.data_type != 'archive-credential'):
if (credential.data_type != 'credential' and
credential.data_type != 'archive-credential'):
return jsonify({}), 404
services = []
for service in Service.data_type_date_index.query('service'):
services.append(service.id)

credential = {
'id': id,
'name': cred.name,
'credential_keys': cred.credential_keys,
'metadata': cred.metadata,
'services': services,
'revision': cred.revision,
'enabled': cred.enabled,
'modified_date': cred.modified_date,
'modified_by': cred.modified_by,
'documentation': cred.documentation
}
include_credential_pairs = False
if acl_module_check(resource_type='credential',
action='get',
resource_id=id):
credential['credential_pairs'] = cred.decrypted_credential_pairs
include_credential_pairs = True
log_line = "{0} get credential {1}".format(
authnz.get_logged_in_user(),
id
)
logging.info(log_line)
return jsonify(credential)
return credential_response_schema.dumps(
CredentialResponse.from_credential(
credential,
include_credential_keys=True,
include_credential_pairs=include_credential_pairs,
)
)


@app.route(
Expand Down Expand Up @@ -156,29 +143,14 @@ def get_archive_credential_revisions(id):
if (cred.data_type != 'credential' and
cred.data_type != 'archive-credential'):
return jsonify({}), 404
revisions = []
_range = range(1, cred.revision + 1)
ids = []
for i in _range:
ids.append("{0}-{1}".format(id, i))
for revision in Credential.batch_get(ids):
revisions.append({
'id': revision.id,
'name': revision.name,
'metadata': cred.metadata,
'revision': revision.revision,
'enabled': revision.enabled,
'modified_date': revision.modified_date,
'modified_by': revision.modified_by,
'documentation': revision.documentation
})
return jsonify({
'revisions': sorted(
revisions,
key=lambda k: k['revision'],
reverse=True
)
})
revisions_response = RevisionsResponse.from_credentials(
Credential.batch_get(ids)
)
return revisions_response_schema.dumps(revisions_response)


@app.route('/v1/archive/credentials', methods=['GET'])
Expand All @@ -196,29 +168,17 @@ def get_archive_credential_list():
except Exception:
logging.exception('Failed to parse provided page')
return jsonify({'error': 'Failed to parse page'}), 400
credentials = []
results = Credential.data_type_date_index.query(
'archive-credential',
scan_index_forward=False,
limit=limit,
last_evaluated_key=page,
)
for cred in results:
credentials.append({
'id': cred.id,
'name': cred.name,
'metadata': cred.metadata,
'revision': cred.revision,
'enabled': cred.enabled,
'modified_date': cred.modified_date,
'modified_by': cred.modified_by,
'documentation': cred.documentation
})
credential_list = {'credentials': credentials}
credential_list['next_page'] = encode_last_evaluated_key(
results.last_evaluated_key
credentials_response = CredentialsResponse.from_credentials(
[credential for credential in results],
next_page=results.last_evaluated_key,
)
return jsonify(credential_list)
return credentials_response_schema.dumps(credentials_response)


@app.route('/v1/credentials', methods=['POST'])
Expand Down Expand Up @@ -290,28 +250,21 @@ def create_credential():
documentation=data.get('documentation')
)
cred.save()
return jsonify({
'id': cred.id,
'name': cred.name,
'credential_pairs': json.loads(cipher.decrypt(cred.credential_pairs)),
'credential_keys': cred.credential_keys,
'metadata': cred.metadata,
'revision': cred.revision,
'enabled': cred.enabled,
'modified_date': cred.modified_date,
'modified_by': cred.modified_by,
'documentation': cred.documentation
})
return credential_response_schema.dumps(
CredentialResponse.from_credential(
cred,
include_credential_keys=True,
include_credential_pairs=True,
)
)


@app.route('/v1/credentials/<id>/services', methods=['GET'])
@authnz.require_auth
def get_credential_dependencies(id):
services = servicemanager.get_services_for_credential(id)
_services = [{'id': x.id, 'enabled': x.enabled} for x in services]
return jsonify({
'services': _services
})
return jsonify({'services': _services})


@app.route('/v1/credentials/<id>', methods=['PUT'])
Expand Down Expand Up @@ -430,18 +383,13 @@ def update_credential(id):
msg = msg.format(cred.name, cred.id, cred.revision)
graphite.send_event(service_names, msg)
webhook.send_event('credential_update', service_names, [cred.id])
return jsonify({
'id': cred.id,
'name': cred.name,
'credential_pairs': json.loads(cipher.decrypt(cred.credential_pairs)),
'credential_keys': cred.credential_keys,
'metadata': cred.metadata,
'revision': cred.revision,
'enabled': cred.enabled,
'modified_date': cred.modified_date,
'modified_by': cred.modified_by,
'documentation': cred.documentation
})
return credential_response_schema.dumps(
CredentialResponse.from_credential(
cred,
include_credential_keys=True,
include_credential_pairs=True,
)
)


@app.route('/v1/credentials/<id>/<to_revision>', methods=['PUT'])
Expand Down Expand Up @@ -548,16 +496,9 @@ def revert_credential_to_revision(id, to_revision):
msg = msg.format(cred.name, cred.id, cred.revision)
graphite.send_event(service_names, msg)
webhook.send_event('credential_update', service_names, [cred.id])
return jsonify({
'id': cred.id,
'name': cred.name,
'metadata': cred.metadata,
'revision': cred.revision,
'enabled': cred.enabled,
'modified_date': cred.modified_date,
'modified_by': cred.modified_by,
'documentation': cred.documentation
})
return credential_response_schema.dumps(
CredentialResponse.from_credential(cred)
)


@app.route('/v1/value_generator', methods=['GET'])
Expand Down
Loading

0 comments on commit 7f18aed

Please sign in to comment.