We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
registry auth for docker service does not work on Windows
Credentials to authenticated docker registry are not passed to docker service on Windows after login:
```
client.login(username, password, registry=registry, reauth=True)
client.services.create([any_args])
```

On Centos7 it works fine.
Tested with AWS ECR.

Debug logs (red lines - Windows, green lines - Centos7):
```diff
[DEBUG]: Looking for auth entry for 'XXX.amazonaws.com'
[DEBUG]: No entry found
[DEBUG]: http://localhost:None "POST /v1.35/auth HTTP/1.1" 200 48
[DEBUG]: {u'IdentityToken': u'', u'Status': u'Login Succeeded'}
[DEBUG]: Looking for auth config
- [DEBUG]: Using credentials store "wincred"
[DEBUG]: Looking for auth entry for 'XXX.amazonaws.com'
- [DEBUG]: No entry found
- [DEBUG]: No auth config found
+ [DEBUG]: Found 'XXX.amazonaws.com'
+ [DEBUG]: Found auth config
[DEBUG]: http://localhost:None "POST /v1.35/services/create HTTP/1.1" 201 35
[DEBUG]: http://localhost:None "GET /v1.35/services/ixpf3gaiy0cep3qzj9ly302n6 HTTP/1.1" 200 None
```

Windows environment:
```
docker==2.7.0
docker-pycreds==0.2.1
Python 2.7.14
Client:
 Version:       17.12.0-ce
 API version:   1.35
 Go version:    go1.9.2
 Git commit:    c97c6d6
 Built: Wed Dec 27 20:05:22 2017
 OS/Arch:       windows/amd64

Server:
 Engine:
  Version:      17.12.0-ce
  API version:  1.35 (minimum version 1.12)
  Go version:   go1.9.2
  Git commit:   c97c6d6
  Built:        Wed Dec 27 20:12:29 2017
  OS/Arch:      linux/amd64
  Experimental: true
```

Centos7 environment:
```
docker==2.7.0
docker-pycreds==0.2.1
Python 2.7.5
Client:
 Version:       17.12.0-ce
 API version:   1.35
 Go version:    go1.9.2
 Git commit:    c97c6d6
 Built: Wed Dec 27 20:10:14 2017
 OS/Arch:       linux/amd64

Server:
 Engine:
  Version:      17.12.0-ce
  API version:  1.35 (minimum version 1.12)
  Go version:   go1.9.2
  Git commit:   c97c6d6
  Built:        Wed Dec 27 20:12:46 2017
  OS/Arch:      linux/amd64
  Experimental: false
```

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `docker/auth.py`
Content:
```
1 import base64
2 import json
3 import logging
4 
5 import dockerpycreds
6 import six
7 
8 from . import errors
9 from .utils import config
10 
11 INDEX_NAME = 'docker.io'
12 INDEX_URL = 'https://index.{0}/v1/'.format(INDEX_NAME)
13 TOKEN_USERNAME = '<token>'
14 
15 log = logging.getLogger(__name__)
16 
17 
18 def resolve_repository_name(repo_name):
19     if '://' in repo_name:
20         raise errors.InvalidRepository(
21             'Repository name cannot contain a scheme ({0})'.format(repo_name)
22         )
23 
24     index_name, remote_name = split_repo_name(repo_name)
25     if index_name[0] == '-' or index_name[-1] == '-':
26         raise errors.InvalidRepository(
27             'Invalid index name ({0}). Cannot begin or end with a'
28             ' hyphen.'.format(index_name)
29         )
30     return resolve_index_name(index_name), remote_name
31 
32 
33 def resolve_index_name(index_name):
34     index_name = convert_to_hostname(index_name)
35     if index_name == 'index.' + INDEX_NAME:
36         index_name = INDEX_NAME
37     return index_name
38 
39 
40 def get_config_header(client, registry):
41     log.debug('Looking for auth config')
42     if not client._auth_configs:
43         log.debug(
44             "No auth config in memory - loading from filesystem"
45         )
46         client._auth_configs = load_config()
47     authcfg = resolve_authconfig(client._auth_configs, registry)
48     # Do not fail here if no authentication exists for this
49     # specific registry as we can have a readonly pull. Just
50     # put the header if we can.
51     if authcfg:
52         log.debug('Found auth config')
53         # auth_config needs to be a dict in the format used by
54         # auth.py username , password, serveraddress, email
55         return encode_header(authcfg)
56     log.debug('No auth config found')
57     return None
58 
59 
60 def split_repo_name(repo_name):
61     parts = repo_name.split('/', 1)
62     if len(parts) == 1 or (
63         '.' not in parts[0] and ':' not in parts[0] and parts[0] != 'localhost'
64     ):
65         # This is a docker index repo (ex: username/foobar or ubuntu)
66         return INDEX_NAME, repo_name
67     return tuple(parts)
68 
69 
70 def get_credential_store(authconfig, registry):
71     if not registry or registry == INDEX_NAME:
72         registry = 'https://index.docker.io/v1/'
73 
74     return authconfig.get('credHelpers', {}).get(registry) or authconfig.get(
75         'credsStore'
76     )
77 
78 
79 def resolve_authconfig(authconfig, registry=None):
80     """
81     Returns the authentication data from the given auth configuration for a
82     specific registry. As with the Docker client, legacy entries in the config
83     with full URLs are stripped down to hostnames before checking for a match.
84     Returns None if no match was found.
85     """
86 
87     if 'credHelpers' in authconfig or 'credsStore' in authconfig:
88         store_name = get_credential_store(authconfig, registry)
89         if store_name is not None:
90             log.debug(
91                 'Using credentials store "{0}"'.format(store_name)
92             )
93             return _resolve_authconfig_credstore(
94                 authconfig, registry, store_name
95             )
96 
97     # Default to the public index server
98     registry = resolve_index_name(registry) if registry else INDEX_NAME
99     log.debug("Looking for auth entry for {0}".format(repr(registry)))
100 
101     authdict = authconfig.get('auths', {})
102     if registry in authdict:
103         log.debug("Found {0}".format(repr(registry)))
104         return authdict[registry]
105 
106     for key, conf in six.iteritems(authdict):
107         if resolve_index_name(key) == registry:
108             log.debug("Found {0}".format(repr(key)))
109             return conf
110 
111     log.debug("No entry found")
112     return None
113 
114 
115 def _resolve_authconfig_credstore(authconfig, registry, credstore_name):
116     if not registry or registry == INDEX_NAME:
117         # The ecosystem is a little schizophrenic with index.docker.io VS
118         # docker.io - in that case, it seems the full URL is necessary.
119         registry = INDEX_URL
120     log.debug("Looking for auth entry for {0}".format(repr(registry)))
121     store = dockerpycreds.Store(credstore_name)
122     try:
123         data = store.get(registry)
124         res = {
125             'ServerAddress': registry,
126         }
127         if data['Username'] == TOKEN_USERNAME:
128             res['IdentityToken'] = data['Secret']
129         else:
130             res.update({
131                 'Username': data['Username'],
132                 'Password': data['Secret'],
133             })
134         return res
135     except dockerpycreds.CredentialsNotFound as e:
136         log.debug('No entry found')
137         return None
138     except dockerpycreds.StoreError as e:
139         raise errors.DockerException(
140             'Credentials store error: {0}'.format(repr(e))
141         )
142 
143 
144 def convert_to_hostname(url):
145     return url.replace('http://', '').replace('https://', '').split('/', 1)[0]
146 
147 
148 def decode_auth(auth):
149     if isinstance(auth, six.string_types):
150         auth = auth.encode('ascii')
151     s = base64.b64decode(auth)
152     login, pwd = s.split(b':', 1)
153     return login.decode('utf8'), pwd.decode('utf8')
154 
155 
156 def encode_header(auth):
157     auth_json = json.dumps(auth).encode('ascii')
158     return base64.urlsafe_b64encode(auth_json)
159 
160 
161 def parse_auth(entries, raise_on_error=False):
162     """
163     Parses authentication entries
164 
165     Args:
166       entries:        Dict of authentication entries.
167       raise_on_error: If set to true, an invalid format will raise
168                       InvalidConfigFile
169 
170     Returns:
171       Authentication registry.
172     """
173 
174     conf = {}
175     for registry, entry in six.iteritems(entries):
176         if not isinstance(entry, dict):
177             log.debug(
178                 'Config entry for key {0} is not auth config'.format(registry)
179             )
180             # We sometimes fall back to parsing the whole config as if it was
181             # the auth config by itself, for legacy purposes. In that case, we
182             # fail silently and return an empty conf if any of the keys is not
183             # formatted properly.
184             if raise_on_error:
185                 raise errors.InvalidConfigFile(
186                     'Invalid configuration for registry {0}'.format(registry)
187                 )
188             return {}
189         if 'identitytoken' in entry:
190             log.debug('Found an IdentityToken entry for registry {0}'.format(
191                 registry
192             ))
193             conf[registry] = {
194                 'IdentityToken': entry['identitytoken']
195             }
196             continue  # Other values are irrelevant if we have a token, skip.
197 
198         if 'auth' not in entry:
199             # Starting with engine v1.11 (API 1.23), an empty dictionary is
200             # a valid value in the auths config.
201             # https://github.com/docker/compose/issues/3265
202             log.debug(
203                 'Auth data for {0} is absent. Client might be using a '
204                 'credentials store instead.'.format(registry)
205             )
206             conf[registry] = {}
207             continue
208 
209         username, password = decode_auth(entry['auth'])
210         log.debug(
211             'Found entry (registry={0}, username={1})'
212             .format(repr(registry), repr(username))
213         )
214 
215         conf[registry] = {
216             'username': username,
217             'password': password,
218             'email': entry.get('email'),
219             'serveraddress': registry,
220         }
221     return conf
222 
223 
224 def load_config(config_path=None, config_dict=None):
225     """
226     Loads authentication data from a Docker configuration file in the given
227     root directory or if config_path is passed use given path.
228     Lookup priority:
229         explicit config_path parameter > DOCKER_CONFIG environment variable >
230         ~/.docker/config.json > ~/.dockercfg
231     """
232 
233     if not config_dict:
234         config_file = config.find_config_file(config_path)
235 
236         if not config_file:
237             return {}
238         try:
239             with open(config_file) as f:
240                 config_dict = json.load(f)
241         except (IOError, KeyError, ValueError) as e:
242             # Likely missing new Docker config file or it's in an
243             # unknown format, continue to attempt to read old location
244             # and format.
245             log.debug(e)
246             return _load_legacy_config(config_file)
247 
248     res = {}
249     if config_dict.get('auths'):
250         log.debug("Found 'auths' section")
251         res.update({
252             'auths': parse_auth(config_dict.pop('auths'), raise_on_error=True)
253         })
254     if config_dict.get('credsStore'):
255         log.debug("Found 'credsStore' section")
256         res.update({'credsStore': config_dict.pop('credsStore')})
257     if config_dict.get('credHelpers'):
258         log.debug("Found 'credHelpers' section")
259         res.update({'credHelpers': config_dict.pop('credHelpers')})
260     if res:
261         return res
262 
263     log.debug(
264         "Couldn't find auth-related section ; attempting to interpret"
265         "as auth-only file"
266     )
267     return parse_auth(config_dict)
268 
269 
270 def _load_legacy_config(config_file):
271     log.debug("Attempting to parse legacy auth file format")
272     try:
273         data = []
274         with open(config_file) as f:
275             for line in f.readlines():
276                 data.append(line.strip().split(' = ')[1])
277             if len(data) < 2:
278                 # Not enough data
279                 raise errors.InvalidConfigFile(
280                     'Invalid or empty configuration file!'
281                 )
282 
283         username, password = decode_auth(data[0])
284         return {
285             INDEX_NAME: {
286                 'username': username,
287                 'password': password,
288                 'email': data[1],
289                 'serveraddress': INDEX_URL,
290             }
291         }
292     except Exception as e:
293         log.debug(e)
294         pass
295 
296     log.debug("All parsing attempts failed - returning empty config")
297     return {}
298
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/docker/auth.py b/docker/auth.py
--- a/docker/auth.py
+++ b/docker/auth.py
@@ -90,9 +90,12 @@
             log.debug(
                 'Using credentials store "{0}"'.format(store_name)
             )
-            return _resolve_authconfig_credstore(
+            cfg = _resolve_authconfig_credstore(
                 authconfig, registry, store_name
             )
+            if cfg is not None:
+                return cfg
+            log.debug('No entry in credstore - fetching from auth dict')
 
     # Default to the public index server
     registry = resolve_index_name(registry) if registry else INDEX_NAME

{"golden_diff": "diff --git a/docker/auth.py b/docker/auth.py\n--- a/docker/auth.py\n+++ b/docker/auth.py\n@@ -90,9 +90,12 @@\n             log.debug(\n                 'Using credentials store \"{0}\"'.format(store_name)\n             )\n-            return _resolve_authconfig_credstore(\n+            cfg = _resolve_authconfig_credstore(\n                 authconfig, registry, store_name\n             )\n+            if cfg is not None:\n+                return cfg\n+            log.debug('No entry in credstore - fetching from auth dict')\n \n     # Default to the public index server\n     registry = resolve_index_name(registry) if registry else INDEX_NAME\n", "issue": "registry auth for docker service does not work on Windows\nCredentials to authenticated docker registry are not passed to docker service on Windows after login:\r\n```\r\nclient.login(username, password, registry=registry, reauth=True)\r\nclient.services.create([any_args])\r\n```\r\n\r\nOn Centos7 it works fine.\r\nTested with AWS ECR.\r\n\r\nDebug logs (red lines - Windows, green lines - Centos7):\r\n```diff\r\n[DEBUG]: Looking for auth entry for 'XXX.amazonaws.com'\r\n[DEBUG]: No entry found\r\n[DEBUG]: http://localhost:None \"POST /v1.35/auth HTTP/1.1\" 200 48\r\n[DEBUG]: {u'IdentityToken': u'', u'Status': u'Login Succeeded'}\r\n[DEBUG]: Looking for auth config\r\n- [DEBUG]: Using credentials store \"wincred\"\r\n[DEBUG]: Looking for auth entry for 'XXX.amazonaws.com'\r\n- [DEBUG]: No entry found\r\n- [DEBUG]: No auth config found\r\n+ [DEBUG]: Found 'XXX.amazonaws.com'\r\n+ [DEBUG]: Found auth config\r\n[DEBUG]: http://localhost:None \"POST /v1.35/services/create HTTP/1.1\" 201 35\r\n[DEBUG]: http://localhost:None \"GET /v1.35/services/ixpf3gaiy0cep3qzj9ly302n6 HTTP/1.1\" 200 None\r\n```\r\n\r\nWindows environment:\r\n```\r\ndocker==2.7.0\r\ndocker-pycreds==0.2.1\r\nPython 2.7.14\r\nClient:\r\n Version:       17.12.0-ce\r\n API version:   1.35\r\n Go version:    go1.9.2\r\n Git commit:    c97c6d6\r\n Built: Wed Dec 27 20:05:22 2017\r\n OS/Arch:       windows/amd64\r\n\r\nServer:\r\n Engine:\r\n  Version:      17.12.0-ce\r\n  API version:  1.35 (minimum version 1.12)\r\n  Go version:   go1.9.2\r\n  Git commit:   c97c6d6\r\n  Built:        Wed Dec 27 20:12:29 2017\r\n  OS/Arch:      linux/amd64\r\n  Experimental: true\r\n```\r\n\r\nCentos7 environment:\r\n```\r\ndocker==2.7.0\r\ndocker-pycreds==0.2.1\r\nPython 2.7.5\r\nClient:\r\n Version:       17.12.0-ce\r\n API version:   1.35\r\n Go version:    go1.9.2\r\n Git commit:    c97c6d6\r\n Built: Wed Dec 27 20:10:14 2017\r\n OS/Arch:       linux/amd64\r\n\r\nServer:\r\n Engine:\r\n  Version:      17.12.0-ce\r\n  API version:  1.35 (minimum version 1.12)\r\n  Go version:   go1.9.2\r\n  Git commit:   c97c6d6\r\n  Built:        Wed Dec 27 20:12:46 2017\r\n  OS/Arch:      linux/amd64\r\n  Experimental: false\r\n```\n", "before_files": [{"content": "import base64\nimport json\nimport logging\n\nimport dockerpycreds\nimport six\n\nfrom . import errors\nfrom .utils import config\n\nINDEX_NAME = 'docker.io'\nINDEX_URL = 'https://index.{0}/v1/'.format(INDEX_NAME)\nTOKEN_USERNAME = '<token>'\n\nlog = logging.getLogger(__name__)\n\n\ndef resolve_repository_name(repo_name):\n    if '://' in repo_name:\n        raise errors.InvalidRepository(\n            'Repository name cannot contain a scheme ({0})'.format(repo_name)\n        )\n\n    index_name, remote_name = split_repo_name(repo_name)\n    if index_name[0] == '-' or index_name[-1] == '-':\n        raise errors.InvalidRepository(\n            'Invalid index name ({0}). Cannot begin or end with a'\n            ' hyphen.'.format(index_name)\n        )\n    return resolve_index_name(index_name), remote_name\n\n\ndef resolve_index_name(index_name):\n    index_name = convert_to_hostname(index_name)\n    if index_name == 'index.' + INDEX_NAME:\n        index_name = INDEX_NAME\n    return index_name\n\n\ndef get_config_header(client, registry):\n    log.debug('Looking for auth config')\n    if not client._auth_configs:\n        log.debug(\n            \"No auth config in memory - loading from filesystem\"\n        )\n        client._auth_configs = load_config()\n    authcfg = resolve_authconfig(client._auth_configs, registry)\n    # Do not fail here if no authentication exists for this\n    # specific registry as we can have a readonly pull. Just\n    # put the header if we can.\n    if authcfg:\n        log.debug('Found auth config')\n        # auth_config needs to be a dict in the format used by\n        # auth.py username , password, serveraddress, email\n        return encode_header(authcfg)\n    log.debug('No auth config found')\n    return None\n\n\ndef split_repo_name(repo_name):\n    parts = repo_name.split('/', 1)\n    if len(parts) == 1 or (\n        '.' not in parts[0] and ':' not in parts[0] and parts[0] != 'localhost'\n    ):\n        # This is a docker index repo (ex: username/foobar or ubuntu)\n        return INDEX_NAME, repo_name\n    return tuple(parts)\n\n\ndef get_credential_store(authconfig, registry):\n    if not registry or registry == INDEX_NAME:\n        registry = 'https://index.docker.io/v1/'\n\n    return authconfig.get('credHelpers', {}).get(registry) or authconfig.get(\n        'credsStore'\n    )\n\n\ndef resolve_authconfig(authconfig, registry=None):\n    \"\"\"\n    Returns the authentication data from the given auth configuration for a\n    specific registry. As with the Docker client, legacy entries in the config\n    with full URLs are stripped down to hostnames before checking for a match.\n    Returns None if no match was found.\n    \"\"\"\n\n    if 'credHelpers' in authconfig or 'credsStore' in authconfig:\n        store_name = get_credential_store(authconfig, registry)\n        if store_name is not None:\n            log.debug(\n                'Using credentials store \"{0}\"'.format(store_name)\n            )\n            return _resolve_authconfig_credstore(\n                authconfig, registry, store_name\n            )\n\n    # Default to the public index server\n    registry = resolve_index_name(registry) if registry else INDEX_NAME\n    log.debug(\"Looking for auth entry for {0}\".format(repr(registry)))\n\n    authdict = authconfig.get('auths', {})\n    if registry in authdict:\n        log.debug(\"Found {0}\".format(repr(registry)))\n        return authdict[registry]\n\n    for key, conf in six.iteritems(authdict):\n        if resolve_index_name(key) == registry:\n            log.debug(\"Found {0}\".format(repr(key)))\n            return conf\n\n    log.debug(\"No entry found\")\n    return None\n\n\ndef _resolve_authconfig_credstore(authconfig, registry, credstore_name):\n    if not registry or registry == INDEX_NAME:\n        # The ecosystem is a little schizophrenic with index.docker.io VS\n        # docker.io - in that case, it seems the full URL is necessary.\n        registry = INDEX_URL\n    log.debug(\"Looking for auth entry for {0}\".format(repr(registry)))\n    store = dockerpycreds.Store(credstore_name)\n    try:\n        data = store.get(registry)\n        res = {\n            'ServerAddress': registry,\n        }\n        if data['Username'] == TOKEN_USERNAME:\n            res['IdentityToken'] = data['Secret']\n        else:\n            res.update({\n                'Username': data['Username'],\n                'Password': data['Secret'],\n            })\n        return res\n    except dockerpycreds.CredentialsNotFound as e:\n        log.debug('No entry found')\n        return None\n    except dockerpycreds.StoreError as e:\n        raise errors.DockerException(\n            'Credentials store error: {0}'.format(repr(e))\n        )\n\n\ndef convert_to_hostname(url):\n    return url.replace('http://', '').replace('https://', '').split('/', 1)[0]\n\n\ndef decode_auth(auth):\n    if isinstance(auth, six.string_types):\n        auth = auth.encode('ascii')\n    s = base64.b64decode(auth)\n    login, pwd = s.split(b':', 1)\n    return login.decode('utf8'), pwd.decode('utf8')\n\n\ndef encode_header(auth):\n    auth_json = json.dumps(auth).encode('ascii')\n    return base64.urlsafe_b64encode(auth_json)\n\n\ndef parse_auth(entries, raise_on_error=False):\n    \"\"\"\n    Parses authentication entries\n\n    Args:\n      entries:        Dict of authentication entries.\n      raise_on_error: If set to true, an invalid format will raise\n                      InvalidConfigFile\n\n    Returns:\n      Authentication registry.\n    \"\"\"\n\n    conf = {}\n    for registry, entry in six.iteritems(entries):\n        if not isinstance(entry, dict):\n            log.debug(\n                'Config entry for key {0} is not auth config'.format(registry)\n            )\n            # We sometimes fall back to parsing the whole config as if it was\n            # the auth config by itself, for legacy purposes. In that case, we\n            # fail silently and return an empty conf if any of the keys is not\n            # formatted properly.\n            if raise_on_error:\n                raise errors.InvalidConfigFile(\n                    'Invalid configuration for registry {0}'.format(registry)\n                )\n            return {}\n        if 'identitytoken' in entry:\n            log.debug('Found an IdentityToken entry for registry {0}'.format(\n                registry\n            ))\n            conf[registry] = {\n                'IdentityToken': entry['identitytoken']\n            }\n            continue  # Other values are irrelevant if we have a token, skip.\n\n        if 'auth' not in entry:\n            # Starting with engine v1.11 (API 1.23), an empty dictionary is\n            # a valid value in the auths config.\n            # https://github.com/docker/compose/issues/3265\n            log.debug(\n                'Auth data for {0} is absent. Client might be using a '\n                'credentials store instead.'.format(registry)\n            )\n            conf[registry] = {}\n            continue\n\n        username, password = decode_auth(entry['auth'])\n        log.debug(\n            'Found entry (registry={0}, username={1})'\n            .format(repr(registry), repr(username))\n        )\n\n        conf[registry] = {\n            'username': username,\n            'password': password,\n            'email': entry.get('email'),\n            'serveraddress': registry,\n        }\n    return conf\n\n\ndef load_config(config_path=None, config_dict=None):\n    \"\"\"\n    Loads authentication data from a Docker configuration file in the given\n    root directory or if config_path is passed use given path.\n    Lookup priority:\n        explicit config_path parameter > DOCKER_CONFIG environment variable >\n        ~/.docker/config.json > ~/.dockercfg\n    \"\"\"\n\n    if not config_dict:\n        config_file = config.find_config_file(config_path)\n\n        if not config_file:\n            return {}\n        try:\n            with open(config_file) as f:\n                config_dict = json.load(f)\n        except (IOError, KeyError, ValueError) as e:\n            # Likely missing new Docker config file or it's in an\n            # unknown format, continue to attempt to read old location\n            # and format.\n            log.debug(e)\n            return _load_legacy_config(config_file)\n\n    res = {}\n    if config_dict.get('auths'):\n        log.debug(\"Found 'auths' section\")\n        res.update({\n            'auths': parse_auth(config_dict.pop('auths'), raise_on_error=True)\n        })\n    if config_dict.get('credsStore'):\n        log.debug(\"Found 'credsStore' section\")\n        res.update({'credsStore': config_dict.pop('credsStore')})\n    if config_dict.get('credHelpers'):\n        log.debug(\"Found 'credHelpers' section\")\n        res.update({'credHelpers': config_dict.pop('credHelpers')})\n    if res:\n        return res\n\n    log.debug(\n        \"Couldn't find auth-related section ; attempting to interpret\"\n        \"as auth-only file\"\n    )\n    return parse_auth(config_dict)\n\n\ndef _load_legacy_config(config_file):\n    log.debug(\"Attempting to parse legacy auth file format\")\n    try:\n        data = []\n        with open(config_file) as f:\n            for line in f.readlines():\n                data.append(line.strip().split(' = ')[1])\n            if len(data) < 2:\n                # Not enough data\n                raise errors.InvalidConfigFile(\n                    'Invalid or empty configuration file!'\n                )\n\n        username, password = decode_auth(data[0])\n        return {\n            INDEX_NAME: {\n                'username': username,\n                'password': password,\n                'email': data[1],\n                'serveraddress': INDEX_URL,\n            }\n        }\n    except Exception as e:\n        log.debug(e)\n        pass\n\n    log.debug(\"All parsing attempts failed - returning empty config\")\n    return {}\n", "path": "docker/auth.py"}], "after_files": [{"content": "import base64\nimport json\nimport logging\n\nimport dockerpycreds\nimport six\n\nfrom . import errors\nfrom .utils import config\n\nINDEX_NAME = 'docker.io'\nINDEX_URL = 'https://index.{0}/v1/'.format(INDEX_NAME)\nTOKEN_USERNAME = '<token>'\n\nlog = logging.getLogger(__name__)\n\n\ndef resolve_repository_name(repo_name):\n    if '://' in repo_name:\n        raise errors.InvalidRepository(\n            'Repository name cannot contain a scheme ({0})'.format(repo_name)\n        )\n\n    index_name, remote_name = split_repo_name(repo_name)\n    if index_name[0] == '-' or index_name[-1] == '-':\n        raise errors.InvalidRepository(\n            'Invalid index name ({0}). Cannot begin or end with a'\n            ' hyphen.'.format(index_name)\n        )\n    return resolve_index_name(index_name), remote_name\n\n\ndef resolve_index_name(index_name):\n    index_name = convert_to_hostname(index_name)\n    if index_name == 'index.' + INDEX_NAME:\n        index_name = INDEX_NAME\n    return index_name\n\n\ndef get_config_header(client, registry):\n    log.debug('Looking for auth config')\n    if not client._auth_configs:\n        log.debug(\n            \"No auth config in memory - loading from filesystem\"\n        )\n        client._auth_configs = load_config()\n    authcfg = resolve_authconfig(client._auth_configs, registry)\n    # Do not fail here if no authentication exists for this\n    # specific registry as we can have a readonly pull. Just\n    # put the header if we can.\n    if authcfg:\n        log.debug('Found auth config')\n        # auth_config needs to be a dict in the format used by\n        # auth.py username , password, serveraddress, email\n        return encode_header(authcfg)\n    log.debug('No auth config found')\n    return None\n\n\ndef split_repo_name(repo_name):\n    parts = repo_name.split('/', 1)\n    if len(parts) == 1 or (\n        '.' not in parts[0] and ':' not in parts[0] and parts[0] != 'localhost'\n    ):\n        # This is a docker index repo (ex: username/foobar or ubuntu)\n        return INDEX_NAME, repo_name\n    return tuple(parts)\n\n\ndef get_credential_store(authconfig, registry):\n    if not registry or registry == INDEX_NAME:\n        registry = 'https://index.docker.io/v1/'\n\n    return authconfig.get('credHelpers', {}).get(registry) or authconfig.get(\n        'credsStore'\n    )\n\n\ndef resolve_authconfig(authconfig, registry=None):\n    \"\"\"\n    Returns the authentication data from the given auth configuration for a\n    specific registry. As with the Docker client, legacy entries in the config\n    with full URLs are stripped down to hostnames before checking for a match.\n    Returns None if no match was found.\n    \"\"\"\n\n    if 'credHelpers' in authconfig or 'credsStore' in authconfig:\n        store_name = get_credential_store(authconfig, registry)\n        if store_name is not None:\n            log.debug(\n                'Using credentials store \"{0}\"'.format(store_name)\n            )\n            cfg = _resolve_authconfig_credstore(\n                authconfig, registry, store_name\n            )\n            if cfg is not None:\n                return cfg\n            log.debug('No entry in credstore - fetching from auth dict')\n\n    # Default to the public index server\n    registry = resolve_index_name(registry) if registry else INDEX_NAME\n    log.debug(\"Looking for auth entry for {0}\".format(repr(registry)))\n\n    authdict = authconfig.get('auths', {})\n    if registry in authdict:\n        log.debug(\"Found {0}\".format(repr(registry)))\n        return authdict[registry]\n\n    for key, conf in six.iteritems(authdict):\n        if resolve_index_name(key) == registry:\n            log.debug(\"Found {0}\".format(repr(key)))\n            return conf\n\n    log.debug(\"No entry found\")\n    return None\n\n\ndef _resolve_authconfig_credstore(authconfig, registry, credstore_name):\n    if not registry or registry == INDEX_NAME:\n        # The ecosystem is a little schizophrenic with index.docker.io VS\n        # docker.io - in that case, it seems the full URL is necessary.\n        registry = INDEX_URL\n    log.debug(\"Looking for auth entry for {0}\".format(repr(registry)))\n    store = dockerpycreds.Store(credstore_name)\n    try:\n        data = store.get(registry)\n        res = {\n            'ServerAddress': registry,\n        }\n        if data['Username'] == TOKEN_USERNAME:\n            res['IdentityToken'] = data['Secret']\n        else:\n            res.update({\n                'Username': data['Username'],\n                'Password': data['Secret'],\n            })\n        return res\n    except dockerpycreds.CredentialsNotFound as e:\n        log.debug('No entry found')\n        return None\n    except dockerpycreds.StoreError as e:\n        raise errors.DockerException(\n            'Credentials store error: {0}'.format(repr(e))\n        )\n\n\ndef convert_to_hostname(url):\n    return url.replace('http://', '').replace('https://', '').split('/', 1)[0]\n\n\ndef decode_auth(auth):\n    if isinstance(auth, six.string_types):\n        auth = auth.encode('ascii')\n    s = base64.b64decode(auth)\n    login, pwd = s.split(b':', 1)\n    return login.decode('utf8'), pwd.decode('utf8')\n\n\ndef encode_header(auth):\n    auth_json = json.dumps(auth).encode('ascii')\n    return base64.urlsafe_b64encode(auth_json)\n\n\ndef parse_auth(entries, raise_on_error=False):\n    \"\"\"\n    Parses authentication entries\n\n    Args:\n      entries:        Dict of authentication entries.\n      raise_on_error: If set to true, an invalid format will raise\n                      InvalidConfigFile\n\n    Returns:\n      Authentication registry.\n    \"\"\"\n\n    conf = {}\n    for registry, entry in six.iteritems(entries):\n        if not isinstance(entry, dict):\n            log.debug(\n                'Config entry for key {0} is not auth config'.format(registry)\n            )\n            # We sometimes fall back to parsing the whole config as if it was\n            # the auth config by itself, for legacy purposes. In that case, we\n            # fail silently and return an empty conf if any of the keys is not\n            # formatted properly.\n            if raise_on_error:\n                raise errors.InvalidConfigFile(\n                    'Invalid configuration for registry {0}'.format(registry)\n                )\n            return {}\n        if 'identitytoken' in entry:\n            log.debug('Found an IdentityToken entry for registry {0}'.format(\n                registry\n            ))\n            conf[registry] = {\n                'IdentityToken': entry['identitytoken']\n            }\n            continue  # Other values are irrelevant if we have a token, skip.\n\n        if 'auth' not in entry:\n            # Starting with engine v1.11 (API 1.23), an empty dictionary is\n            # a valid value in the auths config.\n            # https://github.com/docker/compose/issues/3265\n            log.debug(\n                'Auth data for {0} is absent. Client might be using a '\n                'credentials store instead.'.format(registry)\n            )\n            conf[registry] = {}\n            continue\n\n        username, password = decode_auth(entry['auth'])\n        log.debug(\n            'Found entry (registry={0}, username={1})'\n            .format(repr(registry), repr(username))\n        )\n\n        conf[registry] = {\n            'username': username,\n            'password': password,\n            'email': entry.get('email'),\n            'serveraddress': registry,\n        }\n    return conf\n\n\ndef load_config(config_path=None, config_dict=None):\n    \"\"\"\n    Loads authentication data from a Docker configuration file in the given\n    root directory or if config_path is passed use given path.\n    Lookup priority:\n        explicit config_path parameter > DOCKER_CONFIG environment variable >\n        ~/.docker/config.json > ~/.dockercfg\n    \"\"\"\n\n    if not config_dict:\n        config_file = config.find_config_file(config_path)\n\n        if not config_file:\n            return {}\n        try:\n            with open(config_file) as f:\n                config_dict = json.load(f)\n        except (IOError, KeyError, ValueError) as e:\n            # Likely missing new Docker config file or it's in an\n            # unknown format, continue to attempt to read old location\n            # and format.\n            log.debug(e)\n            return _load_legacy_config(config_file)\n\n    res = {}\n    if config_dict.get('auths'):\n        log.debug(\"Found 'auths' section\")\n        res.update({\n            'auths': parse_auth(config_dict.pop('auths'), raise_on_error=True)\n        })\n    if config_dict.get('credsStore'):\n        log.debug(\"Found 'credsStore' section\")\n        res.update({'credsStore': config_dict.pop('credsStore')})\n    if config_dict.get('credHelpers'):\n        log.debug(\"Found 'credHelpers' section\")\n        res.update({'credHelpers': config_dict.pop('credHelpers')})\n    if res:\n        return res\n\n    log.debug(\n        \"Couldn't find auth-related section ; attempting to interpret\"\n        \"as auth-only file\"\n    )\n    return parse_auth(config_dict)\n\n\ndef _load_legacy_config(config_file):\n    log.debug(\"Attempting to parse legacy auth file format\")\n    try:\n        data = []\n        with open(config_file) as f:\n            for line in f.readlines():\n                data.append(line.strip().split(' = ')[1])\n            if len(data) < 2:\n                # Not enough data\n                raise errors.InvalidConfigFile(\n                    'Invalid or empty configuration file!'\n                )\n\n        username, password = decode_auth(data[0])\n        return {\n            INDEX_NAME: {\n                'username': username,\n                'password': password,\n                'email': data[1],\n                'serveraddress': INDEX_URL,\n            }\n        }\n    except Exception as e:\n        log.debug(e)\n        pass\n\n    log.debug(\"All parsing attempts failed - returning empty config\")\n    return {}\n", "path": "docker/auth.py"}]}