Skip to content

Commit

Permalink
[sonic-package-manager] fix registry requests failing when no service…
Browse files Browse the repository at this point in the history
… field in Bearer fields (sonic-net#1921)

Signed-off-by: Stepan Blyschak stepanb@nvidia.com

What I did
If Auth service did not reply with "service" field, don't fail and request the token without it.

How I did it
Modified registry.py and added UT.

How to verify it
Tested on DUT.
  • Loading branch information
stepanblyschak authored Nov 15, 2021
1 parent 00b6045 commit ed88013
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 8 deletions.
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@
],
tests_require = [
'pyfakefs',
'responses',
'pytest',
'mockredispy>=2.9.3',
'deepdiff==5.2.3'
Expand Down
17 changes: 9 additions & 8 deletions sonic_package_manager/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,28 +23,29 @@ class AuthenticationService:
""" AuthenticationService provides an authentication tokens. """

@staticmethod
def get_token(realm, service, scope) -> str:
def get_token(bearer: Dict) -> str:
""" Retrieve an authentication token.
Args:
realm: Realm: url to request token.
service: service to request token for.
scope: scope to requests token for.
bearer: Bearer token.
Returns:
token value as a string.
"""

log.debug(f'getting authentication token: realm={realm} service={service} scope={scope}')
log.debug(f'getting authentication token {bearer}')
if 'realm' not in bearer:
raise AuthenticationServiceError(f'Realm is required in bearer')

response = requests.get(f'{realm}?scope={scope}&service={service}')
url = bearer.pop('realm')
response = requests.get(url, params=bearer)
if response.status_code != requests.codes.ok:
raise AuthenticationServiceError('Failed to retrieve token')

content = json.loads(response.content)
token = content['token']
expires_in = content['expires_in']

log.debug(f'authentication token for realm={realm} service={service} scope={scope}: '
log.debug(f'authentication token for bearer={bearer}: '
f'token={token} expires_in={expires_in}')

return token
Expand Down Expand Up @@ -85,7 +86,7 @@ def _execute_get_request(url, headers):
log.debug(f'unauthorized: retrieving authentication details '
f'from response headers {www_authenticate_details}')
bearer = www_authenticate.parse(www_authenticate_details)['bearer']
token = AuthenticationService.get_token(**bearer)
token = AuthenticationService.get_token(bearer)
headers['Authorization'] = f'Bearer {token}'
# Repeat request
response = requests.get(url, headers=headers)
Expand Down
21 changes: 21 additions & 0 deletions tests/sonic_package_manager/test_registry.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#!/usr/bin/env python

import requests
import responses
from sonic_package_manager.registry import RegistryResolver


Expand All @@ -13,3 +15,22 @@ def test_get_registry_for():
assert registry.url == 'https://registry-server:5000'
registry = resolver.get_registry_for('registry-server.com/docker')
assert registry.url == 'https://registry-server.com'


@responses.activate
def test_registry_auth():
resolver = RegistryResolver()
registry = resolver.get_registry_for('registry-server:5000/docker')
responses.add(responses.GET, registry.url + '/v2/docker/tags/list',
headers={
'www-authenticate': 'Bearer realm="https://auth.docker.io/token",scope="repository:library/docker:pull,push"'
},
status=requests.codes.unauthorized)
responses.add(responses.GET,
'https://auth.docker.io/token?scope=repository:library/docker:pull,push',
json={'token': 'a', 'expires_in': '100'},
status=requests.codes.ok)
responses.add(responses.GET, registry.url + '/v2/docker/tags/list',
json={'tags': ['a', 'b']},
status=requests.codes.ok)
assert registry.tags('registry-server:5000/docker') == ['a', 'b']

0 comments on commit ed88013

Please sign in to comment.