|
13 | 13 | # limitations under the License.
|
14 | 14 |
|
15 | 15 | import base64
|
16 |
| -import fileinput |
17 | 16 | import json
|
18 | 17 | import logging
|
19 | 18 | import os
|
@@ -102,7 +101,7 @@ def decode_auth(auth):
|
102 | 101 |
|
103 | 102 | def encode_header(auth):
|
104 | 103 | auth_json = json.dumps(auth).encode('ascii')
|
105 |
| - return base64.b64encode(auth_json) |
| 104 | + return base64.urlsafe_b64encode(auth_json) |
106 | 105 |
|
107 | 106 |
|
108 | 107 | def parse_auth(entries):
|
@@ -132,78 +131,79 @@ def parse_auth(entries):
|
132 | 131 | return conf
|
133 | 132 |
|
134 | 133 |
|
| 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 | + |
135 | 155 | def load_config(config_path=None):
|
136 | 156 | """
|
137 | 157 | Loads authentication data from a Docker configuration file in the given
|
138 | 158 | 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 |
139 | 162 | """
|
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) |
169 | 163 |
|
170 |
| - log.debug("Trying {0}".format(config_file)) |
| 164 | + config_file = find_config_file(config_path) |
171 | 165 |
|
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") |
174 | 168 | return {}
|
175 | 169 |
|
176 |
| - log.debug("Attempting to parse as JSON") |
177 | 170 | try:
|
178 | 171 | 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['auths']) |
| 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. |
181 | 184 | log.debug(e)
|
182 |
| - pass |
183 | 185 |
|
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 |
| - |
189 | 186 | log.debug("Attempting to parse legacy auth file format")
|
190 | 187 | try:
|
191 | 188 | 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 | + ) |
198 | 197 |
|
199 | 198 | 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 | + } |
205 | 206 | }
|
206 |
| - return conf |
207 | 207 | except Exception as e:
|
208 | 208 | log.debug(e)
|
209 | 209 | pass
|
|
0 commit comments