rocketmq_auth/secret_provider/
environment.rs1use std::collections::BTreeMap;
16use std::fmt;
17
18use rocketmq_security_api::SecretAccess;
19use rocketmq_security_api::SecretMaterial;
20use rocketmq_security_api::SecretName;
21use rocketmq_security_api::SecretPersistence;
22use rocketmq_security_api::SecretProvider;
23use rocketmq_security_api::SecretProviderCapabilities;
24use rocketmq_security_api::SecretProviderId;
25use rocketmq_security_api::SecretVersion;
26use rocketmq_security_api::SecretVersioning;
27use rocketmq_security_api::SecurityOperation;
28use rocketmq_security_api::SecurityProviderError;
29use rocketmq_security_api::SecurityProviderFailure;
30use rocketmq_security_api::VersionedSecret;
31
32use crate::AuthFailureKind;
33use crate::AuthOperation;
34use crate::AuthServiceError;
35use crate::AuthServiceResult;
36
37pub struct EnvironmentSecretProvider {
39 id: SecretProviderId,
40 variables: BTreeMap<SecretName, String>,
41}
42
43impl EnvironmentSecretProvider {
44 pub fn new(
50 id: SecretProviderId,
51 mappings: impl IntoIterator<Item = (SecretName, String)>,
52 ) -> AuthServiceResult<Self> {
53 let mut variables = BTreeMap::new();
54 for (name, variable) in mappings {
55 if variable.is_empty() || variable.contains(['\0', '=']) || variables.insert(name, variable).is_some() {
56 return Err(AuthServiceError::new(
57 AuthOperation::LoadSecret,
58 AuthFailureKind::InvalidConfiguration,
59 ));
60 }
61 }
62 if variables.is_empty() {
63 return Err(AuthServiceError::new(
64 AuthOperation::LoadSecret,
65 AuthFailureKind::InvalidConfiguration,
66 ));
67 }
68 Ok(Self { id, variables })
69 }
70}
71
72impl fmt::Debug for EnvironmentSecretProvider {
73 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74 f.debug_struct("EnvironmentSecretProvider")
75 .field("id", &self.id)
76 .field("mapped_name_count", &self.variables.len())
77 .finish()
78 }
79}
80
81impl SecretProvider for EnvironmentSecretProvider {
82 fn id(&self) -> &SecretProviderId {
83 &self.id
84 }
85
86 fn capabilities(&self) -> SecretProviderCapabilities {
87 SecretProviderCapabilities::new(
88 SecretAccess::ReadOnly,
89 SecretPersistence::ProcessEnvironment,
90 SecretVersioning::Unversioned,
91 )
92 }
93
94 fn read(&self, name: &SecretName) -> Result<VersionedSecret, SecurityProviderError> {
95 let variable = self.variables.get(name).ok_or_else(|| {
96 SecurityProviderError::new(SecurityProviderFailure::NotFound, SecurityOperation::ReadSecret)
97 })?;
98 let value = match std::env::var(variable) {
99 Ok(value) => value,
100 Err(std::env::VarError::NotPresent) => {
101 return Err(SecurityProviderError::new(
102 SecurityProviderFailure::NotFound,
103 SecurityOperation::ReadSecret,
104 ));
105 }
106 Err(std::env::VarError::NotUnicode(_)) => {
107 return Err(SecurityProviderError::new(
108 SecurityProviderFailure::InvalidData,
109 SecurityOperation::ReadSecret,
110 ));
111 }
112 };
113 let material = SecretMaterial::new(value.into_bytes()).map_err(|source| {
114 SecurityProviderError::caused_by(
115 SecurityProviderFailure::InvalidData,
116 SecurityOperation::ReadSecret,
117 source,
118 )
119 })?;
120 Ok(VersionedSecret::new(material, None))
121 }
122
123 fn write(
124 &self,
125 _name: &SecretName,
126 _material: SecretMaterial,
127 _expected_version: Option<SecretVersion>,
128 ) -> Result<SecretVersion, SecurityProviderError> {
129 Err(SecurityProviderError::new(
130 SecurityProviderFailure::Unsupported,
131 SecurityOperation::WriteSecret,
132 ))
133 }
134}