From 95e1cf6673e1ecf3ecee18b0c5a6d9c098cd3074 Mon Sep 17 00:00:00 2001 From: Joseph Schorr Date: Thu, 16 Mar 2017 17:06:05 -0400 Subject: [PATCH] Make V2 login errors more descriptive If login fails, we now call validate again to get the reason for the failure, and then surface it to the user of the CLI. This allows for more actionable responses, such as: $ docker login 10.0.2.2:5000 Username (devtable): devtable Password: Error response from daemon: Get http://10.0.2.2:5000/v2/: unauthorized: Client login with unencrypted passwords is disabled. Please generate an encrypted password in the user admin panel for use here. --- endpoints/v2/errors.py | 9 +++++++++ endpoints/v2/v2auth.py | 16 ++++++++-------- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/endpoints/v2/errors.py b/endpoints/v2/errors.py index e511c0500..3d9bb9c68 100644 --- a/endpoints/v2/errors.py +++ b/endpoints/v2/errors.py @@ -146,3 +146,12 @@ class Unsupported(V2RegistryException): 'The operation is unsupported.', detail, 405) + + +class InvalidLogin(V2RegistryException): + def __init__(self, message=None): + super(InvalidLogin, self).__init__('UNAUTHORIZED', + message or 'Specified credentials are invalid', + {}, + 401) + diff --git a/endpoints/v2/v2auth.py b/endpoints/v2/v2auth.py index c9f0dc960..7ae9b37a1 100644 --- a/endpoints/v2/v2auth.py +++ b/endpoints/v2/v2auth.py @@ -6,12 +6,12 @@ from flask import request, jsonify, abort from app import app, userevents, instance_keys from auth.auth_context import get_authenticated_user, get_validated_token, get_validated_oauth_token -from auth.decorators import process_auth +from auth.decorators import process_basic_auth from auth.permissions import (ModifyRepositoryPermission, ReadRepositoryPermission, CreateRepositoryPermission, AdministerRepositoryPermission) -from auth.process import process_auth -from endpoints.v2 import v2_bp from endpoints.decorators import anon_protect +from endpoints.v2 import v2_bp +from endpoints.v2.errors import InvalidLogin 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 @@ -34,10 +34,10 @@ def get_scope_regex(): @v2_bp.route('/auth') -@process_auth +@process_basic_auth @no_cache @anon_protect -def generate_registry_jwt(): +def generate_registry_jwt(auth_result): """ This endpoint will generate a JWT conforming to the Docker Registry v2 Auth Spec: https://docs.docker.com/registry/spec/auth/token/ @@ -57,11 +57,11 @@ def generate_registry_jwt(): oauthtoken = get_validated_oauth_token() logger.debug('Authenticated OAuth token: %s', oauthtoken) - auth_credentials_sent = bool(request.headers.get('authorization', '')) + auth_header = request.headers.get('authorization', '') + auth_credentials_sent = bool(auth_header) if auth_credentials_sent and not user and not token: # The auth credentials sent for the user are invalid. - logger.debug('Invalid auth credentials') - abort(401) + raise InvalidLogin(auth_result.error_message) access = [] user_event_data = {