diff --git a/tripleo_common/image/image_uploader.py b/tripleo_common/image/image_uploader.py index 8d73a5a32..28b419780 100644 --- a/tripleo_common/image/image_uploader.py +++ b/tripleo_common/image/image_uploader.py @@ -667,31 +667,48 @@ class BaseImageUploader(object): raise ImageUploaderException( 'Unknown authentication method for headers: %s' % r.headers) + auth = None www_auth = r.headers['www-authenticate'] - if not www_auth.startswith('Bearer '): - raise ImageUploaderException( - 'Unknown www-authenticate value: %s' % www_auth) token_param = {} - realm = re.search('realm="(.*?)"', www_auth).group(1) - if 'service=' in www_auth: - token_param['service'] = re.search( - 'service="(.*?)"', www_auth).group(1) - token_param['scope'] = 'repository:%s:pull' % image[1:] + if www_auth.startswith('Bearer '): + LOG.debug('Using bearer token auth') + realm = re.search('realm="(.*?)"', www_auth).group(1) + if 'service=' in www_auth: + token_param['service'] = re.search( + 'service="(.*?)"', www_auth).group(1) + token_param['scope'] = 'repository:%s:pull' % image[1:] - auth = None - if username: + if username: + auth = requests_auth.HTTPBasicAuth(username, password) + LOG.debug('Token parameters: params {}'.format(token_param)) + rauth = session.get(realm, params=token_param, auth=auth, + timeout=30) + rauth.raise_for_status() + auth_header = 'Bearer %s' % rauth.json()['token'] + elif www_auth.startswith('Basic '): + LOG.debug('Using basic auth') + if not username or not password: + raise Exception('Authentication credentials required for ' + 'basic auth: %s' % url) auth = requests_auth.HTTPBasicAuth(username, password) - LOG.debug('Token parameters: params {}'.format(token_param)) - rauth = session.get(realm, params=token_param, auth=auth, timeout=30) - rauth.raise_for_status() - session.headers['Authorization'] = 'Bearer %s' % rauth.json()['token'] + rauth = session.get(url, params=token_param, auth=auth, timeout=30) + rauth.raise_for_status() + auth_header = ( + 'Basic %s' % base64.b64encode( + six.b(username + ':' + password)).decode('ascii') + ) + else: + raise ImageUploaderException( + 'Unknown www-authenticate value: %s' % www_auth) hash_request_id = hashlib.sha1(str(rauth.url).encode()) LOG.debug( 'Session authenticated: id {}'.format( hash_request_id.hexdigest() ) ) + session.headers['Authorization'] = auth_header + setattr(session, 'reauthenticate', self.authenticate) setattr( session, diff --git a/tripleo_common/tests/image/test_image_uploader.py b/tripleo_common/tests/image/test_image_uploader.py index a38b21c00..8e89c8e2f 100644 --- a/tripleo_common/tests/image/test_image_uploader.py +++ b/tripleo_common/tests/image/test_image_uploader.py @@ -800,6 +800,31 @@ class TestBaseImageUploader(base.TestCase): auth(url1).headers['Authorization'] ) + def test_authenticate_basic_auth(self): + req = self.requests + auth = self.uploader.authenticate + url1 = urlparse('docker://myrepo.com/t/nova-api:latest') + + # successful auth requests + headers = { + 'www-authenticate': 'Basic realm="Some Realm"' + } + + def req_match(request): + resp = requests.Response() + resp.headers = headers + resp.status_code = 401 + # if we got sent an user/password, return 200 + if 'Authorization' in request.headers: + resp.status_code = 200 + return resp + + req.add_matcher(req_match) + self.assertEqual( + 'Basic Zm9vOmJhcg==', + auth(url1, username='foo', password='bar').headers['Authorization'] + ) + def test_authenticate_with_no_service(self): req = self.requests auth = self.uploader.authenticate