From cae9d693762031dc972183ac2d98bd3a6b99cf1e Mon Sep 17 00:00:00 2001 From: Joseph Schorr Date: Thu, 30 Mar 2017 16:12:27 -0400 Subject: [PATCH] Better error messages for Docker errors --- endpoints/v2/errors.py | 16 ++++++++++++---- endpoints/v2/v2auth.py | 23 +++++++++++++---------- 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/endpoints/v2/errors.py b/endpoints/v2/errors.py index 3d9bb9c68..127424ca1 100644 --- a/endpoints/v2/errors.py +++ b/endpoints/v2/errors.py @@ -80,9 +80,9 @@ class ManifestUnverified(V2RegistryException): class NameInvalid(V2RegistryException): - def __init__(self, detail=None): + def __init__(self, detail=None, message=None): super(NameInvalid, self).__init__('NAME_INVALID', - 'invalid repository name', + message or 'invalid repository name', detail) @@ -141,9 +141,9 @@ class Unauthorized(V2RegistryException): class Unsupported(V2RegistryException): - def __init__(self, detail=None): + def __init__(self, detail=None, message=None): super(Unsupported, self).__init__('UNSUPPORTED', - 'The operation is unsupported.', + message or 'The operation is unsupported.', detail, 405) @@ -155,3 +155,11 @@ class InvalidLogin(V2RegistryException): {}, 401) + + +class InvalidRequest(V2RegistryException): + def __init__(self, message=None): + super(InvalidRequest, self).__init__('INVALID_REQUEST', + message or 'Invalid request', + {}, + 400) \ No newline at end of file diff --git a/endpoints/v2/v2auth.py b/endpoints/v2/v2auth.py index b09b62652..c304300d4 100644 --- a/endpoints/v2/v2auth.py +++ b/endpoints/v2/v2auth.py @@ -11,7 +11,7 @@ from auth.permissions import (ModifyRepositoryPermission, ReadRepositoryPermissi CreateRepositoryPermission, AdministerRepositoryPermission) from endpoints.decorators import anon_protect from endpoints.v2 import v2_bp -from endpoints.v2.errors import InvalidLogin +from endpoints.v2.errors import InvalidLogin, NameInvalid, InvalidRequest, Unsupported, Unauthorized from data.interfaces.v2 import pre_oci_model as model from util.cache import no_cache from util.names import parse_namespace_repository, REPOSITORY_NAME_REGEX @@ -21,8 +21,7 @@ logger = logging.getLogger(__name__) TOKEN_VALIDITY_LIFETIME_S = 60 * 60 # 1 hour -SCOPE_REGEX_TEMPLATE = r'^repository:((?:{}\/)?((?:[\.a-zA-Z0-9_\-]+\/)?[\.a-zA-Z0-9_\-]+)):((?:push|pull|\*)(?:,(?:push|pull|\*))*)$' - +SCOPE_REGEX_TEMPLATE = r'^repository:((?:{}\/)?((?:[\.a-zA-Z0-9_\-]+\/)*[\.a-zA-Z0-9_\-]+)):((?:push|pull|\*)(?:,(?:push|pull|\*))*)$' @lru_cache(maxsize=1) def get_scope_regex(): @@ -73,7 +72,7 @@ def generate_registry_jwt(auth_result): logger.debug('Match: %s', match) logger.debug('len: %s', len(scope_param)) logger.warning('Unable to decode repository and actions: %s', scope_param) - abort(400) + raise InvalidRequest('Unable to decode repository and actions: %s' % scope_param) logger.debug('Match: %s', match.groups()) @@ -87,7 +86,11 @@ def generate_registry_jwt(auth_result): # Ensure that we are never creating an invalid repository. if not REPOSITORY_NAME_REGEX.match(reponame): logger.debug('Found invalid repository name in auth flow: %s', reponame) - abort(400) + if len(namespace_and_repo.split('/')) > 1: + msg = 'Nested repositories are not supported. Found: %s' % namespace_and_repo + raise NameInvalid(message=msg) + + raise NameInvalid(message='Invalid repository name: %s' % namespace_and_repo) final_actions = [] @@ -108,7 +111,7 @@ def generate_registry_jwt(auth_result): if repo: if ModifyRepositoryPermission(namespace, reponame).can(): if repo.kind != 'image': - abort(405, invalid_repo_message) + raise Unsupported(message=invalid_repo_message) final_actions.append('push') else: @@ -125,7 +128,7 @@ def generate_registry_jwt(auth_result): # Grant pull if the user can read the repo or it is public. if ReadRepositoryPermission(namespace, reponame).can() or repo_is_public: if repo is not None and repo.kind != 'image': - abort(405, invalid_repo_message) + raise Unsupported(message=invalid_repo_message) final_actions.append('pull') else: @@ -135,7 +138,7 @@ def generate_registry_jwt(auth_result): # Grant * user is admin if AdministerRepositoryPermission(namespace, reponame).can(): if repo is not None and repo.kind != 'image': - abort(405, invalid_repo_message) + raise Unsupported(message=invalid_repo_message) final_actions.append('*') else: @@ -161,13 +164,13 @@ def generate_registry_jwt(auth_result): 'repository': reponame, 'namespace': namespace, } - + tuf_root = get_tuf_root(namespace, reponame) elif user is None and token is None: # In this case, we are doing an auth flow, and it's not an anonymous pull logger.debug('No user and no token sent for empty scope list') - abort(401) + raise Unauthorized() # Send the user event. if user is not None: