1use std::sync::{Arc, LazyLock};
16
17use common_base::secrets::SecretString;
18use digest::Digest;
19use hmac::{Hmac, Mac};
20use pbkdf2::pbkdf2_hmac;
21use sha1::Sha1;
22use sha2::Sha256;
23use snafu::{OptionExt, ensure};
24use subtle::ConstantTimeEq;
25
26use crate::error::{IllegalParamSnafu, InvalidConfigSnafu, Result, UserPasswordMismatchSnafu};
27use crate::user_info::DefaultUserInfo;
28use crate::user_provider::static_user_provider::{STATIC_USER_PROVIDER, StaticUserProvider};
29use crate::user_provider::watch_file_user_provider::{
30 WATCH_FILE_USER_PROVIDER, WatchFileUserProvider,
31};
32use crate::{UserInfoRef, UserProviderRef};
33
34pub(crate) const DEFAULT_USERNAME: &str = "greptime";
35pub const DEFAULT_PBKDF2_SHA256_ITERATIONS: u32 = 4096;
36pub const DEFAULT_PBKDF2_SHA256_SALT_LEN: usize = 16;
37pub const PBKDF2_SHA256_HASH_LEN: usize = 32;
38pub const MAX_PBKDF2_SHA256_ITERATIONS: u32 = 1_000_000;
39pub const MAX_PBKDF2_SHA256_SALT_LEN: usize = 1024;
40pub const PG_SCRAM_SHA256_KEY_LEN: usize = 32;
41
42type HmacSha256 = Hmac<Sha256>;
43
44static PG_SCRAM_MOCK_SECRET: LazyLock<[u8; PG_SCRAM_SHA256_KEY_LEN]> = LazyLock::new(rand::random);
47
48pub fn userinfo_by_name(username: Option<String>) -> UserInfoRef {
51 DefaultUserInfo::with_name(username.unwrap_or_else(|| DEFAULT_USERNAME.to_string()))
52}
53
54pub fn user_provider_from_option(opt: &str) -> Result<UserProviderRef> {
55 let (name, content) = opt.split_once(':').with_context(|| InvalidConfigSnafu {
56 value: opt.to_string(),
57 msg: "UserProviderOption must be in format `<option>:<value>`",
58 })?;
59 match name {
60 STATIC_USER_PROVIDER => {
61 let provider =
62 StaticUserProvider::new(content).map(|p| Arc::new(p) as UserProviderRef)?;
63 Ok(provider)
64 }
65 WATCH_FILE_USER_PROVIDER => {
66 WatchFileUserProvider::new(content).map(|p| Arc::new(p) as UserProviderRef)
67 }
68 _ => InvalidConfigSnafu {
69 value: name.to_string(),
70 msg: "Invalid UserProviderOption",
71 }
72 .fail(),
73 }
74}
75
76pub fn static_user_provider_from_option(opt: &str) -> Result<StaticUserProvider> {
77 let (name, content) = opt.split_once(':').with_context(|| InvalidConfigSnafu {
78 value: opt.to_string(),
79 msg: "UserProviderOption must be in format `<option>:<value>`",
80 })?;
81 match name {
82 STATIC_USER_PROVIDER => {
83 let provider = StaticUserProvider::new(content)?;
84 Ok(provider)
85 }
86 _ => InvalidConfigSnafu {
87 value: name.to_string(),
88 msg: format!("Invalid UserProviderOption, expect only {STATIC_USER_PROVIDER}"),
89 }
90 .fail(),
91 }
92}
93
94type Username<'a> = &'a str;
95type HostOrIp<'a> = &'a str;
96
97#[derive(Debug, Clone)]
98pub enum Identity<'a> {
99 UserId(Username<'a>, Option<HostOrIp<'a>>),
100}
101
102pub type HashedPassword<'a> = &'a [u8];
103pub type Salt<'a> = &'a [u8];
104
105pub enum Password<'a> {
107 PlainText(SecretString),
108 MysqlNativePassword(HashedPassword<'a>, Salt<'a>),
109 PgMD5(HashedPassword<'a>, Salt<'a>),
110}
111
112impl Password<'_> {
113 pub fn r#type(&self) -> &str {
114 match self {
115 Password::PlainText(_) => "plain_text",
116 Password::MysqlNativePassword(_, _) => "mysql_native_password",
117 Password::PgMD5(_, _) => "pg_md5",
118 }
119 }
120}
121
122pub fn auth_mysql(
123 auth_data: HashedPassword,
124 salt: Salt,
125 username: &str,
126 save_pwd: &[u8],
127) -> Result<()> {
128 let hash_stage_2 = mysql_native_password_hash(save_pwd);
129 auth_mysql_with_hash_stage_2(auth_data, salt, username, &hash_stage_2)
130}
131
132pub(crate) fn auth_mysql_with_hash_stage_2(
133 auth_data: HashedPassword,
134 salt: Salt,
135 username: &str,
136 hash_stage_2: &[u8],
137) -> Result<()> {
138 ensure!(
139 auth_data.len() == 20,
140 IllegalParamSnafu {
141 msg: "Illegal mysql password length"
142 }
143 );
144 ensure!(
145 hash_stage_2.len() == 20,
146 InvalidConfigSnafu {
147 value: hash_stage_2.len().to_string(),
148 msg: "Illegal mysql native password verifier length",
149 }
150 );
151 let tmp = sha1_two(salt, hash_stage_2);
153 let mut xor_result = [0u8; 20];
155 for i in 0..20 {
156 xor_result[i] = auth_data[i] ^ tmp[i];
157 }
158 let candidate_stage_2 = sha1_one(&xor_result);
159 if candidate_stage_2 == hash_stage_2 {
160 Ok(())
161 } else {
162 UserPasswordMismatchSnafu {
163 username: username.to_string(),
164 }
165 .fail()
166 }
167}
168
169pub fn mysql_native_password_hash(save_pwd: &[u8]) -> Vec<u8> {
170 double_sha1(save_pwd)
171}
172
173pub fn format_mysql_native_password_verifier(password: &[u8]) -> String {
174 format!(
175 "mysql_native_password:{}",
176 hex::encode(mysql_native_password_hash(password))
177 )
178}
179
180pub fn format_pbkdf2_sha256_password_verifier(
181 password: &[u8],
182 salt: &[u8],
183 iterations: u32,
184) -> Result<String> {
185 ensure!(
186 iterations > 0 && iterations <= MAX_PBKDF2_SHA256_ITERATIONS,
187 IllegalParamSnafu {
188 msg: format!(
189 "pbkdf2_sha256 iterations must be in 1..={}",
190 MAX_PBKDF2_SHA256_ITERATIONS
191 )
192 }
193 );
194 ensure!(
195 !salt.is_empty() && salt.len() <= MAX_PBKDF2_SHA256_SALT_LEN,
196 IllegalParamSnafu {
197 msg: format!(
198 "pbkdf2_sha256 salt length must be in 1..={}",
199 MAX_PBKDF2_SHA256_SALT_LEN
200 )
201 }
202 );
203
204 let mut hash = [0u8; PBKDF2_SHA256_HASH_LEN];
205 pbkdf2_hmac::<Sha256>(password, salt, iterations, &mut hash);
206 Ok(format!(
207 "pbkdf2_sha256:{iterations}:{}:{}",
208 hex::encode(salt),
209 hex::encode(hash)
210 ))
211}
212
213#[derive(Clone, PartialEq, Eq)]
214pub struct PgScramSha256Verifier {
215 iterations: u32,
216 salt: Vec<u8>,
217 stored_key: Vec<u8>,
218 server_key: Vec<u8>,
219}
220
221impl std::fmt::Debug for PgScramSha256Verifier {
222 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
223 f.debug_struct("PgScramSha256Verifier")
224 .field("iterations", &self.iterations)
225 .field("salt", &"<REDACTED>")
226 .field("stored_key", &"<REDACTED>")
227 .field("server_key", &"<REDACTED>")
228 .finish()
229 }
230}
231
232impl PgScramSha256Verifier {
233 pub fn new(
234 iterations: u32,
235 salt: Vec<u8>,
236 stored_key: Vec<u8>,
237 server_key: Vec<u8>,
238 ) -> Result<Self> {
239 ensure!(
240 iterations > 0 && iterations <= MAX_PBKDF2_SHA256_ITERATIONS,
241 IllegalParamSnafu {
242 msg: format!(
243 "pg_scram_sha256 iterations must be in 1..={}",
244 MAX_PBKDF2_SHA256_ITERATIONS
245 )
246 }
247 );
248 ensure!(
249 !salt.is_empty() && salt.len() <= MAX_PBKDF2_SHA256_SALT_LEN,
250 IllegalParamSnafu {
251 msg: format!(
252 "pg_scram_sha256 salt length must be in 1..={}",
253 MAX_PBKDF2_SHA256_SALT_LEN
254 )
255 }
256 );
257 ensure!(
258 stored_key.len() == PG_SCRAM_SHA256_KEY_LEN,
259 IllegalParamSnafu {
260 msg: "pg_scram_sha256 stored key must be 32 bytes"
261 }
262 );
263 ensure!(
264 server_key.len() == PG_SCRAM_SHA256_KEY_LEN,
265 IllegalParamSnafu {
266 msg: "pg_scram_sha256 server key must be 32 bytes"
267 }
268 );
269
270 Ok(Self {
271 iterations,
272 salt,
273 stored_key,
274 server_key,
275 })
276 }
277
278 pub fn from_password(password: &[u8], salt: &[u8], iterations: u32) -> Result<Self> {
279 let salted_password = pg_scram_sha256_salted_password(password, salt, iterations)?;
280 Self::from_salted_password(salted_password, salt.to_vec(), iterations)
281 }
282
283 pub fn from_salted_password(
284 salted_password: Vec<u8>,
285 salt: Vec<u8>,
286 iterations: u32,
287 ) -> Result<Self> {
288 ensure!(
289 salted_password.len() == PG_SCRAM_SHA256_KEY_LEN,
290 IllegalParamSnafu {
291 msg: "pg_scram_sha256 salted password must be 32 bytes"
292 }
293 );
294 let client_key = hmac_sha256(&salted_password, b"Client Key");
295 let stored_key = sha256(&client_key);
296 let server_key = hmac_sha256(&salted_password, b"Server Key");
297 Self::new(iterations, salt, stored_key, server_key)
298 }
299
300 pub fn mock_for_unknown_user(username: &[u8]) -> Self {
307 let mock_salt = hmac_sha256(PG_SCRAM_MOCK_SECRET.as_slice(), username);
308 Self {
309 iterations: DEFAULT_PBKDF2_SHA256_ITERATIONS,
310 salt: mock_salt[..DEFAULT_PBKDF2_SHA256_SALT_LEN].to_vec(),
311 stored_key: rand::random::<[u8; PG_SCRAM_SHA256_KEY_LEN]>().to_vec(),
312 server_key: rand::random::<[u8; PG_SCRAM_SHA256_KEY_LEN]>().to_vec(),
313 }
314 }
315
316 pub fn iterations(&self) -> u32 {
317 self.iterations
318 }
319
320 pub fn salt(&self) -> &[u8] {
321 &self.salt
322 }
323
324 pub fn verify_plain_password(&self, password: &[u8]) -> Result<bool> {
325 let salted_password =
326 pg_scram_sha256_salted_password(password, &self.salt, self.iterations)?;
327 let client_key = hmac_sha256(&salted_password, b"Client Key");
328 let stored_key = sha256(&client_key);
329 Ok(self.stored_key.ct_eq(&stored_key).into())
330 }
331
332 pub fn verify_client_proof(
333 &self,
334 auth_message: &[u8],
335 client_proof: &[u8],
336 ) -> Result<Option<Vec<u8>>> {
337 if client_proof.len() != PG_SCRAM_SHA256_KEY_LEN {
338 return Ok(None);
339 }
340
341 let client_signature = hmac_sha256(&self.stored_key, auth_message);
342 let client_key = xor(client_proof, &client_signature);
343 let stored_key = sha256(&client_key);
344 if self.stored_key.ct_eq(&stored_key).into() {
345 Ok(Some(hmac_sha256(&self.server_key, auth_message)))
346 } else {
347 Ok(None)
348 }
349 }
350}
351
352pub fn format_pg_scram_sha256_password_verifier(
353 password: &[u8],
354 salt: &[u8],
355 iterations: u32,
356) -> Result<String> {
357 let verifier = PgScramSha256Verifier::from_password(password, salt, iterations)?;
358 Ok(format!(
359 "pg_scram_sha256:{iterations}:{}:{}:{}",
360 hex::encode(verifier.salt),
361 hex::encode(verifier.stored_key),
362 hex::encode(verifier.server_key)
363 ))
364}
365
366fn pg_scram_sha256_salted_password(
367 password: &[u8],
368 salt: &[u8],
369 iterations: u32,
370) -> Result<Vec<u8>> {
371 ensure!(
372 iterations > 0 && iterations <= MAX_PBKDF2_SHA256_ITERATIONS,
373 IllegalParamSnafu {
374 msg: format!(
375 "pg_scram_sha256 iterations must be in 1..={}",
376 MAX_PBKDF2_SHA256_ITERATIONS
377 )
378 }
379 );
380 ensure!(
381 !salt.is_empty() && salt.len() <= MAX_PBKDF2_SHA256_SALT_LEN,
382 IllegalParamSnafu {
383 msg: format!(
384 "pg_scram_sha256 salt length must be in 1..={}",
385 MAX_PBKDF2_SHA256_SALT_LEN
386 )
387 }
388 );
389
390 let prepared_password = std::str::from_utf8(password)
391 .ok()
392 .and_then(|password| stringprep::saslprep(password).ok());
393 let password = prepared_password
394 .as_deref()
395 .map(str::as_bytes)
396 .unwrap_or(password);
397
398 let mut salted_password = [0u8; PG_SCRAM_SHA256_KEY_LEN];
399 pbkdf2_hmac::<Sha256>(password, salt, iterations, &mut salted_password);
400 Ok(salted_password.to_vec())
401}
402
403fn hmac_sha256(key: &[u8], msg: &[u8]) -> Vec<u8> {
404 let mut mac = HmacSha256::new_from_slice(key).expect("HMAC accepts any key length");
405 mac.update(msg);
406 mac.finalize().into_bytes().to_vec()
407}
408
409fn sha256(data: &[u8]) -> Vec<u8> {
410 let mut hasher = Sha256::new();
411 hasher.update(data);
412 hasher.finalize().to_vec()
413}
414
415fn xor(lhs: &[u8], rhs: &[u8]) -> Vec<u8> {
416 lhs.iter().zip(rhs).map(|(l, r)| l ^ r).collect()
417}
418
419fn sha1_two(input_1: &[u8], input_2: &[u8]) -> Vec<u8> {
420 let mut hasher = Sha1::new();
421 hasher.update(input_1);
422 hasher.update(input_2);
423 hasher.finalize().to_vec()
424}
425
426fn sha1_one(data: &[u8]) -> Vec<u8> {
427 let mut hasher = Sha1::new();
428 hasher.update(data);
429 hasher.finalize().to_vec()
430}
431
432fn double_sha1(data: &[u8]) -> Vec<u8> {
433 sha1_one(&sha1_one(data))
434}
435
436#[cfg(test)]
437mod tests {
438 use super::*;
439
440 #[test]
441 fn test_sha() {
442 let sha_1_answer: Vec<u8> = vec![
443 124, 74, 141, 9, 202, 55, 98, 175, 97, 229, 149, 32, 148, 61, 194, 100, 148, 248, 148,
444 27,
445 ];
446 let sha_1 = sha1_one("123456".as_bytes());
447 assert_eq!(sha_1, sha_1_answer);
448
449 let double_sha1_answer: Vec<u8> = vec![
450 107, 180, 131, 126, 183, 67, 41, 16, 94, 228, 86, 141, 218, 125, 198, 126, 210, 202,
451 42, 217,
452 ];
453 let double_sha1 = double_sha1("123456".as_bytes());
454 assert_eq!(double_sha1, double_sha1_answer);
455
456 let sha1_2_answer: Vec<u8> = vec![
457 132, 115, 215, 211, 99, 186, 164, 206, 168, 152, 217, 192, 117, 47, 240, 252, 142, 244,
458 37, 204,
459 ];
460 let sha1_2 = sha1_two("123456".as_bytes(), "654321".as_bytes());
461 assert_eq!(sha1_2, sha1_2_answer);
462 }
463
464 #[test]
465 fn test_format_mysql_native_password_verifier() {
466 let verifier = format_mysql_native_password_verifier("123456".as_bytes());
467 assert_eq!(
468 "mysql_native_password:6bb4837eb74329105ee4568dda7dc67ed2ca2ad9",
469 verifier
470 );
471 }
472
473 #[test]
474 fn test_format_pbkdf2_sha256_password_verifier() {
475 let verifier =
476 format_pbkdf2_sha256_password_verifier("password".as_bytes(), b"salt", 4096).unwrap();
477 assert_eq!(
478 "pbkdf2_sha256:4096:73616c74:c5e478d59288c841aa530db6845c4c8d962893a001ce4e11a4963873aa98134a",
479 verifier
480 );
481
482 assert!(format_pbkdf2_sha256_password_verifier(b"password", b"", 4096).is_err());
483 assert!(format_pbkdf2_sha256_password_verifier(b"password", b"salt", 0).is_err());
484 assert!(
485 format_pbkdf2_sha256_password_verifier(
486 b"password",
487 b"salt",
488 MAX_PBKDF2_SHA256_ITERATIONS + 1,
489 )
490 .is_err()
491 );
492 }
493
494 #[test]
495 fn test_format_pg_scram_sha256_password_verifier() {
496 let verifier =
497 format_pg_scram_sha256_password_verifier("password".as_bytes(), b"salt", 4096).unwrap();
498 assert_eq!(
499 "pg_scram_sha256:4096:73616c74:945e1c466fc9932efadc23781edc5d1e78d5e10f005933652af1a6105154f084:b9bf0e811b1fb6793671c0cc3adedf7c75cd72291191092ad65878c5a02aad2c",
500 verifier
501 );
502 }
503
504 #[test]
505 fn test_pg_scram_sha256_applies_saslprep() {
506 let normalized = PgScramSha256Verifier::from_password(b"pass word", b"salt", 4096).unwrap();
507 let non_breaking_space =
508 PgScramSha256Verifier::from_password("pass\u{00a0}word".as_bytes(), b"salt", 4096)
509 .unwrap();
510
511 assert_eq!(normalized, non_breaking_space);
512 assert!(
513 non_breaking_space
514 .verify_plain_password(b"pass word")
515 .unwrap()
516 );
517 }
518
519 #[test]
520 fn test_pg_scram_sha256_uses_original_bytes_when_saslprep_is_not_possible() {
521 let invalid_utf8 = b"password\xff";
522 let prohibited = b"password\x07";
523
524 for password in [invalid_utf8.as_slice(), prohibited.as_slice()] {
525 let verifier = PgScramSha256Verifier::from_password(password, b"salt", 4096).unwrap();
526 assert!(verifier.verify_plain_password(password).unwrap());
527 }
528 }
529
530 #[test]
531 fn test_mock_verifier_is_stable_per_username() {
532 let alice = PgScramSha256Verifier::mock_for_unknown_user(b"alice");
533 let alice_again = PgScramSha256Verifier::mock_for_unknown_user(b"alice");
534 let bob = PgScramSha256Verifier::mock_for_unknown_user(b"bob");
535
536 assert_eq!(alice.salt(), alice_again.salt());
539 assert_ne!(alice.salt(), bob.salt());
540 assert_eq!(alice.iterations(), DEFAULT_PBKDF2_SHA256_ITERATIONS);
541 assert_eq!(alice.salt().len(), DEFAULT_PBKDF2_SHA256_SALT_LEN);
542
543 assert!(
545 alice
546 .verify_client_proof(b"auth-message", &[0u8; PG_SCRAM_SHA256_KEY_LEN])
547 .unwrap()
548 .is_none()
549 );
550 }
551}