Skip to content

Commit 23cf768

Browse files
committed
Use DOCKER_CONFIG environment variable to look up auth config
When provided, default paths are ignored. Signed-off-by: Joffrey F <[email protected]>
1 parent f479720 commit 23cf768

File tree

2 files changed

+84
-57
lines changed

2 files changed

+84
-57
lines changed

docker/auth/auth.py

Lines changed: 54 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
# limitations under the License.
1414

1515
import base64
16-
import fileinput
1716
import json
1817
import logging
1918
import os
@@ -132,78 +131,79 @@ def parse_auth(entries):
132131
return conf
133132

134133

134+
def find_config_file(config_path=None):
135+
environment_path = os.path.join(
136+
os.environ.get('DOCKER_CONFIG'),
137+
os.path.basename(DOCKER_CONFIG_FILENAME)
138+
) if os.environ.get('DOCKER_CONFIG') else None
139+
140+
paths = [
141+
config_path, # 1
142+
environment_path, # 2
143+
os.path.join(os.path.expanduser('~'), DOCKER_CONFIG_FILENAME), # 3
144+
os.path.join(
145+
os.path.expanduser('~'), LEGACY_DOCKER_CONFIG_FILENAME
146+
) # 4
147+
]
148+
149+
for path in paths:
150+
if path and os.path.exists(path):
151+
return path
152+
return None
153+
154+
135155
def load_config(config_path=None):
136156
"""
137157
Loads authentication data from a Docker configuration file in the given
138158
root directory or if config_path is passed use given path.
159+
Lookup priority:
160+
explicit config_path parameter > DOCKER_CONFIG environment variable >
161+
~/.docker/config.json > ~/.dockercfg
139162
"""
140-
conf = {}
141-
data = None
142-
143-
# Prefer ~/.docker/config.json.
144-
config_file = config_path or os.path.join(os.path.expanduser('~'),
145-
DOCKER_CONFIG_FILENAME)
146-
147-
log.debug("Trying {0}".format(config_file))
148-
149-
if os.path.exists(config_file):
150-
try:
151-
with open(config_file) as f:
152-
for section, data in six.iteritems(json.load(f)):
153-
if section != 'auths':
154-
continue
155-
log.debug("Found 'auths' section")
156-
return parse_auth(data)
157-
log.debug("Couldn't find 'auths' section")
158-
except (IOError, KeyError, ValueError) as e:
159-
# Likely missing new Docker config file or it's in an
160-
# unknown format, continue to attempt to read old location
161-
# and format.
162-
log.debug(e)
163-
pass
164-
else:
165-
log.debug("File doesn't exist")
166-
167-
config_file = config_path or os.path.join(os.path.expanduser('~'),
168-
LEGACY_DOCKER_CONFIG_FILENAME)
169163

170-
log.debug("Trying {0}".format(config_file))
164+
config_file = find_config_file(config_path)
171165

172-
if not os.path.exists(config_file):
173-
log.debug("File doesn't exist - returning empty config")
166+
if not config_file:
167+
log.debug("File doesn't exist")
174168
return {}
175169

176-
log.debug("Attempting to parse as JSON")
177170
try:
178171
with open(config_file) as f:
179-
return parse_auth(json.load(f))
180-
except Exception as e:
172+
data = json.load(f)
173+
if data.get('auths'):
174+
log.debug("Found 'auths' section")
175+
return parse_auth(data)
176+
else:
177+
log.debug("Couldn't find 'auths' section")
178+
f.seek(0)
179+
return parse_auth(json.load(f))
180+
except (IOError, KeyError, ValueError) as e:
181+
# Likely missing new Docker config file or it's in an
182+
# unknown format, continue to attempt to read old location
183+
# and format.
181184
log.debug(e)
182-
pass
183185

184-
# If that fails, we assume the configuration file contains a single
185-
# authentication token for the public registry in the following format:
186-
#
187-
# auth = AUTH_TOKEN
188-
189186
log.debug("Attempting to parse legacy auth file format")
190187
try:
191188
data = []
192-
for line in fileinput.input(config_file):
193-
data.append(line.strip().split(' = ')[1])
194-
if len(data) < 2:
195-
# Not enough data
196-
raise errors.InvalidConfigFile(
197-
'Invalid or empty configuration file!')
189+
with open(config_file) as f:
190+
for line in f.readlines():
191+
data.append(line.strip().split(' = ')[1])
192+
if len(data) < 2:
193+
# Not enough data
194+
raise errors.InvalidConfigFile(
195+
'Invalid or empty configuration file!'
196+
)
198197

199198
username, password = decode_auth(data[0])
200-
conf[INDEX_NAME] = {
201-
'username': username,
202-
'password': password,
203-
'email': data[1],
204-
'serveraddress': INDEX_URL,
199+
return {
200+
INDEX_NAME: {
201+
'username': username,
202+
'password': password,
203+
'email': data[1],
204+
'serveraddress': INDEX_URL,
205+
}
205206
}
206-
return conf
207207
except Exception as e:
208208
log.debug(e)
209209
pass

tests/test.py

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2387,7 +2387,7 @@ def test_load_config(self):
23872387
f.write('auth = {0}\n'.format(auth_))
23882388
f.write('email = [email protected]')
23892389
cfg = docker.auth.load_config(dockercfg_path)
2390-
self.assertTrue(docker.auth.INDEX_NAME in cfg)
2390+
assert docker.auth.INDEX_NAME in cfg
23912391
self.assertNotEqual(cfg[docker.auth.INDEX_NAME], None)
23922392
cfg = cfg[docker.auth.INDEX_NAME]
23932393
self.assertEqual(cfg['username'], 'sakuya')
@@ -2412,17 +2412,44 @@ def test_load_config_with_random_name(self):
24122412
}
24132413

24142414
with open(dockercfg_path, 'w') as f:
2415-
f.write(json.dumps(config))
2415+
json.dump(config, f)
24162416

24172417
cfg = docker.auth.load_config(dockercfg_path)
2418-
self.assertTrue(registry in cfg)
2418+
assert registry in cfg
24192419
self.assertNotEqual(cfg[registry], None)
24202420
cfg = cfg[registry]
24212421
self.assertEqual(cfg['username'], 'sakuya')
24222422
self.assertEqual(cfg['password'], 'izayoi')
24232423
self.assertEqual(cfg['email'], '[email protected]')
24242424
self.assertEqual(cfg.get('auth'), None)
24252425

2426+
def test_load_config_custom_config_env(self):
2427+
folder = tempfile.mkdtemp()
2428+
self.addCleanup(shutil.rmtree, folder)
2429+
2430+
dockercfg_path = os.path.join(folder, 'config.json')
2431+
registry = 'https://your.private.registry.io'
2432+
auth_ = base64.b64encode(b'sakuya:izayoi').decode('ascii')
2433+
config = {
2434+
registry: {
2435+
'auth': '{0}'.format(auth_),
2436+
'email': '[email protected]'
2437+
}
2438+
}
2439+
2440+
with open(dockercfg_path, 'w') as f:
2441+
json.dump(config, f)
2442+
2443+
with mock.patch.dict(os.environ, {'DOCKER_CONFIG': folder}):
2444+
cfg = docker.auth.load_config(None)
2445+
assert registry in cfg
2446+
self.assertNotEqual(cfg[registry], None)
2447+
cfg = cfg[registry]
2448+
self.assertEqual(cfg['username'], 'sakuya')
2449+
self.assertEqual(cfg['password'], 'izayoi')
2450+
self.assertEqual(cfg['email'], '[email protected]')
2451+
self.assertEqual(cfg.get('auth'), None)
2452+
24262453
def test_tar_with_excludes(self):
24272454
dirs = [
24282455
'foo',

0 commit comments

Comments
 (0)