Merge "Return correct response on HTTP basic failure"

This commit is contained in:
Zuul 2020-07-24 15:06:18 +00:00 committed by Gerrit Code Review
commit 798c1357ca
4 changed files with 26 additions and 10 deletions

View File

@ -18,6 +18,7 @@ import binascii
import bcrypt import bcrypt
from oslo_log import log from oslo_log import log
import webob
from ironic_lib.common.i18n import _ from ironic_lib.common.i18n import _
from ironic_lib import exception from ironic_lib import exception
@ -34,6 +35,16 @@ class BasicAuthMiddleware(object):
self.auth_file = auth_file self.auth_file = auth_file
validate_auth_file(auth_file) validate_auth_file(auth_file)
def format_exception(self, e):
result = {'error': {'message': str(e), 'code': e.code}}
headers = list(e.headers.items()) + [
('Content-Type', 'application/json')
]
return webob.Response(content_type='application/json',
status_code=e.code,
json_body=result,
headerlist=headers)
def __call__(self, env, start_response): def __call__(self, env, start_response):
try: try:
@ -44,9 +55,8 @@ class BasicAuthMiddleware(object):
return self.app(env, start_response) return self.app(env, start_response)
except exception.IronicException as e: except exception.IronicException as e:
status = '%s %s' % (int(e.code), str(e)) response = self.format_exception(e)
headers = [(k, v) for k, v in e.headers.items()] return response(env, start_response)
start_response(status, headers)
def authenticate(auth_file, username, password): def authenticate(auth_file, username, password):
@ -182,6 +192,4 @@ def unauthorized(message=None):
""" """
if not message: if not message:
message = _('Incorrect username or password') message = _('Incorrect username or password')
e = exception.Unauthorized(message) raise exception.Unauthorized(message)
e.headers['WWW-Authenticate'] = 'Basic realm="Baremetal API"'
raise e

View File

@ -176,6 +176,7 @@ class BadRequest(IronicException):
class Unauthorized(IronicException): class Unauthorized(IronicException):
code = http_client.UNAUTHORIZED code = http_client.UNAUTHORIZED
headers = {'WWW-Authenticate': 'Basic realm="Baremetal API"'}
class ConfigInvalid(IronicException): class ConfigInvalid(IronicException):

View File

@ -14,6 +14,7 @@
# under the License. # under the License.
import base64 import base64
import json
import os import os
import tempfile import tempfile
from unittest import mock from unittest import mock
@ -55,13 +56,18 @@ class TestAuthBasic(base.IronicLibTestCase):
app = mock.Mock() app = mock.Mock()
start_response = mock.Mock() start_response = mock.Mock()
middleware = auth_basic.BasicAuthMiddleware(app, auth_file) middleware = auth_basic.BasicAuthMiddleware(app, auth_file)
env = {} env = {'REQUEST_METHOD': 'GET'}
middleware(env, start_response) body = middleware(env, start_response)
decoded = json.loads(body[0].decode())
self.assertEqual({'error': {'message': 'Authorization required',
'code': 401}}, decoded)
start_response.assert_called_once_with( start_response.assert_called_once_with(
'401 Authorization required', '401 Unauthorized',
[('WWW-Authenticate', 'Basic realm="Baremetal API"')] [('WWW-Authenticate', 'Basic realm="Baremetal API"'),
('Content-Type', 'application/json'),
('Content-Length', str(len(body[0])))]
) )
app.assert_not_called() app.assert_not_called()

View File

@ -13,3 +13,4 @@ requests>=2.14.2 # Apache-2.0
oslo.log>=3.36.0 # Apache-2.0 oslo.log>=3.36.0 # Apache-2.0
zeroconf>=0.24.0 # LGPL zeroconf>=0.24.0 # LGPL
bcrypt>=3.1.3 # Apache-2.0 bcrypt>=3.1.3 # Apache-2.0
WebOb>=1.7.1 # MIT