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
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)))