fix(auth): allow unauthenticated access to health and version endpoints

The AuthenticationMiddleware was blocking all requests without an
Authorization header, including health and version endpoints that are
needed by monitoring tools, load balancers, and Kubernetes probes.

This commit adds a `require_authentication` parameter to the @webmethod
decorator (defaults to True). Endpoints can opt out of authentication by
setting `require_authentication=False`. The /health and /version endpoints
now use this parameter to allow unauthenticated access.

Changes:
- Add `require_authentication` field to WebMethod dataclass
- Update @webmethod decorator to accept `require_authentication` parameter
- Mark /health and /version endpoints with `require_authentication=False`
- Update middleware to check webmethod.require_authentication dynamically

Closes: #3735

Signed-off-by: Derek Higgins <derekh@redhat.com>
This commit is contained in:
Derek Higgins 2025-10-08 17:52:19 +01:00
parent 96886afaca
commit c9dfd26385
5 changed files with 116 additions and 36 deletions

View file

@ -61,6 +61,7 @@ class WebMethod:
descriptive_name: str | None = None
required_scope: str | None = None
deprecated: bool | None = False
require_authentication: bool | None = True
CallableT = TypeVar("CallableT", bound=Callable[..., Any])
@ -77,6 +78,7 @@ def webmethod(
descriptive_name: str | None = None,
required_scope: str | None = None,
deprecated: bool | None = False,
require_authentication: bool | None = True,
) -> Callable[[CallableT], CallableT]:
"""
Decorator that supplies additional metadata to an endpoint operation function.
@ -86,6 +88,7 @@ def webmethod(
:param request_examples: Sample requests that the operation might take. Pass a list of objects, not JSON.
:param response_examples: Sample responses that the operation might produce. Pass a list of objects, not JSON.
:param required_scope: Required scope for this endpoint (e.g., 'monitoring.viewer').
:param require_authentication: Whether this endpoint requires authentication (default True).
"""
def wrap(func: CallableT) -> CallableT:
@ -100,6 +103,7 @@ def webmethod(
descriptive_name=descriptive_name,
required_scope=required_scope,
deprecated=deprecated,
require_authentication=require_authentication if require_authentication is not None else True,
)
# Store all webmethods in a list to support multiple decorators