LCOV - code coverage report
Current view: top level - proxy/src/auth/backend - hacks.rs (source / functions) Coverage Total Hit
Test: a14d6a1f0ccf210374e9eaed9918e97cd6f5d5ba.info Lines: 94.0 % 50 47
Test Date: 2025-08-04 14:37:31 Functions: 33.3 % 12 4

            Line data    Source code
       1              : use tokio::io::{AsyncRead, AsyncWrite};
       2              : use tracing::{debug, info};
       3              : 
       4              : use super::{ComputeCredentials, ComputeUserInfo, ComputeUserInfoNoEndpoint};
       5              : use crate::auth::{self, AuthFlow};
       6              : use crate::config::AuthenticationConfig;
       7              : use crate::context::RequestContext;
       8              : use crate::control_plane::AuthSecret;
       9              : use crate::intern::{EndpointIdInt, RoleNameInt};
      10              : use crate::sasl;
      11              : use crate::stream::{self, Stream};
      12              : 
      13              : /// Compared to [SCRAM](crate::scram), cleartext password auth saves
      14              : /// one round trip and *expensive* computations (>= 4096 HMAC iterations).
      15              : /// These properties are benefical for serverless JS workers, so we
      16              : /// use this mechanism for websocket connections.
      17            1 : pub(crate) async fn authenticate_cleartext(
      18            1 :     ctx: &RequestContext,
      19            1 :     info: ComputeUserInfo,
      20            1 :     client: &mut stream::PqStream<Stream<impl AsyncRead + AsyncWrite + Unpin>>,
      21            1 :     secret: AuthSecret,
      22            1 :     config: &'static AuthenticationConfig,
      23            1 : ) -> auth::Result<ComputeCredentials> {
      24            1 :     debug!("cleartext auth flow override is enabled, proceeding");
      25            1 :     ctx.set_auth_method(crate::context::AuthMethod::Cleartext);
      26              : 
      27            1 :     let ep = EndpointIdInt::from(&info.endpoint);
      28            1 :     let role = RoleNameInt::from(&info.user);
      29              : 
      30            1 :     let auth_flow = AuthFlow::new(
      31            1 :         client,
      32            1 :         auth::CleartextPassword {
      33            1 :             secret,
      34            1 :             endpoint: ep,
      35            1 :             role,
      36            1 :             pool: config.scram_thread_pool.clone(),
      37            1 :         },
      38              :     );
      39            1 :     let auth_outcome = {
      40              :         // pause the timer while we communicate with the client
      41            1 :         let _paused = ctx.latency_timer_pause(crate::metrics::Waiting::Client);
      42              : 
      43              :         // cleartext auth is only allowed to the ws/http protocol.
      44              :         // If we're here, we already received the password in the first message.
      45              :         // Scram protocol will be executed on the proxy side.
      46            1 :         auth_flow.authenticate().await?
      47              :     };
      48              : 
      49            1 :     let keys = match auth_outcome {
      50            1 :         sasl::Outcome::Success(key) => key,
      51            0 :         sasl::Outcome::Failure(reason) => {
      52            0 :             info!("auth backend failed with an error: {reason}");
      53            0 :             return Err(auth::AuthError::password_failed(&*info.user));
      54              :         }
      55              :     };
      56              : 
      57            1 :     Ok(ComputeCredentials { info, keys })
      58            1 : }
      59              : 
      60              : /// Workaround for clients which don't provide an endpoint (project) name.
      61              : /// Similar to [`authenticate_cleartext`], but there's a specific password format,
      62              : /// and passwords are not yet validated (we don't know how to validate them!)
      63            1 : pub(crate) async fn password_hack_no_authentication(
      64            1 :     ctx: &RequestContext,
      65            1 :     info: ComputeUserInfoNoEndpoint,
      66            1 :     client: &mut stream::PqStream<Stream<impl AsyncRead + AsyncWrite + Unpin>>,
      67            1 : ) -> auth::Result<(ComputeUserInfo, Vec<u8>)> {
      68            1 :     debug!("project not specified, resorting to the password hack auth flow");
      69            1 :     ctx.set_auth_method(crate::context::AuthMethod::Cleartext);
      70              : 
      71              :     // pause the timer while we communicate with the client
      72            1 :     let _paused = ctx.latency_timer_pause(crate::metrics::Waiting::Client);
      73              : 
      74            1 :     let payload = AuthFlow::new(client, auth::PasswordHack)
      75            1 :         .get_password()
      76            1 :         .await?;
      77              : 
      78            1 :     debug!(project = &*payload.endpoint, "received missing parameter");
      79              : 
      80              :     // Report tentative success; compute node will check the password anyway.
      81            1 :     Ok((
      82            1 :         ComputeUserInfo {
      83            1 :             user: info.user,
      84            1 :             options: info.options,
      85            1 :             endpoint: payload.endpoint,
      86            1 :         },
      87            1 :         payload.password,
      88            1 :     ))
      89            1 : }
        

Generated by: LCOV version 2.1-beta