converging on proper rotation
This commit is contained in:
parent
aaf9e83278
commit
f406942984
4 changed files with 101 additions and 67 deletions
|
@ -1,3 +1,5 @@
|
|||
import json
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
import jwt
|
||||
|
@ -46,20 +48,16 @@ def _validate_jwt(encoded_jwt, jwk, service):
|
|||
abort(400)
|
||||
|
||||
|
||||
def _signer_jwk(encoded_jwt, jwk, kid):
|
||||
def _signer_kid(encoded_jwt):
|
||||
decoded_jwt = jwt.decode(encoded_jwt, verify=False)
|
||||
return decoded_jwt.get('signer_kid', None)
|
||||
|
||||
signer_kid = decoded_jwt.get('signer_kid', '')
|
||||
# If we already have our own JWK and it's the signer, short-circuit.
|
||||
if (signer_kid == kid or signer_kid == '') and jwk is not None:
|
||||
return jwk
|
||||
else:
|
||||
try:
|
||||
service_key = data.model.service_keys.get_service_key(signer_kid)
|
||||
except data.model.ServiceKeyDoesNotExist:
|
||||
abort(404)
|
||||
|
||||
return service_key.jwk
|
||||
def _signer_key(signer_kid):
|
||||
try:
|
||||
return data.model.service_keys.get_service_key(signer_kid)
|
||||
except data.model.ServiceKeyDoesNotExist:
|
||||
abort(403)
|
||||
|
||||
|
||||
@key_server.route('/services/<service>/keys', methods=['GET'])
|
||||
|
@ -88,25 +86,31 @@ def put_service_keys(service, kid):
|
|||
except ValueError:
|
||||
abort(400)
|
||||
|
||||
_validate_jwk(jwk, kid)
|
||||
|
||||
encoded_jwt = request.headers.get(JWT_HEADER_NAME, None)
|
||||
if not encoded_jwt:
|
||||
abort(400)
|
||||
|
||||
signer_jwk = _signer_jwk(encoded_jwt, jwk, kid)
|
||||
_validate_jwt(encoded_jwt, signer_jwk, service)
|
||||
_validate_jwk(jwk, kid)
|
||||
|
||||
|
||||
signer_kid = _signer_kid(encoded_jwt)
|
||||
signer_key = _signer_key(signer_kid)
|
||||
|
||||
if signer_key.service != service:
|
||||
abort(403)
|
||||
|
||||
_validate_jwt(encoded_jwt, signer_key.jwk, service)
|
||||
|
||||
metadata = {
|
||||
'ip': request.remote_addr,
|
||||
'signer_jwk': signer_jwk,
|
||||
'created_by': 'Key Rotation',
|
||||
'rotated_by': json.dumps(signer_key),
|
||||
}
|
||||
|
||||
|
||||
try:
|
||||
data.model.service_keys.update_service_key('', kid, metadata, expiration_date)
|
||||
data.model.service_keys.replace_service_key(kid, jwk, metadata, expiration_date)
|
||||
except data.model.ServiceKeyDoesNotExist:
|
||||
data.model.service_keys.create_service_key('', kid, service, jwk, metadata, expiration_date)
|
||||
abort(404)
|
||||
|
||||
|
||||
@key_server.route('/services/<service>/keys/<kid>', methods=['DELETE'])
|
||||
|
@ -115,12 +119,15 @@ def delete_service_key(service, kid):
|
|||
if not encoded_jwt:
|
||||
abort(400)
|
||||
|
||||
signer_jwk = _signer_jwk(encoded_jwt, None, kid)
|
||||
_validate_jwt(encoded_jwt, signer_jwk, service)
|
||||
signer_kid = _signer_kid(encoded_jwt)
|
||||
signer_key = _signer_key(signer_kid)
|
||||
|
||||
try:
|
||||
data.model.service_keys.delete_service_key(service, kid)
|
||||
except data.model.ServiceKeyDoesNotExist:
|
||||
abort(404)
|
||||
if (kid == signer_kid) or (signer_key.approval is not None):
|
||||
_validate_jwt(encoded_jwt, signer_key.jwk, service)
|
||||
try:
|
||||
data.model.service_keys.delete_service_key(service, kid)
|
||||
except data.model.ServiceKeyDoesNotExist:
|
||||
abort(404)
|
||||
return make_response('', 200)
|
||||
|
||||
return make_response('', 200)
|
||||
abort(403)
|
||||
|
|
Reference in a new issue