Skip to content

Commit 48ee1a6

Browse files
committed
sasl/scram
1 parent 7d4f3d9 commit 48ee1a6

File tree

32 files changed

+1172
-51
lines changed

32 files changed

+1172
-51
lines changed

Cargo.lock

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/adapter/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ anyhow = "1.0.98"
1414
arrow = { version = "55.2.0", default-features = false }
1515
async-stream = "0.3.6"
1616
async-trait = "0.1.88"
17+
base64 = "0.22.1"
1718
bytes = "1.10.1"
1819
bytesize = "1.3.0"
1920
chrono = { version = "0.4.39", default-features = false, features = ["std"] }

src/adapter/src/catalog/open.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ impl Catalog {
154154
source_references: BTreeMap::new(),
155155
storage_metadata: Default::default(),
156156
temporary_schemas: BTreeMap::new(),
157+
mock_authentication_nonce: Default::default(),
157158
config: mz_sql::catalog::CatalogConfig {
158159
start_time: to_datetime((config.now)()),
159160
start_instant: Instant::now(),
@@ -406,6 +407,13 @@ impl Catalog {
406407
.unwrap_or("new")
407408
.to_string();
408409

410+
let mz_authentication_mock_nonce =
411+
txn.get_authentication_mock_nonce().ok_or_else(|| {
412+
Error::new(ErrorKind::SettingError("authentication nonce".to_string()))
413+
})?;
414+
415+
state.mock_authentication_nonce = Some(mz_authentication_mock_nonce);
416+
409417
// Migrate item ASTs.
410418
let builtin_table_update = if !config.skip_migrations {
411419
let migrate_result = migrate::migrate(

src/adapter/src/catalog/state.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ pub struct CatalogState {
142142
#[serde(serialize_with = "mz_ore::serde::map_key_to_string")]
143143
pub(super) source_references: BTreeMap<CatalogItemId, SourceReferences>,
144144
pub(super) storage_metadata: StorageMetadata,
145+
pub(super) mock_authentication_nonce: Option<String>,
145146

146147
// Mutable state not derived from the durable catalog.
147148
#[serde(skip)]
@@ -316,6 +317,7 @@ impl CatalogState {
316317
source_references: Default::default(),
317318
storage_metadata: Default::default(),
318319
license_key: ValidatedLicenseKey::for_tests(),
320+
mock_authentication_nonce: Default::default(),
319321
}
320322
}
321323

@@ -2614,6 +2616,10 @@ impl CatalogState {
26142616
CommentObjectId::NetworkPolicy(id) => self.get_network_policy(&id).name.clone(),
26152617
}
26162618
}
2619+
2620+
pub fn mock_authentication_nonce(&self) -> String {
2621+
self.mock_authentication_nonce.clone().unwrap_or_default()
2622+
}
26172623
}
26182624

26192625
impl ConnectionResolver for CatalogState {

src/adapter/src/client.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ use uuid::Uuid;
5050
use crate::catalog::Catalog;
5151
use crate::command::{
5252
AuthResponse, CatalogDump, CatalogSnapshot, Command, ExecuteResponse, Response,
53+
SASLChallengeResponse, SASLVerifyProofResponse,
5354
};
5455
use crate::coord::{Coordinator, ExecuteContextExtra};
5556
use crate::error::AdapterError;
@@ -167,6 +168,40 @@ impl Client {
167168
Ok(response)
168169
}
169170

171+
pub async fn generate_sasl_challenge(
172+
&self,
173+
user: &String,
174+
client_nonce: &String,
175+
) -> Result<SASLChallengeResponse, AdapterError> {
176+
let (tx, rx) = oneshot::channel();
177+
self.send(Command::AuthenticateGetSASLChallenge {
178+
role_name: user.to_string(),
179+
nonce: client_nonce.to_string(),
180+
tx,
181+
});
182+
let response = rx.await.expect("sender dropped")?;
183+
Ok(response)
184+
}
185+
186+
pub async fn verify_sasl_proof(
187+
&self,
188+
user: &String,
189+
proof: &String,
190+
nonce: &String,
191+
mock_hash: &String,
192+
) -> Result<SASLVerifyProofResponse, AdapterError> {
193+
let (tx, rx) = oneshot::channel();
194+
self.send(Command::AuthenticateVerifySASLProof {
195+
role_name: user.to_string(),
196+
proof: proof.to_string(),
197+
auth_message: nonce.to_string(),
198+
mock_hash: mock_hash.to_string(),
199+
tx,
200+
});
201+
let response = rx.await.expect("sender dropped")?;
202+
Ok(response)
203+
}
204+
170205
/// Upgrades this client to a session client.
171206
///
172207
/// A session is a connection that has successfully negotiated parameters,
@@ -908,6 +943,8 @@ impl SessionClient {
908943
Command::GetWebhook { .. } => typ = Some("webhook"),
909944
Command::Startup { .. }
910945
| Command::AuthenticatePassword { .. }
946+
| Command::AuthenticateGetSASLChallenge { .. }
947+
| Command::AuthenticateVerifySASLProof { .. }
911948
| Command::CatalogSnapshot { .. }
912949
| Command::Commit { .. }
913950
| Command::CancelRequest { .. }

src/adapter/src/command.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,20 @@ pub enum Command {
7373
password: Option<Password>,
7474
},
7575

76+
AuthenticateGetSASLChallenge {
77+
tx: oneshot::Sender<Result<SASLChallengeResponse, AdapterError>>,
78+
role_name: String,
79+
nonce: String,
80+
},
81+
82+
AuthenticateVerifySASLProof {
83+
tx: oneshot::Sender<Result<SASLVerifyProofResponse, AdapterError>>,
84+
role_name: String,
85+
proof: String,
86+
auth_message: String,
87+
mock_hash: String,
88+
},
89+
7690
Execute {
7791
portal_name: String,
7892
session: Session,
@@ -148,6 +162,8 @@ impl Command {
148162
Command::CancelRequest { .. }
149163
| Command::Startup { .. }
150164
| Command::AuthenticatePassword { .. }
165+
| Command::AuthenticateGetSASLChallenge { .. }
166+
| Command::AuthenticateVerifySASLProof { .. }
151167
| Command::CatalogSnapshot { .. }
152168
| Command::PrivilegedCancelRequest { .. }
153169
| Command::GetWebhook { .. }
@@ -166,6 +182,8 @@ impl Command {
166182
Command::CancelRequest { .. }
167183
| Command::Startup { .. }
168184
| Command::AuthenticatePassword { .. }
185+
| Command::AuthenticateGetSASLChallenge { .. }
186+
| Command::AuthenticateVerifySASLProof { .. }
169187
| Command::CatalogSnapshot { .. }
170188
| Command::PrivilegedCancelRequest { .. }
171189
| Command::GetWebhook { .. }
@@ -210,6 +228,22 @@ pub struct AuthResponse {
210228
pub superuser: bool,
211229
}
212230

231+
#[derive(Derivative)]
232+
#[derivative(Debug)]
233+
pub struct SASLChallengeResponse {
234+
pub iteration_count: usize,
235+
/// Base64-encoded salt for the SASL challenge.
236+
pub salt: String,
237+
pub nonce: String,
238+
}
239+
240+
#[derive(Derivative)]
241+
#[derivative(Debug)]
242+
pub struct SASLVerifyProofResponse {
243+
pub verifier: String,
244+
pub auth_resp: AuthResponse,
245+
}
246+
213247
// Facile implementation for `StartupResponse`, which does not use the `allowed`
214248
// feature of `ClientTransmitter`.
215249
impl Transmittable for StartupResponse {

src/adapter/src/coord.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,8 @@ impl Message {
356356
Command::CheckConsistency { .. } => "command-check_consistency",
357357
Command::Dump { .. } => "command-dump",
358358
Command::AuthenticatePassword { .. } => "command-auth_check",
359+
Command::AuthenticateGetSASLChallenge { .. } => "command-auth_get_sasl_challenge",
360+
Command::AuthenticateVerifySASLProof { .. } => "command-auth_verify_sasl_proof",
359361
},
360362
Message::ControllerReady {
361363
controller: ControllerReadiness::Compute,

0 commit comments

Comments
 (0)