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 fn auth_mysql_with_verifier(
134 auth_data: HashedPassword,
135 salt: Salt,
136 username: &str,
137 verifier: &str,
138) -> Result<()> {
139 let hash_stage_2 = parse_mysql_native_password_verifier(verifier)?;
140 auth_mysql_with_hash_stage_2(auth_data, salt, username, &hash_stage_2)
141}
142
143pub fn validate_mysql_native_password_verifier(verifier: &str) -> Result<()> {
144 parse_mysql_native_password_verifier(verifier).map(|_| ())
145}
146
147pub(crate) fn parse_mysql_native_password_verifier(verifier: &str) -> Result<Vec<u8>> {
148 let Some(verifier) = verifier.strip_prefix("mysql_native_password:") else {
149 return InvalidConfigSnafu {
150 value: "mysql_native_password".to_string(),
151 msg: "Invalid mysql native password verifier format",
152 }
153 .fail();
154 };
155 let Ok(hash_stage_2) = hex::decode(verifier) else {
156 return InvalidConfigSnafu {
157 value: "mysql_native_password".to_string(),
158 msg: "Invalid mysql native password verifier encoding",
159 }
160 .fail();
161 };
162 ensure!(
163 hash_stage_2.len() == 20,
164 InvalidConfigSnafu {
165 value: "mysql_native_password".to_string(),
166 msg: "Illegal mysql native password verifier length",
167 }
168 );
169 Ok(hash_stage_2)
170}
171
172pub(crate) fn auth_mysql_with_hash_stage_2(
173 auth_data: HashedPassword,
174 salt: Salt,
175 username: &str,
176 hash_stage_2: &[u8],
177) -> Result<()> {
178 ensure!(
179 auth_data.len() == 20,
180 IllegalParamSnafu {
181 msg: "Illegal mysql password length"
182 }
183 );
184 ensure!(
185 hash_stage_2.len() == 20,
186 InvalidConfigSnafu {
187 value: hash_stage_2.len().to_string(),
188 msg: "Illegal mysql native password verifier length",
189 }
190 );
191 let tmp = sha1_two(salt, hash_stage_2);
193 let mut xor_result = [0u8; 20];
195 for i in 0..20 {
196 xor_result[i] = auth_data[i] ^ tmp[i];
197 }
198 let candidate_stage_2 = sha1_one(&xor_result);
199 if candidate_stage_2 == hash_stage_2 {
200 Ok(())
201 } else {
202 UserPasswordMismatchSnafu {
203 username: username.to_string(),
204 }
205 .fail()
206 }
207}
208
209pub fn mysql_native_password_hash(save_pwd: &[u8]) -> Vec<u8> {
210 double_sha1(save_pwd)
211}
212
213pub fn format_mysql_native_password_verifier(password: &[u8]) -> String {
214 format!(
215 "mysql_native_password:{}",
216 hex::encode(mysql_native_password_hash(password))
217 )
218}
219
220pub fn format_pbkdf2_sha256_password_verifier(
221 password: &[u8],
222 salt: &[u8],
223 iterations: u32,
224) -> Result<String> {
225 ensure!(
226 iterations > 0 && iterations <= MAX_PBKDF2_SHA256_ITERATIONS,
227 IllegalParamSnafu {
228 msg: format!(
229 "pbkdf2_sha256 iterations must be in 1..={}",
230 MAX_PBKDF2_SHA256_ITERATIONS
231 )
232 }
233 );
234 ensure!(
235 !salt.is_empty() && salt.len() <= MAX_PBKDF2_SHA256_SALT_LEN,
236 IllegalParamSnafu {
237 msg: format!(
238 "pbkdf2_sha256 salt length must be in 1..={}",
239 MAX_PBKDF2_SHA256_SALT_LEN
240 )
241 }
242 );
243
244 let mut hash = [0u8; PBKDF2_SHA256_HASH_LEN];
245 pbkdf2_hmac::<Sha256>(password, salt, iterations, &mut hash);
246 Ok(format!(
247 "pbkdf2_sha256:{iterations}:{}:{}",
248 hex::encode(salt),
249 hex::encode(hash)
250 ))
251}
252
253#[derive(Clone, PartialEq, Eq)]
254pub struct PgScramSha256Verifier {
255 iterations: u32,
256 salt: Vec<u8>,
257 stored_key: Vec<u8>,
258 server_key: Vec<u8>,
259}
260
261impl std::fmt::Debug for PgScramSha256Verifier {
262 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
263 f.debug_struct("PgScramSha256Verifier")
264 .field("iterations", &self.iterations)
265 .field("salt", &"<REDACTED>")
266 .field("stored_key", &"<REDACTED>")
267 .field("server_key", &"<REDACTED>")
268 .finish()
269 }
270}
271
272impl PgScramSha256Verifier {
273 pub fn new(
274 iterations: u32,
275 salt: Vec<u8>,
276 stored_key: Vec<u8>,
277 server_key: Vec<u8>,
278 ) -> Result<Self> {
279 ensure!(
280 iterations > 0 && iterations <= MAX_PBKDF2_SHA256_ITERATIONS,
281 IllegalParamSnafu {
282 msg: format!(
283 "pg_scram_sha256 iterations must be in 1..={}",
284 MAX_PBKDF2_SHA256_ITERATIONS
285 )
286 }
287 );
288 ensure!(
289 !salt.is_empty() && salt.len() <= MAX_PBKDF2_SHA256_SALT_LEN,
290 IllegalParamSnafu {
291 msg: format!(
292 "pg_scram_sha256 salt length must be in 1..={}",
293 MAX_PBKDF2_SHA256_SALT_LEN
294 )
295 }
296 );
297 ensure!(
298 stored_key.len() == PG_SCRAM_SHA256_KEY_LEN,
299 IllegalParamSnafu {
300 msg: "pg_scram_sha256 stored key must be 32 bytes"
301 }
302 );
303 ensure!(
304 server_key.len() == PG_SCRAM_SHA256_KEY_LEN,
305 IllegalParamSnafu {
306 msg: "pg_scram_sha256 server key must be 32 bytes"
307 }
308 );
309
310 Ok(Self {
311 iterations,
312 salt,
313 stored_key,
314 server_key,
315 })
316 }
317
318 pub fn from_password(password: &[u8], salt: &[u8], iterations: u32) -> Result<Self> {
319 let salted_password = pg_scram_sha256_salted_password(password, salt, iterations)?;
320 Self::from_salted_password(salted_password, salt.to_vec(), iterations)
321 }
322
323 pub fn from_salted_password(
324 salted_password: Vec<u8>,
325 salt: Vec<u8>,
326 iterations: u32,
327 ) -> Result<Self> {
328 ensure!(
329 salted_password.len() == PG_SCRAM_SHA256_KEY_LEN,
330 IllegalParamSnafu {
331 msg: "pg_scram_sha256 salted password must be 32 bytes"
332 }
333 );
334 let client_key = hmac_sha256(&salted_password, b"Client Key");
335 let stored_key = sha256(&client_key);
336 let server_key = hmac_sha256(&salted_password, b"Server Key");
337 Self::new(iterations, salt, stored_key, server_key)
338 }
339
340 pub fn mock_for_unknown_user(username: &[u8]) -> Self {
347 let mock_salt = hmac_sha256(PG_SCRAM_MOCK_SECRET.as_slice(), username);
348 Self {
349 iterations: DEFAULT_PBKDF2_SHA256_ITERATIONS,
350 salt: mock_salt[..DEFAULT_PBKDF2_SHA256_SALT_LEN].to_vec(),
351 stored_key: rand::random::<[u8; PG_SCRAM_SHA256_KEY_LEN]>().to_vec(),
352 server_key: rand::random::<[u8; PG_SCRAM_SHA256_KEY_LEN]>().to_vec(),
353 }
354 }
355
356 pub fn iterations(&self) -> u32 {
357 self.iterations
358 }
359
360 pub fn salt(&self) -> &[u8] {
361 &self.salt
362 }
363
364 pub fn stored_key(&self) -> &[u8] {
366 &self.stored_key
367 }
368
369 pub fn server_key(&self) -> &[u8] {
373 &self.server_key
374 }
375
376 pub fn verify_plain_password(&self, password: &[u8]) -> Result<bool> {
377 let salted_password =
378 pg_scram_sha256_salted_password(password, &self.salt, self.iterations)?;
379 let client_key = hmac_sha256(&salted_password, b"Client Key");
380 let stored_key = sha256(&client_key);
381 Ok(self.stored_key.ct_eq(&stored_key).into())
382 }
383
384 pub fn verify_client_proof(
385 &self,
386 auth_message: &[u8],
387 client_proof: &[u8],
388 ) -> Result<Option<Vec<u8>>> {
389 if client_proof.len() != PG_SCRAM_SHA256_KEY_LEN {
390 return Ok(None);
391 }
392
393 let client_signature = hmac_sha256(&self.stored_key, auth_message);
394 let client_key = xor(client_proof, &client_signature);
395 let stored_key = sha256(&client_key);
396 if self.stored_key.ct_eq(&stored_key).into() {
397 Ok(Some(hmac_sha256(&self.server_key, auth_message)))
398 } else {
399 Ok(None)
400 }
401 }
402}
403
404pub fn format_pg_scram_sha256_password_verifier(
405 password: &[u8],
406 salt: &[u8],
407 iterations: u32,
408) -> Result<String> {
409 let verifier = PgScramSha256Verifier::from_password(password, salt, iterations)?;
410 Ok(format!(
411 "pg_scram_sha256:{iterations}:{}:{}:{}",
412 hex::encode(verifier.salt),
413 hex::encode(verifier.stored_key),
414 hex::encode(verifier.server_key)
415 ))
416}
417
418pub fn parse_pg_scram_sha256_password_verifier(verifier: &str) -> Result<PgScramSha256Verifier> {
420 let Some(verifier) = verifier.strip_prefix("pg_scram_sha256:") else {
421 return InvalidConfigSnafu {
422 value: "pg_scram_sha256".to_string(),
423 msg: "Invalid pg scram sha256 verifier format",
424 }
425 .fail();
426 };
427 let mut parts = verifier.split(':');
428 let (Some(iterations), Some(salt), Some(stored_key), Some(server_key), None) = (
429 parts.next(),
430 parts.next(),
431 parts.next(),
432 parts.next(),
433 parts.next(),
434 ) else {
435 return InvalidConfigSnafu {
436 value: "pg_scram_sha256".to_string(),
437 msg: "Invalid pg scram sha256 verifier format",
438 }
439 .fail();
440 };
441 let (Ok(iterations), Ok(salt), Ok(stored_key), Ok(server_key)) = (
442 iterations.parse::<u32>(),
443 hex::decode(salt),
444 hex::decode(stored_key),
445 hex::decode(server_key),
446 ) else {
447 return InvalidConfigSnafu {
448 value: "pg_scram_sha256".to_string(),
449 msg: "Invalid pg scram sha256 verifier encoding",
450 }
451 .fail();
452 };
453
454 PgScramSha256Verifier::new(iterations, salt, stored_key, server_key)
455}
456
457fn pg_scram_sha256_salted_password(
458 password: &[u8],
459 salt: &[u8],
460 iterations: u32,
461) -> Result<Vec<u8>> {
462 ensure!(
463 iterations > 0 && iterations <= MAX_PBKDF2_SHA256_ITERATIONS,
464 IllegalParamSnafu {
465 msg: format!(
466 "pg_scram_sha256 iterations must be in 1..={}",
467 MAX_PBKDF2_SHA256_ITERATIONS
468 )
469 }
470 );
471 ensure!(
472 !salt.is_empty() && salt.len() <= MAX_PBKDF2_SHA256_SALT_LEN,
473 IllegalParamSnafu {
474 msg: format!(
475 "pg_scram_sha256 salt length must be in 1..={}",
476 MAX_PBKDF2_SHA256_SALT_LEN
477 )
478 }
479 );
480
481 let prepared_password = std::str::from_utf8(password)
482 .ok()
483 .and_then(|password| stringprep::saslprep(password).ok());
484 let password = prepared_password
485 .as_deref()
486 .map(str::as_bytes)
487 .unwrap_or(password);
488
489 let mut salted_password = [0u8; PG_SCRAM_SHA256_KEY_LEN];
490 pbkdf2_hmac::<Sha256>(password, salt, iterations, &mut salted_password);
491 Ok(salted_password.to_vec())
492}
493
494fn hmac_sha256(key: &[u8], msg: &[u8]) -> Vec<u8> {
495 let mut mac = HmacSha256::new_from_slice(key).expect("HMAC accepts any key length");
496 mac.update(msg);
497 mac.finalize().into_bytes().to_vec()
498}
499
500fn sha256(data: &[u8]) -> Vec<u8> {
501 let mut hasher = Sha256::new();
502 hasher.update(data);
503 hasher.finalize().to_vec()
504}
505
506fn xor(lhs: &[u8], rhs: &[u8]) -> Vec<u8> {
507 lhs.iter().zip(rhs).map(|(l, r)| l ^ r).collect()
508}
509
510fn sha1_two(input_1: &[u8], input_2: &[u8]) -> Vec<u8> {
511 let mut hasher = Sha1::new();
512 hasher.update(input_1);
513 hasher.update(input_2);
514 hasher.finalize().to_vec()
515}
516
517fn sha1_one(data: &[u8]) -> Vec<u8> {
518 let mut hasher = Sha1::new();
519 hasher.update(data);
520 hasher.finalize().to_vec()
521}
522
523fn double_sha1(data: &[u8]) -> Vec<u8> {
524 sha1_one(&sha1_one(data))
525}
526
527#[cfg(test)]
528mod tests {
529 use super::*;
530
531 fn mysql_native_password_auth_data(password: &[u8], salt: &[u8]) -> Vec<u8> {
532 let hash_stage_1 = sha1_one(password);
533 let hash_stage_2 = mysql_native_password_hash(password);
534 let scramble = sha1_two(salt, &hash_stage_2);
535 hash_stage_1
536 .iter()
537 .zip(scramble)
538 .map(|(lhs, rhs)| lhs ^ rhs)
539 .collect()
540 }
541
542 #[test]
543 fn test_sha() {
544 let sha_1_answer: Vec<u8> = vec![
545 124, 74, 141, 9, 202, 55, 98, 175, 97, 229, 149, 32, 148, 61, 194, 100, 148, 248, 148,
546 27,
547 ];
548 let sha_1 = sha1_one("123456".as_bytes());
549 assert_eq!(sha_1, sha_1_answer);
550
551 let double_sha1_answer: Vec<u8> = vec![
552 107, 180, 131, 126, 183, 67, 41, 16, 94, 228, 86, 141, 218, 125, 198, 126, 210, 202,
553 42, 217,
554 ];
555 let double_sha1 = double_sha1("123456".as_bytes());
556 assert_eq!(double_sha1, double_sha1_answer);
557
558 let sha1_2_answer: Vec<u8> = vec![
559 132, 115, 215, 211, 99, 186, 164, 206, 168, 152, 217, 192, 117, 47, 240, 252, 142, 244,
560 37, 204,
561 ];
562 let sha1_2 = sha1_two("123456".as_bytes(), "654321".as_bytes());
563 assert_eq!(sha1_2, sha1_2_answer);
564 }
565
566 #[test]
567 fn test_format_mysql_native_password_verifier() {
568 let verifier = format_mysql_native_password_verifier("123456".as_bytes());
569 assert_eq!(
570 "mysql_native_password:6bb4837eb74329105ee4568dda7dc67ed2ca2ad9",
571 verifier
572 );
573 assert_eq!(
574 mysql_native_password_hash(b"123456"),
575 parse_mysql_native_password_verifier(&verifier).unwrap()
576 );
577 assert!(parse_mysql_native_password_verifier("mysql_native_password:00").is_err());
578
579 let salt = b"01234567890123456789";
580 let auth_data = mysql_native_password_auth_data(b"123456", salt);
581 auth_mysql_with_verifier(&auth_data, salt, "greptime", &verifier).unwrap();
582 assert!(
583 auth_mysql_with_verifier(
584 &auth_data,
585 salt,
586 "greptime",
587 &format_mysql_native_password_verifier(b"wrong")
588 )
589 .is_err()
590 );
591 }
592
593 #[test]
594 fn test_format_pbkdf2_sha256_password_verifier() {
595 let verifier =
596 format_pbkdf2_sha256_password_verifier("password".as_bytes(), b"salt", 4096).unwrap();
597 assert_eq!(
598 "pbkdf2_sha256:4096:73616c74:c5e478d59288c841aa530db6845c4c8d962893a001ce4e11a4963873aa98134a",
599 verifier
600 );
601
602 assert!(format_pbkdf2_sha256_password_verifier(b"password", b"", 4096).is_err());
603 assert!(format_pbkdf2_sha256_password_verifier(b"password", b"salt", 0).is_err());
604 assert!(
605 format_pbkdf2_sha256_password_verifier(
606 b"password",
607 b"salt",
608 MAX_PBKDF2_SHA256_ITERATIONS + 1,
609 )
610 .is_err()
611 );
612 }
613
614 #[test]
615 fn test_format_pg_scram_sha256_password_verifier() {
616 let verifier =
617 format_pg_scram_sha256_password_verifier("password".as_bytes(), b"salt", 4096).unwrap();
618 assert_eq!(
619 "pg_scram_sha256:4096:73616c74:945e1c466fc9932efadc23781edc5d1e78d5e10f005933652af1a6105154f084:b9bf0e811b1fb6793671c0cc3adedf7c75cd72291191092ad65878c5a02aad2c",
620 verifier
621 );
622 let parsed = parse_pg_scram_sha256_password_verifier(&verifier).unwrap();
623 assert_eq!(4096, parsed.iterations());
624 assert_eq!(b"salt", parsed.salt());
625 assert!(parse_pg_scram_sha256_password_verifier("pg_scram_sha256:bad").is_err());
626 }
627
628 #[test]
629 fn test_pg_scram_sha256_applies_saslprep() {
630 let normalized = PgScramSha256Verifier::from_password(b"pass word", b"salt", 4096).unwrap();
631 let non_breaking_space =
632 PgScramSha256Verifier::from_password("pass\u{00a0}word".as_bytes(), b"salt", 4096)
633 .unwrap();
634
635 assert_eq!(normalized, non_breaking_space);
636 assert!(
637 non_breaking_space
638 .verify_plain_password(b"pass word")
639 .unwrap()
640 );
641 }
642
643 #[test]
644 fn test_pg_scram_sha256_uses_original_bytes_when_saslprep_is_not_possible() {
645 let invalid_utf8 = b"password\xff";
646 let prohibited = b"password\x07";
647
648 for password in [invalid_utf8.as_slice(), prohibited.as_slice()] {
649 let verifier = PgScramSha256Verifier::from_password(password, b"salt", 4096).unwrap();
650 assert!(verifier.verify_plain_password(password).unwrap());
651 }
652 }
653
654 #[test]
655 fn test_mock_verifier_is_stable_per_username() {
656 let alice = PgScramSha256Verifier::mock_for_unknown_user(b"alice");
657 let alice_again = PgScramSha256Verifier::mock_for_unknown_user(b"alice");
658 let bob = PgScramSha256Verifier::mock_for_unknown_user(b"bob");
659
660 assert_eq!(alice.salt(), alice_again.salt());
663 assert_ne!(alice.salt(), bob.salt());
664 assert_eq!(alice.iterations(), DEFAULT_PBKDF2_SHA256_ITERATIONS);
665 assert_eq!(alice.salt().len(), DEFAULT_PBKDF2_SHA256_SALT_LEN);
666
667 assert!(
669 alice
670 .verify_client_proof(b"auth-message", &[0u8; PG_SCRAM_SHA256_KEY_LEN])
671 .unwrap()
672 .is_none()
673 );
674 }
675}