manta_server/service/
auth.rs

1//! Authentication service — proxies CLI credential exchange to the
2//! configured CSM/OCHAMI backend.
3//!
4//! The CLI never talks to Keycloak directly; it POSTs username+password
5//! to `manta-server /api/v1/auth/token`, which calls
6//! `backend.get_api_token` on the user's behalf and returns the CSM
7//! bearer token. `validate_api_token` mirrors the CLI's pre-Phase-6
8//! token-still-valid check.
9
10use std::time::Instant;
11
12use manta_backend_dispatcher::{
13  error::Error, interfaces::authentication::AuthenticationTrait,
14};
15
16use crate::server::common::app_context::InfraContext;
17
18/// Exchange `username` + `password` for a CSM bearer token via the
19/// site's configured backend.
20#[tracing::instrument(
21  skip_all,
22  fields(
23    site = %infra.site_name,
24    backend = %infra.backend.backend_kind(),
25    backend_url = %infra.shasta_base_url,
26  )
27)]
28pub async fn get_api_token(
29  infra: &InfraContext<'_>,
30  username: &str,
31  password: &str,
32) -> Result<String, Error> {
33  tracing::info!(user = %username, "backend: requesting token");
34  let started = Instant::now();
35  let result = infra.backend.get_api_token(username, password).await;
36  let elapsed_ms = started.elapsed().as_millis() as u64;
37  match &result {
38    Ok(_) => tracing::debug!(
39      user = %username,
40      elapsed_ms,
41      "backend: token issued"
42    ),
43    Err(e) => tracing::warn!(
44      user = %username,
45      elapsed_ms,
46      error = %e,
47      "backend: token request rejected"
48    ),
49  }
50  result
51}
52
53/// Verify that `token` is still accepted by the site's backend.
54#[tracing::instrument(
55  skip_all,
56  fields(
57    site = %infra.site_name,
58    backend = %infra.backend.backend_kind(),
59    backend_url = %infra.shasta_base_url,
60  )
61)]
62pub async fn validate_api_token(
63  infra: &InfraContext<'_>,
64  token: &str,
65) -> Result<(), Error> {
66  tracing::info!("backend: validating token");
67  let started = Instant::now();
68  let result = infra.backend.validate_api_token(token).await;
69  let elapsed_ms = started.elapsed().as_millis() as u64;
70  match &result {
71    Ok(()) => tracing::debug!(elapsed_ms, "backend: token accepted"),
72    Err(e) => tracing::warn!(
73      elapsed_ms,
74      error = %e,
75      "backend: token validation rejected"
76    ),
77  }
78  result
79}