Line data Source code
1 : use super::{
2 : ComputeCredentialKeys, ComputeCredentials, ComputeUserInfo, ComputeUserInfoNoEndpoint,
3 : };
4 : use crate::{
5 : auth::{self, AuthFlow},
6 : console::AuthSecret,
7 : metrics::LatencyTimer,
8 : sasl,
9 : stream::{self, Stream},
10 : };
11 : use tokio::io::{AsyncRead, AsyncWrite};
12 : use tracing::{info, warn};
13 :
14 : /// Compared to [SCRAM](crate::scram), cleartext password auth saves
15 : /// one round trip and *expensive* computations (>= 4096 HMAC iterations).
16 : /// These properties are benefical for serverless JS workers, so we
17 : /// use this mechanism for websocket connections.
18 0 : pub async fn authenticate_cleartext(
19 0 : info: ComputeUserInfo,
20 0 : client: &mut stream::PqStream<Stream<impl AsyncRead + AsyncWrite + Unpin>>,
21 0 : latency_timer: &mut LatencyTimer,
22 0 : secret: AuthSecret,
23 0 : ) -> auth::Result<ComputeCredentials<ComputeCredentialKeys>> {
24 0 : warn!("cleartext auth flow override is enabled, proceeding");
25 :
26 : // pause the timer while we communicate with the client
27 0 : let _paused = latency_timer.pause();
28 :
29 0 : let auth_outcome = AuthFlow::new(client)
30 0 : .begin(auth::CleartextPassword(secret))
31 0 : .await?
32 0 : .authenticate()
33 0 : .await?;
34 :
35 0 : let keys = match auth_outcome {
36 0 : sasl::Outcome::Success(key) => key,
37 0 : sasl::Outcome::Failure(reason) => {
38 0 : info!("auth backend failed with an error: {reason}");
39 0 : return Err(auth::AuthError::auth_failed(&*info.user));
40 : }
41 : };
42 :
43 0 : Ok(ComputeCredentials { info, keys })
44 0 : }
45 :
46 : /// Workaround for clients which don't provide an endpoint (project) name.
47 : /// Similar to [`authenticate_cleartext`], but there's a specific password format,
48 : /// and passwords are not yet validated (we don't know how to validate them!)
49 3 : pub async fn password_hack_no_authentication(
50 3 : info: ComputeUserInfoNoEndpoint,
51 3 : client: &mut stream::PqStream<Stream<impl AsyncRead + AsyncWrite + Unpin>>,
52 3 : latency_timer: &mut LatencyTimer,
53 3 : ) -> auth::Result<ComputeCredentials<Vec<u8>>> {
54 3 : warn!("project not specified, resorting to the password hack auth flow");
55 :
56 : // pause the timer while we communicate with the client
57 3 : let _paused = latency_timer.pause();
58 :
59 3 : let payload = AuthFlow::new(client)
60 3 : .begin(auth::PasswordHack)
61 0 : .await?
62 3 : .get_password()
63 3 : .await?;
64 :
65 2 : info!(project = &*payload.endpoint, "received missing parameter");
66 :
67 : // Report tentative success; compute node will check the password anyway.
68 2 : Ok(ComputeCredentials {
69 2 : info: ComputeUserInfo {
70 2 : user: info.user,
71 2 : options: info.options,
72 2 : endpoint: payload.endpoint,
73 2 : },
74 2 : keys: payload.password,
75 2 : })
76 3 : }
|