tansu_storage/service/
alter_user_scram_credentials.rs1use crate::{Error, Result, ScramCredential, Storage};
16use bytes::Bytes;
17use rama::{Context, Service};
18use rsasl::mechanisms::scram::tools::derive_keys;
19use sha2::{Digest, Sha256, Sha512};
20use tansu_sans_io::{
21 AlterUserScramCredentialsRequest, AlterUserScramCredentialsResponse, ApiKey, ErrorCode,
22 ScramMechanism, alter_user_scram_credentials_response::AlterUserScramCredentialsResult,
23};
24use tracing::{debug, instrument};
25
26#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
27pub struct AlterUserScramCredentialsService;
28
29impl ApiKey for AlterUserScramCredentialsService {
30 const KEY: i16 = AlterUserScramCredentialsRequest::KEY;
31}
32
33impl<G> Service<G, AlterUserScramCredentialsRequest> for AlterUserScramCredentialsService
34where
35 G: Storage,
36{
37 type Response = AlterUserScramCredentialsResponse;
38 type Error = Error;
39
40 #[instrument(skip(ctx, req))]
41 async fn serve(
42 &self,
43 ctx: Context<G>,
44 req: AlterUserScramCredentialsRequest,
45 ) -> Result<Self::Response, Self::Error> {
46 let mut results = vec![];
47
48 if let Some(deletions) = req.deletions {
49 for deletion in deletions {
50 let mechanism = ScramMechanism::try_from(deletion.mechanism)?;
51
52 results.push(
53 ctx.state()
54 .delete_user_scram_credential(&deletion.name, mechanism)
55 .await
56 .map_or(
57 AlterUserScramCredentialsResult::default()
58 .user(deletion.name.clone())
59 .error_code(ErrorCode::UnsupportedSaslMechanism.into())
60 .error_message(Some("".into())),
61 |()| {
62 AlterUserScramCredentialsResult::default()
63 .user(deletion.name.clone())
64 .error_code(ErrorCode::None.into())
65 .error_message(Some("".into()))
66 },
67 ),
68 );
69 }
70 }
71
72 if let Some(upsertions) = req.upsertions {
73 for upsertion in upsertions {
74 let (mechanism, stored_key, server_key) =
75 ScramMechanism::try_from(upsertion.mechanism)
76 .inspect(|mechanism| debug!(?mechanism))
77 .map(|mechanism| {
78 if mechanism == ScramMechanism::Scram256 {
79 let (client_key, server_key) =
80 derive_keys::<Sha256>(&upsertion.salted_password);
81
82 (
83 mechanism,
84 Bytes::copy_from_slice(&Sha256::digest(client_key)[..]),
85 Bytes::copy_from_slice(&server_key[..]),
86 )
87 } else {
88 let (client_key, server_key) =
89 derive_keys::<Sha512>(&upsertion.salted_password);
90
91 (
92 mechanism,
93 Bytes::copy_from_slice(&Sha512::digest(client_key)[..]),
94 Bytes::copy_from_slice(&server_key[..]),
95 )
96 }
97 })?;
98
99 let credential = ScramCredential {
100 salt: upsertion.salt,
101 iterations: upsertion.iterations,
102 stored_key,
103 server_key,
104 };
105
106 results.push(
107 ctx.state()
108 .upsert_user_scram_credential(
109 upsertion.name.as_str(),
110 mechanism,
111 credential,
112 )
113 .await
114 .map_or(
115 AlterUserScramCredentialsResult::default()
116 .user(upsertion.name.clone())
117 .error_code(ErrorCode::UnsupportedSaslMechanism.into())
118 .error_message(Some("".into())),
119 |()| {
120 AlterUserScramCredentialsResult::default()
121 .user(upsertion.name.clone())
122 .error_code(ErrorCode::None.into())
123 .error_message(Some("".into()))
124 },
125 ),
126 );
127 }
128 }
129
130 Ok(AlterUserScramCredentialsResponse::default()
131 .throttle_time_ms(0)
132 .results(Some(results)))
133 }
134}