Source code for flux_restful.auth
"""
Pluggable authentication for the Flux RESTful API.
Select a backend with FLUX_AUTH_BACKEND (see flux_restful.core.config.KNOWN_AUTH_BACKENDS).
Routers only depend on get_backend() and the Principal it returns.
"""
from typing import Dict, Optional, Type
from flux_restful.auth.base import AuthBackend, AuthError, Principal # noqa: F401
from flux_restful.auth.database import DatabaseBackend, SharedSecretBackend
from flux_restful.auth.none import NoAuthBackend
from flux_restful.auth.oidc import OidcBackend
from flux_restful.auth.pam import PamBackend
from flux_restful.core.config import settings
BACKENDS: Dict[str, Type[AuthBackend]] = {
NoAuthBackend.name: NoAuthBackend,
DatabaseBackend.name: DatabaseBackend,
SharedSecretBackend.name: SharedSecretBackend,
PamBackend.name: PamBackend,
OidcBackend.name: OidcBackend,
}
_backend: Optional[AuthBackend] = None
[docs]def create_backend(name: str) -> AuthBackend:
"""
Instantiate and validate a backend by name.
"""
try:
cls = BACKENDS[name]
except KeyError:
raise AuthError(
f"Unknown auth backend '{name}'. Choose from: {', '.join(BACKENDS)}"
)
backend = cls()
if backend.issues_tokens and not settings.token_signing_key:
raise AuthError(
f"The {name} auth backend issues access tokens, so FLUX_TOKEN_SIGNING_KEY "
"must be set (for example: python3 -c 'import secrets; "
"print(secrets.token_hex(32))'). It must be the same for every worker."
)
backend.validate()
return backend
[docs]def get_backend() -> AuthBackend:
"""
The configured backend (created on first use).
"""
global _backend
if _backend is None:
_backend = create_backend(settings.auth_backend)
return _backend
[docs]def reset_backend() -> None:
"""
Forget the cached backend so it is re-created from settings (for tests).
"""
global _backend
_backend = None
[docs]def handshake_enabled() -> bool:
"""
The shared-secret handshake on /v1/token needs a password backend and a secret.
"""
return bool(settings.secret_key) and get_backend().supports_password
[docs]def describe() -> dict:
"""
Public description of how to authenticate, safe to show to anyone.
"""
backend = get_backend()
info = {
"backend": backend.name,
"password_login": backend.supports_password,
"shared_secret_handshake": handshake_enabled(),
}
if backend.name == OidcBackend.name:
info["oidc"] = {
"issuer": settings.oidc_issuer,
"audience": settings.oidc_audience,
}
return info