Skip to content
This repository was archived by the owner on Jun 4, 2021. It is now read-only.
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 34 additions & 22 deletions client/docker_creds_.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,13 @@ def password(self):

_MAGIC_NOT_FOUND_MESSAGE = 'credentials not found in native keychain'

_DOMAIN_FORMATS = [
# Allow naked domains
'%s',
# Allow scheme-prefixed.
'https://%s',
'http://%s',
]

class Helper(Basic):
"""This provider wraps a particularly named credential helper."""
Expand All @@ -151,29 +158,39 @@ def Get(self):

bin_name = 'docker-credential-{name}'.format(name=self._name)
logging.info('Invoking %r to obtain Docker credentials.', bin_name)
try:
p = subprocess.Popen(
[bin_name, 'get'],
stdout=subprocess.PIPE,
stdin=subprocess.PIPE,
stderr=subprocess.STDOUT)
except OSError as e:
if e.errno == errno.ENOENT:
raise Exception('executable not found: ' + bin_name)
raise

def get_credential(registry):
try:
p = subprocess.Popen(
[bin_name, 'get'],
stdout=subprocess.PIPE,
stdin=subprocess.PIPE,
stderr=subprocess.STDOUT)
except OSError as e:
if e.errno == errno.ENOENT:
raise Exception('executable not found: ' + bin_name)
raise
stdout = p.communicate(input=registry)[0]
if stdout.strip() == _MAGIC_NOT_FOUND_MESSAGE:
return _MAGIC_NOT_FOUND_MESSAGE
if p.returncode != 0:
raise Exception('Error fetching credential for %s, exit status: %d\n%s' %
(self._name, p.returncode, stdout))
return stdout

# Some keychains expect a scheme:
# https://github.com/bazelbuild/rules_docker/issues/111
stdout = p.communicate(input='https://' + self._registry)[0]
if stdout.strip() == _MAGIC_NOT_FOUND_MESSAGE:
stdout = _MAGIC_NOT_FOUND_MESSAGE
for form in _DOMAIN_FORMATS:
stdout = get_credential(form % self._registry)
if stdout != _MAGIC_NOT_FOUND_MESSAGE:
break

if stdout == _MAGIC_NOT_FOUND_MESSAGE:
# Use empty auth when no auth is found.
logging.info('Credentials not found, falling back to anonymous auth.')
return Anonymous().Get()

if p.returncode != 0:
raise Exception('Error fetching credential for %s, exit status: %d\n%s' %
(self._name, p.returncode, stdout))

blob = json.loads(stdout)
logging.info('Successfully obtained Docker credentials.')
return Basic(blob['Username'], blob['Secret']).Get()
Expand All @@ -196,12 +213,7 @@ def Resolve(self, name):
# pytype: enable=bad-return-type


_FORMATS = [
# Allow naked domains
'%s',
# Allow scheme-prefixed.
'https://%s',
'http://%s',
_FORMATS = _DOMAIN_FORMATS + [
# Allow scheme-prefixes with version in url path.
'https://%s/v1/',
'http://%s/v1/',
Expand Down