Assemble the authenticator chain for the gateway. Chain order (first-match-wins): 1. `K8sServiceAccountAuthenticator` (path-scoped to `IssueSandboxToken`) — exchanges a projected SA token for a `Principal::Sandbox` so the `IssueSandboxToken` handler can mint a gateway JWT. No-op on every other path; only present when the gateway runs in-cluster. 2. `SandboxJwtAuthenticator` — validates gateway-mi
(state: &ServerState)
| 446 | /// dev gateway), the chain is left as `None` so the router short-circuits |
| 447 | /// to pass-through unless mTLS or local unauthenticated users are enabled. |
| 448 | fn build_authenticator_chain(state: &ServerState) -> Option<AuthenticatorChain> { |
| 449 | let mut authenticators: Vec<Arc<dyn crate::auth::authenticator::Authenticator>> = Vec::new(); |
| 450 | if let Some(k8s) = state.k8s_sa_authenticator.clone() { |
| 451 | authenticators.push(k8s); |
| 452 | } |
| 453 | if let Some(jwt) = state.sandbox_jwt_authenticator.clone() { |
| 454 | authenticators.push(jwt); |
| 455 | } |
| 456 | if let Some(cache) = state.oidc_cache.clone() { |
| 457 | authenticators.push(Arc::new(OidcAuthenticator::new(cache))); |
| 458 | } |
| 459 | if authenticators.is_empty() { |
| 460 | return None; |
| 461 | } |
| 462 | Some(AuthenticatorChain::new(authenticators)) |
| 463 | } |
| 464 | |
| 465 | /// gRPC router wrapper that runs the [`AuthenticatorChain`] and inserts the |
| 466 | /// resulting [`Principal`] into the request's extensions. |
no test coverage detected