コード例 #1
0
    def _get_oidc_provider(
            self,
            provider_id: Union[str,
                               None] = None) -> Tuple[str, OidcProviderInfo]:
        """
        Get OpenID Connect discovery URL for given provider_id

        :param provider_id: id of OIDC provider as specified by backend (/credentials/oidc).
            Can be None if there is just one provider.
        :return: updated provider_id and provider info object
        """
        if self._api_version.at_least("1.0.0"):
            oidc_info = self.get("/credentials/oidc",
                                 expected_status=200).json()
            providers = {p["id"]: p for p in oidc_info["providers"]}
            _log.info(
                "Found OIDC providers: {p}".format(p=list(providers.keys())))
            if provider_id:
                if provider_id not in providers:
                    raise OpenEoClientException(
                        "Requested OIDC provider {r!r} not available. Should be one of {p}."
                        .format(r=provider_id, p=list(providers.keys())))
                provider = providers[provider_id]
            elif len(providers) == 1:
                provider_id, provider = providers.popitem()
                _log.info(
                    "No OIDC provider given, but only one available: {p!r}. Use that one."
                    .format(p=provider_id))
            else:
                # Check if there is a single provider in the config to use.
                backend = self._orig_url
                provider_configs = self._get_auth_config(
                ).get_oidc_provider_configs(backend=backend)
                intersection = set(provider_configs.keys()).intersection(
                    providers.keys())
                if len(intersection) == 1:
                    provider_id = intersection.pop()
                    provider = providers[provider_id]
                    _log.info(
                        "No OIDC provider id given, but only one in config (backend {b!r}): {p!r}."
                        " Use that one.".format(b=backend, p=provider_id))
                else:
                    raise OpenEoClientException(
                        "No OIDC provider id given. Pick one from: {p!r}.".
                        format(p=list(providers.keys())))
            provider = OidcProviderInfo.from_dict(provider)
        else:
            # Per spec: '/credentials/oidc' will redirect to  OpenID Connect discovery document
            provider = OidcProviderInfo(
                discovery_url=self.build_url('/credentials/oidc'))
        return provider_id, provider
コード例 #2
0
def main_add_oidc(args):
    """
    Add a config entry for OIDC auth
    """
    backend = args.backend
    provider_id = args.provider_id
    client_id = args.client_id
    ask_client_secret = args.ask_client_secret
    use_default_client = args.use_default_client
    config = AuthConfig()

    print("Will add OpenID Connect auth config for backend URL {b!r}".format(
        b=backend))
    print("to config file: {c!r}".format(c=str(config.path)))

    con = connect(backend)
    api_version = con.capabilities().api_version_check
    if api_version < "1.0.0":
        raise CliToolException(
            "Backend API version is too low: {v} < 1.0.0".format(
                v=api_version))
    # Find provider ID
    oidc_info = con.get("/credentials/oidc", expected_status=200).json()
    providers = OrderedDict((p["id"], OidcProviderInfo.from_dict(p))
                            for p in oidc_info["providers"])

    if not providers:
        raise CliToolException(
            "No OpenID Connect providers listed by backend {b!r}.".format(
                b=backend))
    if not provider_id:
        if len(providers) == 1:
            provider_id = list(providers.keys())[0]
        else:
            provider_id = _interactive_choice(
                title="Backend {b!r} has multiple OpenID Connect providers.".
                format(b=backend),
                options=[(p.id, "{t} (issuer {s})".format(t=p.title,
                                                          s=p.issuer))
                         for p in providers.values()])
    if provider_id not in providers:
        raise CliToolException(
            "Invalid provider ID {p!r}. Should be one of {o}.".format(
                p=provider_id, o=list(providers.keys())))
    provider = providers[provider_id]
    print("Using provider ID {p!r} (issuer {i!r})".format(p=provider_id,
                                                          i=provider.issuer))

    # Get client_id and client_secret (if necessary)
    if use_default_client:
        if not provider.default_clients:
            show_warning(
                "No default clients declared for provider {p!r}".format(
                    p=provider_id))
        client_id, client_secret = None, None
    else:
        if not client_id:
            if provider.default_clients:
                client_prompt = "Enter client_id or leave empty to use default client, and press enter: "
            else:
                client_prompt = "Enter client_id and press enter: "
            client_id = builtins.input(client_prompt).strip() or None
        print("Using client ID {u!r}".format(u=client_id))
        if not client_id and not provider.default_clients:
            show_warning("Given client ID was empty.")

        if client_id and ask_client_secret:
            client_secret = getpass(
                "Enter client_secret or leave empty to not use a secret, and press enter: "
            ) or None
        else:
            client_secret = None

    config.set_oidc_client_config(backend=backend,
                                  provider_id=provider_id,
                                  client_id=client_id,
                                  client_secret=client_secret,
                                  issuer=provider.issuer)
    print("Saved client information to {p!r}".format(p=str(config.path)))