def test_resolve_registry_and_auth(self): auth_config = { 'https://index.docker.io/v1/': {'auth': 'indexuser'}, 'my.registry.net': {'auth': 'privateuser'}, } # library image image = 'image' self.assertEqual( resolve_authconfig(auth_config, resolve_repository_name(image)[0]), {'auth': 'indexuser'}, ) # docker hub image image = 'username/image' self.assertEqual( resolve_authconfig(auth_config, resolve_repository_name(image)[0]), {'auth': 'indexuser'}, ) # private registry image = 'my.registry.net/image' self.assertEqual( resolve_authconfig(auth_config, resolve_repository_name(image)[0]), {'auth': 'privateuser'}, ) # unauthenticated registry image = 'other.registry.net/image' self.assertEqual( resolve_authconfig(auth_config, resolve_repository_name(image)[0]), None, )
def test_resolve_authconfig(self): auth_config = { 'https://index.docker.io/v1/': {'auth': 'indexuser'}, 'http://my.registry.net/v1/': {'auth': 'privateuser'} } # hostname only self.assertEqual( resolve_authconfig(auth_config, 'my.registry.net'), {'auth': 'privateuser'} ) # no protocol self.assertEqual( resolve_authconfig(auth_config, 'my.registry.net/v1/'), {'auth': 'privateuser'} ) # no path self.assertEqual( resolve_authconfig(auth_config, 'http://my.registry.net'), {'auth': 'privateuser'} ) # no path, trailing slash self.assertEqual( resolve_authconfig(auth_config, 'http://my.registry.net/'), {'auth': 'privateuser'} ) # no path, wrong secure protocol self.assertEqual( resolve_authconfig(auth_config, 'https://my.registry.net'), {'auth': 'privateuser'} ) # no path, wrong insecure protocol self.assertEqual( resolve_authconfig(auth_config, 'http://index.docker.io'), {'auth': 'indexuser'} ) # with path, wrong protocol self.assertEqual( resolve_authconfig(auth_config, 'https://my.registry.net/v1/'), {'auth': 'privateuser'} ) # default registry self.assertEqual( resolve_authconfig(auth_config), {'auth': 'indexuser'} ) # default registry (explicit None) self.assertEqual( resolve_authconfig(auth_config, None), {'auth': 'indexuser'} ) # fully explicit self.assertEqual( resolve_authconfig(auth_config, 'http://my.registry.net/v1/'), {'auth': 'privateuser'} )
def test_resolve_authconfig_no_path_wrong_secure_proto(self): self.assertEqual( auth.resolve_authconfig( self.auth_config, 'https://my.registry.net' ), {'auth': 'privateuser'} )
def test_resolve_authconfig_no_path(self): self.assertEqual( auth.resolve_authconfig( self.auth_config, 'http://my.registry.net' ), {'auth': 'privateuser'} )
def test_resolve_authconfig_hostname_only(self): self.assertEqual( auth.resolve_authconfig( self.auth_config, 'my.registry.net' )['username'], 'privateuser' )
def pull(self, repository, tag=None, stream=False): registry, repo_name = auth.resolve_repository_name(repository) if repo_name.count(":") == 1: repository, tag = repository.rsplit(":", 1) params = {'tag': tag, 'fromImage': repository} headers = {} if utils.compare_version('1.5', self._version) >= 0: if getattr(self, '_cfg', None) is None: self._cfg = auth.load_config() authcfg = auth.resolve_authconfig(self._cfg, registry) # do not fail if no atuhentication exists # for this specific registry as we can have a readonly pull if authcfg: headers['X-Registry-Auth'] = auth.encode_header(authcfg) u = self._url("/images/create") response = self._post(u, params=params, headers=headers, stream=stream, timeout=None) if stream: return self._stream_helper(response) else: return self._result(response)
def test_resolve_authconfig_legacy_config(self): self.assertEqual( auth.resolve_authconfig( self.auth_config, 'legacy.registry.url' )['username'], 'legacyauth' )
def test_resolve_authconfig_fully_explicit(self): self.assertEqual( auth.resolve_authconfig( self.auth_config, 'http://my.registry.net/v1/' )['username'], 'privateuser' )
def pull(self, repository, tag=None, stream=False): registry, repo_name = auth.resolve_repository_name(repository) if repo_name.count(":") == 1: repository, tag = repository.rsplit(":", 1) params = { 'tag': tag, 'fromImage': repository } headers = {} if utils.compare_version('1.5', self._version) >= 0: if getattr(self, '_cfg', None) is None: self._cfg = auth.load_config() authcfg = auth.resolve_authconfig(self._cfg, registry) # do not fail if no atuhentication exists # for this specific registry as we can have a readonly pull if authcfg: headers['X-Registry-Auth'] = auth.encode_header(authcfg) u = self._url("/images/create") response = self._post(u, params=params, headers=headers, stream=stream, timeout=None) if stream: return self._stream_helper(response) else: return self._result(response)
def test_resolve_authconfig_no_protocol(self): self.assertEqual( auth.resolve_authconfig( self.auth_config, 'my.registry.net/v1/' )['username'], 'privateuser' )
def test_resolve_authconfig_no_path_trailing_slash(self): self.assertEqual( auth.resolve_authconfig( self.auth_config, 'http://my.registry.net/' )['username'], 'privateuser' )
def test_resolve_authconfig_no_path_wrong_insecure_proto(self): self.assertEqual( auth.resolve_authconfig( self.auth_config, 'http://index.docker.io' )['username'], 'indexuser' )
def test_resolve_registry_and_auth_hub_image(self): image = 'username/image' self.assertEqual( auth.resolve_authconfig(self.auth_config, auth.resolve_repository_name(image)[0]), {'auth': 'indexuser'}, )
def test_resolve_registry_and_auth_private_registry(self): image = 'my.registry.net/image' self.assertEqual( auth.resolve_authconfig(self.auth_config, auth.resolve_repository_name(image)[0]), {'auth': 'privateuser'}, )
def test_resolve_registry_and_auth_unauthenticated_registry(self): image = 'other.registry.net/image' self.assertEqual( auth.resolve_authconfig(self.auth_config, auth.resolve_repository_name(image)[0]), None, )
def test_resolve_authconfig_path_wrong_proto(self): self.assertEqual( auth.resolve_authconfig( self.auth_config, 'https://my.registry.net/v1/' )['username'], 'privateuser' )
def test_resolve_registry_and_auth_explicit_legacy_hub(self): image = 'index.docker.io/username/image' self.assertEqual( auth.resolve_authconfig( self.auth_config, auth.resolve_repository_name(image)[0])['username'], 'indexuser', )
def test_resolve_registry_and_auth_library_image(self): image = 'image' self.assertEqual( auth.resolve_authconfig( self.auth_config, auth.resolve_repository_name(image)[0])['username'], 'indexuser', )
def test_resolve_authconfig(self): auth_config = { 'https://index.docker.io/v1/': { 'auth': 'indexuser' }, 'http://my.registry.net/v1/': { 'auth': 'privateuser' } } # hostname only self.assertEqual(resolve_authconfig(auth_config, 'my.registry.net'), {'auth': 'privateuser'}) # no protocol self.assertEqual( resolve_authconfig(auth_config, 'my.registry.net/v1/'), {'auth': 'privateuser'}) # no path self.assertEqual( resolve_authconfig(auth_config, 'http://my.registry.net'), {'auth': 'privateuser'}) # no path, trailing slash self.assertEqual( resolve_authconfig(auth_config, 'http://my.registry.net/'), {'auth': 'privateuser'}) # no path, wrong secure protocol self.assertEqual( resolve_authconfig(auth_config, 'https://my.registry.net'), {'auth': 'privateuser'}) # no path, wrong insecure protocol self.assertEqual( resolve_authconfig(auth_config, 'http://index.docker.io'), {'auth': 'indexuser'}) # with path, wrong protocol self.assertEqual( resolve_authconfig(auth_config, 'https://my.registry.net/v1/'), {'auth': 'privateuser'}) # default registry self.assertEqual(resolve_authconfig(auth_config), {'auth': 'indexuser'}) # default registry (explicit None) self.assertEqual(resolve_authconfig(auth_config, None), {'auth': 'indexuser'}) # fully explicit self.assertEqual( resolve_authconfig(auth_config, 'http://my.registry.net/v1/'), {'auth': 'privateuser'})
def test_resolve_registry_and_auth_unauthenticated_registry(self): image = 'other.registry.net/image' self.assertEqual( auth.resolve_authconfig( self.auth_config, auth.resolve_repository_name(image)[0] ), None, )
def test_resolve_registry_and_auth_explicit_legacy_hub(self): image = 'index.docker.io/username/image' self.assertEqual( auth.resolve_authconfig( self.auth_config, auth.resolve_repository_name(image)[0] )['username'], 'indexuser', )
def test_resolve_registry_and_auth_private_registry(self): image = 'my.registry.net/image' self.assertEqual( auth.resolve_authconfig( self.auth_config, auth.resolve_repository_name(image)[0] )['username'], 'privateuser', )
def test_resolve_registry_and_auth_library_image(self): image = 'image' self.assertEqual( auth.resolve_authconfig( self.auth_config, auth.resolve_repository_name(image)[0] ), {'auth': 'indexuser'}, )
def test_resolve_registry_and_auth_hub_image(self): image = 'username/image' self.assertEqual( auth.resolve_authconfig( self.auth_config, auth.resolve_repository_name(image)[0] )['username'], 'indexuser', )
def test_resolve_registry_and_auth(self): auth_config = {"https://index.docker.io/v1/": {"auth": "indexuser"}, "my.registry.net": {"auth": "privateuser"}} # library image image = "image" self.assertEqual(resolve_authconfig(auth_config, resolve_repository_name(image)[0]), {"auth": "indexuser"}) # docker hub image image = "username/image" self.assertEqual(resolve_authconfig(auth_config, resolve_repository_name(image)[0]), {"auth": "indexuser"}) # private registry image = "my.registry.net/image" self.assertEqual(resolve_authconfig(auth_config, resolve_repository_name(image)[0]), {"auth": "privateuser"}) # unauthenticated registry image = "other.registry.net/image" self.assertEqual(resolve_authconfig(auth_config, resolve_repository_name(image)[0]), None)
def _run(self): registry = LoginTask.registry_for_container(self.container, self._registries) if not registry: return if 'username' not in registry or not registry['username']: dockercfg_path = os.path.expanduser(os.path.join('/root/.docker', 'config.json')) if dockercfg_path and os.path.exists(dockercfg_path): auth_configs = auth.load_config(dockercfg_path) authcfg = auth.resolve_authconfig(auth_configs, registry['registry']) username = authcfg.get('username', None) if username: registry['username'] = username else: raise Exception("Missing login (username) credentials for registry {}".format(registry['registry'])) if 'password' not in registry or not registry['password']: dockercfg_path = os.path.expanduser(os.path.join('/root/.docker', 'config.json')) if dockercfg_path and os.path.exists(dockercfg_path): auth_configs = auth.load_config(dockercfg_path) authcfg = auth.resolve_authconfig(auth_configs, registry['registry']) username = authcfg.get('password', None) if username: registry['password'] = username else: raise Exception("Missing login (password) credentials for registry {}".format(registry['registry'])) if 'username' not in registry: raise Exception("Missing username for registry {}".format(registry['registry'])) if 'password' not in registry: raise Exception("Missing password for registry {}".format(registry['registry'])) self.o.reset() self.o.pending('logging in to {}...'.format(registry['registry'])) try: self.container.ship.backend.login(**registry) except Exception as e: raise exceptions.ContainerOrchestrationException( self.container, 'Login to {} as {} failed: {}' .format(registry['registry'], registry['username'], e))
def test_resolve_registry_and_auth(self): auth_config = { 'https://index.docker.io/v1/': { 'auth': 'indexuser' }, 'my.registry.net': { 'auth': 'privateuser' }, } # library image image = 'image' self.assertEqual( resolve_authconfig(auth_config, resolve_repository_name(image)[0]), {'auth': 'indexuser'}, ) # docker hub image image = 'username/image' self.assertEqual( resolve_authconfig(auth_config, resolve_repository_name(image)[0]), {'auth': 'indexuser'}, ) # private registry image = 'my.registry.net/image' self.assertEqual( resolve_authconfig(auth_config, resolve_repository_name(image)[0]), {'auth': 'privateuser'}, ) # unauthenticated registry image = 'other.registry.net/image' self.assertEqual( resolve_authconfig(auth_config, resolve_repository_name(image)[0]), None, )
def test_resolve_auth_with_empty_credstore_and_auth_dict(self): auth_config = { 'auths': auth.parse_auth({ 'https://index.docker.io/v1/': self.index_config, }), 'credsStore': 'blackbox' } with mock.patch('docker.auth._resolve_authconfig_credstore') as m: m.return_value = None assert 'indexuser' == auth.resolve_authconfig( auth_config, None )['username']
def test_resolve_auth_with_empty_credstore_and_auth_dict(self): auth_config = { 'auths': auth.parse_auth({ 'https://index.docker.io/v1/': self.index_config, }), 'credsStore': 'blackbox' } with mock.patch('docker.auth._resolve_authconfig_credstore') as m: m.return_value = None assert 'indexuser' == auth.resolve_authconfig(auth_config, None)['username']
def push(self, repository): registry, repo_name = auth.resolve_repository_name(repository) u = self._url("/images/{0}/push".format(repository)) headers = {} if getattr(self, '_cfg', None) is None: self._cfg = auth.load_config() authcfg = auth.resolve_authconfig(self._cfg, registry) if utils.compare_version('1.5', self._version) >= 0: # do not fail if no atuhentication exists # for this specific registry as we can have an anon push if authcfg: headers['X-Registry-Auth'] = auth.encode_header(authcfg) return self._result(self._post_json(u, None, headers=headers)) return self._result(self._post_json(u, authcfg))
def login(self, username, password=None, email=None, registry=None): url = self._url("/auth") if registry is None: registry = auth.INDEX_URL if getattr(self, '_cfg', None) is None: self._cfg = auth.load_config() authcfg = auth.resolve_authconfig(self._cfg, registry) if 'username' in authcfg and authcfg['username'] == username: return authcfg req_data = {'username': username, 'password': password, 'email': email} res = self._result(self._post_json(url, data=req_data), True) if res['Status'] == 'Login Succeeded': self._cfg['Configs'][registry] = req_data return res
def login(self, username, password=None, email=None, registry=None): url = self._url("/auth") if registry is None: registry = auth.INDEX_URL if getattr(self, "_cfg", None) is None: self._cfg = auth.load_config() authcfg = auth.resolve_authconfig(self._cfg, registry) if "username" in authcfg and authcfg["username"] == username: return authcfg req_data = {"username": username, "password": password, "email": email} res = self._result(self._post_json(url, data=req_data), True) if res["Status"] == "Login Succeeded": self._cfg["Configs"][registry] = req_data return res
def push_image(self, name, tag=None): ''' If the name of the image contains a repository path, then push the image. :param name Name of the image to push. :param tag Use a specific tag. :return: None ''' repository = name if not tag: repository, tag = utils.parse_repository_tag(name) registry, repo_name = auth.resolve_repository_name(repository) if re.search('/', repository): if registry: config = auth.load_config() if not auth.resolve_authconfig(config, registry): self.fail( "Error: configuration for %s not found. Try logging into %s first." % (registry, registry)) self.log("pushing image %s" % repository) self.results['actions'].append( "Pushed image %s to %s:%s" % (self.name, self.repository, self.tag)) self.results['changed'] = True if not self.check_mode: status = None try: for line in self.client.push(repository, tag=tag, stream=True): line = json.loads(line) self.log(line, pretty_print=True) if line.get('errorDetail'): raise Exception(line['errorDetail']['message']) status = line.get('status') except Exception as exc: if re.search('unauthorized', str(exc)): self.fail( "Error pushing image %s: %s. Does the repository exist?" % (repository, str(exc))) self.fail("Error pushing image %s: %s" % (repository, str(exc))) self.results['image'] = self.client.find_image(name=repository, tag=tag) if not self.results['image']: self.results['image'] = dict() self.results['image']['push_status'] = status
def test_load_json_config(self): folder = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, folder) cfg_path = os.path.join(folder, '.dockercfg') auth_ = base64.b64encode(b'sakuya:izayoi').decode('ascii') email = '*****@*****.**' with open(cfg_path, 'w') as f: json.dump({auth.INDEX_URL: {'auth': auth_, 'email': email}}, f) cfg = auth.load_config(cfg_path) assert auth.resolve_authconfig(cfg) is not None assert cfg['auths'][auth.INDEX_URL] is not None cfg = cfg['auths'][auth.INDEX_URL] assert cfg['username'] == 'sakuya' assert cfg['password'] == 'izayoi' assert cfg['email'] == email assert cfg.get('Auth') is None
def get_jwt_for_registry(auth_url, registry, appname): # get auth username and password from dockercfg try: cfg = auth.resolve_authconfig(auth.load_config(), registry=registry) username = cfg['username'] if 'username' in cfg else cfg['Username'] password = cfg['password'] if 'password' in cfg else cfg['Password'] # phase, phase_config = get_phase_config_from_registry(registry) # domain = phase_config.get(user_config.domain_key, '') # only use `lain.local` as service url = "%s?service=%s&scope=repository:%s:push,pull&account=%s" % ( auth_url, "lain.local", appname, username) response = requests.get(url, auth=HTTPBasicAuth(username, password)) if response.status_code < 400 and response.json()['token']: return response.json()['token'] except Exception as e: warn("can not load registry auth config : %s, need lain login first." % e) return ''
def test_load_legacy_config(self): folder = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, folder) cfg_path = os.path.join(folder, '.dockercfg') auth_ = base64.b64encode(b'sakuya:izayoi').decode('ascii') with open(cfg_path, 'w') as f: f.write('auth = {0}\n'.format(auth_)) f.write('email = [email protected]') cfg = auth.load_config(cfg_path) assert auth.resolve_authconfig(cfg) is not None assert cfg['auths'][auth.INDEX_NAME] is not None cfg = cfg['auths'][auth.INDEX_NAME] assert cfg['username'] == 'sakuya' assert cfg['password'] == 'izayoi' assert cfg['email'] == '*****@*****.**' assert cfg.get('Auth') is None
def login(self, username, password=None, email=None, registry=None): url = self._url("/auth") if registry is None: registry = auth.INDEX_URL if getattr(self, '_cfg', None) is None: self._cfg = auth.load_config() authcfg = auth.resolve_authconfig(self._cfg, registry) if 'username' in authcfg and authcfg['username'] == username: return authcfg req_data = { 'username': username, 'password': password, 'email': email } res = self._result(self._post_json(url, data=req_data), True) if res['Status'] == 'Login Succeeded': self._cfg['Configs'][registry] = req_data return res
def push(self, repository, authcfg=None): registry, _ = auth.resolve_repository_name(repository) u = self._url("/images/{0}/push".format(repository)) headers = {} if authcfg is None: if getattr(self, '_cfg', None) is None: self._cfg = auth.load_config() authcfg = auth.resolve_authconfig(self._cfg, registry) if utils.compare_version('1.5', self._version) >= 0: # do not fail if no atuhentication exists # for this specific registry as we can have an anon push if authcfg: headers['X-Registry-Auth'] = auth.encode_header(authcfg) response = self._post_json(u, None, headers=headers, stream=True) else: response = self._post_json(u, authcfg, stream=True) response.raise_for_status() return response.iter_content(1)
def push(self, repository, stream=False): registry, repo_name = auth.resolve_repository_name(repository) u = self._url("/images/{0}/push".format(repository)) headers = {} if getattr(self, "_cfg", None) is None: self._cfg = auth.load_config() authcfg = auth.resolve_authconfig(self._cfg, registry) if utils.compare_version("1.5", self._version) >= 0: # do not fail if no atuhentication exists # for this specific registry as we can have an anon push if authcfg: headers["X-Registry-Auth"] = auth.encode_header(authcfg) if stream: return self._stream_helper(self._post_json(u, None, headers=headers, stream=True)) else: return self._result(self._post_json(u, None, headers=headers, stream=False)) if stream: return self._stream_helper(self._post_json(u, authcfg, stream=True)) else: return self._result(self._post_json(u, authcfg, stream=False))
def push_image(self, name, tag=None): ''' If the name of the image contains a repository path, then push the image. :param name Name of the image to push. :param tag Use a specific tag. :return: None ''' repository = name if not tag: repository, tag = utils.parse_repository_tag(name) registry, repo_name = auth.resolve_repository_name(repository) if re.search('/', repository): if registry: config = auth.load_config() if not auth.resolve_authconfig(config, registry): self.fail("Error: configuration for %s not found. Try logging into %s first." % registry) self.log("pushing image %s" % repository) self.results['actions'].append("Pushed image %s to %s:%s" % (self.name, self.repository, self.tag)) self.results['changed'] = True if not self.check_mode: status = None try: for line in self.client.push(repository, tag=tag, stream=True): line = json.loads(line) self.log(line, pretty_print=True) if line.get('errorDetail'): raise Exception(line['errorDetail']['message']) status = line.get('status') except Exception as exc: if re.search('unauthorized', str(exc)): self.fail("Error pushing image %s: %s. Does the repository exist?" % (repository, str(exc))) self.fail("Error pushing image %s: %s" % (repository, str(exc))) self.results['image'] = self.client.find_image(name=repository, tag=tag) if not self.results['image']: self.results['image'] = dict() self.results['image']['push_status'] = status
def push_image(self, name, tag=None): ''' Push an image to a repository. :param name - name of the image to push. Type: str :param tag - use a specific tag. Type: str :return: None ''' repository = name if not tag: repository, tag = utils.parse_repository_tag(name) registry, repo_name = auth.resolve_repository_name(repository) if registry: config = auth.load_config() if not auth.resolve_authconfig(config, registry): self.fail("Error: configuration for %s not found. Try logging into %s first." % registry) try: self.log("pushing image %s" % (repository)) status = None if not self.check_mode: self.results['actions'].append("Pushed image %s to %s:%s" % (self.name, self.repository, self.tag)) for line in self.client.push(repository, tag=tag, stream=True): response = json.loads(line) self.log(response, pretty_print=True) if response.get('errorDetail'): # there was an error raise Exception(response['errorDetail']['message']) status = response.get('status') self.results['changed'] = True image = self.client.find_image(name=repository, tag=tag) if image: self.results['image'] = image self.results['image']['push_status'] = status except Exception, exc: if re.search(r'unauthorized', str(exc)): self.fail("Error pushing image %s: %s. Does the repository exist?" % (repository, str(exc))) self.fail("Error pushing image %s: %s" % (repository, str(exc)))
def test_resolve_authconfig_legacy_config(self): self.assertEqual( auth.resolve_authconfig(self.auth_config, 'legacy.registry.url'), {'auth': 'legacyauth'})
def test_resolve_authconfig_no_path_wrong_secure_proto(self): self.assertEqual( auth.resolve_authconfig(self.auth_config, 'https://my.registry.net'), {'auth': 'privateuser'})
def test_resolve_authconfig_no_path(self): self.assertEqual( auth.resolve_authconfig(self.auth_config, 'http://my.registry.net'), {'auth': 'privateuser'})
def test_resolve_registry_and_auth_library_image(self): image = 'image' assert auth.resolve_authconfig( self.auth_config, auth.resolve_repository_name(image)[0] )['username'] == 'indexuser'
def test_resolve_registry_and_auth_explicit_hub(self): image = 'docker.io/username/image' assert auth.resolve_authconfig( self.auth_config, auth.resolve_repository_name(image)[0] )['username'] == 'indexuser'
def test_resolve_authconfig_no_match(self): assert auth.resolve_authconfig( self.auth_config, 'does.not.exist' ) is None
def test_resolve_authconfig_legacy_config(self): assert auth.resolve_authconfig( self.auth_config, 'legacy.registry.url' )['username'] == 'legacyauth'
def test_resolve_authconfig_default_registry(self): self.assertEqual(auth.resolve_authconfig(self.auth_config), {'auth': 'indexuser'})
def test_resolve_authconfig_default_explicit_none(self): self.assertEqual(auth.resolve_authconfig(self.auth_config, None), {'auth': 'indexuser'})
def test_resolve_authconfig_no_match(self): self.assertTrue( auth.resolve_authconfig(self.auth_config, 'does.not.exist') is None )