async def _basic_auth_registry_request(app: web.Application, path: str,
                                       method: str,
                                       **session_kwargs) -> Tuple[Dict, Dict]:
    if not config.REGISTRY_URL:
        raise exceptions.DirectorException("URL to registry is not defined")

    url = URL(
        f"{'https' if config.REGISTRY_SSL else 'http'}://{config.REGISTRY_URL}{path}"
    )
    logger.debug("Requesting registry using %s", url)
    # try the registry with basic authentication first, spare 1 call
    resp_data: Dict = {}
    resp_headers: Dict = {}
    auth = (BasicAuth(login=config.REGISTRY_USER, password=config.REGISTRY_PW)
            if config.REGISTRY_AUTH and config.REGISTRY_USER
            and config.REGISTRY_PW else None)

    session = app[APP_CLIENT_SESSION_KEY]
    try:
        async with session.request(method.lower(),
                                   url,
                                   auth=auth,
                                   **session_kwargs) as response:
            if response.status == HTTPStatus.UNAUTHORIZED:
                logger.debug("Registry unauthorized request: %s", await
                             response.text())
                # basic mode failed, test with other auth mode
                resp_data, resp_headers = await _auth_registry_request(
                    url, method, response.headers, session, **session_kwargs)

            elif response.status == HTTPStatus.NOT_FOUND:
                logger.exception("Path to registry not found: %s", url)
                raise exceptions.ServiceNotAvailableError(str(path))

            elif response.status > 399:
                logger.exception("Unknown error while accessing registry: %s",
                                 str(response))
                raise exceptions.RegistryConnectionError(str(response))

            else:
                # registry that does not need an auth
                resp_data = await response.json(content_type=None)
                resp_headers = response.headers

            return (resp_data, resp_headers)
    except client_exceptions.ClientError as exc:
        logger.exception("Unknown error while accessing registry: %s",
                         str(exc))
        raise exceptions.DirectorException(
            f"Unknown error while accessing registry: {str(exc)}")
Exemple #2
0
async def _auth_registry_request(
    url: URL, method: str, auth_headers: Dict, session: ClientSession
) -> Tuple[Dict, Dict]:
    if not config.REGISTRY_AUTH or not config.REGISTRY_USER or not config.REGISTRY_PW:
        raise exceptions.RegistryConnectionError(
            "Wrong configuration: Authentication to registry is needed!"
        )
    # auth issue let's try some authentication get the auth type
    auth_type = None
    auth_details: Dict[str, str] = {}
    for key in auth_headers:
        if str(key).lower() == "www-authenticate":
            auth_type, auth_value = str(auth_headers[key]).split(" ", 1)
            auth_details = {
                x.split("=")[0]: x.split("=")[1].strip('"')
                for x in auth_value.split(",")
            }
            break
    if not auth_type:
        raise exceptions.RegistryConnectionError(
            "Unknown registry type: cannot deduce authentication method!"
        )
    auth = BasicAuth(login=config.REGISTRY_USER, password=config.REGISTRY_PW)

    # bearer type, it needs a token with all communications
    if auth_type == "Bearer":
        # get the token
        token_url = URL(auth_details["realm"]).with_query(
            service=auth_details["service"], scope=auth_details["scope"]
        )
        async with session.get(token_url, auth=auth) as token_resp:
            if not token_resp.status == 200:
                raise exceptions.RegistryConnectionError(
                    "Unknown error while authentifying with registry: {}".format(
                        str(token_resp)
                    )
                )
            bearer_code = (await token_resp.json())["token"]
            headers = {"Authorization": "Bearer {}".format(bearer_code)}
            async with getattr(session, method.lower())(
                url, headers=headers
            ) as resp_wtoken:
                if resp_wtoken.status == 404:
                    _logger.exception("path to registry not found: %s", url)
                    raise exceptions.ServiceNotAvailableError(str(url))
                if resp_wtoken.status > 399:
                    _logger.exception(
                        "Unknown error while accessing with token authorized registry: %s",
                        str(resp_wtoken),
                    )
                    raise exceptions.RegistryConnectionError(str(resp_wtoken))
                resp_data = await resp_wtoken.json(content_type=None)
                resp_headers = resp_wtoken.headers
                return (resp_data, resp_headers)
    elif auth_type == "Basic":
        # basic authentication should not be since we tried already...
        async with getattr(session, method.lower())(url, auth=auth) as resp_wbasic:
            if resp_wbasic.status == 404:
                _logger.exception("path to registry not found: %s", url)
                raise exceptions.ServiceNotAvailableError(str(url))
            if resp_wbasic.status > 399:
                _logger.exception(
                    "Unknown error while accessing with token authorized registry: %s",
                    str(resp_wbasic),
                )
                raise exceptions.RegistryConnectionError(str(resp_wbasic))
            resp_data = await resp_wbasic.json(content_type=None)
            resp_headers = resp_wbasic.headers
            return (resp_data, resp_headers)
    raise exceptions.RegistryConnectionError(
        f"Unknown registry authentification type: {url}"
    )