Skip to content

Commit 5124a4c

Browse files
committed
.
1 parent 162f609 commit 5124a4c

3 files changed

Lines changed: 14 additions & 21 deletions

File tree

devolutions-gateway/src/api/preflight.rs

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -337,17 +337,8 @@ async fn handle_operation(
337337
});
338338
}
339339

340-
// Encrypt passwords before storing.
341-
let encrypted_mapping = mapping.map(|m| m.encrypt()).transpose().map_err(|e| {
342-
error!(error = format!("{e:#}"), "Failed to encrypt credentials");
343-
PreflightError::new(
344-
PreflightAlertStatus::InternalServerError,
345-
"credential encryption failed",
346-
)
347-
})?;
348-
349340
let previous_entry = credential_store
350-
.insert(token, encrypted_mapping, time_to_live)
341+
.insert(token, mapping, time_to_live)
351342
.inspect_err(|error| warn!(%operation.id, error = format!("{error:#}"), "Failed to insert credentials"))
352343
.map_err(|e| PreflightError::new(PreflightAlertStatus::InternalServerError, format!("{e:#}")))?;
353344

devolutions-gateway/src/credential/mod.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,10 @@ pub struct AppCredentialMapping {
4545
pub target: AppCredential,
4646
}
4747

48-
/// Cleartext credential wrapper used only for deserialization.
48+
/// Cleartext credential received from the API, used for deserialization only.
4949
///
50-
/// This type is converted to `AppCredential` (with encrypted password) immediately after deserialization.
50+
/// Passwords are encrypted and stored as [`AppCredential`] inside the credential store.
51+
/// This type is never stored directly — hand it to [`CredentialStoreHandle::insert`].
5152
#[derive(Debug, Deserialize)]
5253
#[serde(tag = "kind")]
5354
pub enum CleartextAppCredential {
@@ -59,8 +60,7 @@ pub enum CleartextAppCredential {
5960
}
6061

6162
impl CleartextAppCredential {
62-
/// Encrypt the password and convert to storage-ready `AppCredential`.
63-
pub fn encrypt(self) -> anyhow::Result<AppCredential> {
63+
fn encrypt(self) -> anyhow::Result<AppCredential> {
6464
match self {
6565
CleartextAppCredential::UsernamePassword { username, password } => {
6666
let encrypted = MASTER_KEY.lock().encrypt(password.expose_secret())?;
@@ -73,9 +73,9 @@ impl CleartextAppCredential {
7373
}
7474
}
7575

76-
/// Cleartext credential mapping wrapper used only for deserialization.
76+
/// Cleartext credential mapping received from the API, used for deserialization only.
7777
///
78-
/// This type is converted to `AppCredentialMapping` (with encrypted passwords) immediately after deserialization.
78+
/// Passwords are encrypted on write. Hand this directly to [`CredentialStoreHandle::insert`].
7979
#[derive(Debug, Deserialize)]
8080
pub struct CleartextAppCredentialMapping {
8181
#[serde(rename = "proxy_credential")]
@@ -85,8 +85,7 @@ pub struct CleartextAppCredentialMapping {
8585
}
8686

8787
impl CleartextAppCredentialMapping {
88-
/// Encrypt passwords and convert to storage-ready `AppCredentialMapping`.
89-
pub fn encrypt(self) -> anyhow::Result<AppCredentialMapping> {
88+
fn encrypt(self) -> anyhow::Result<AppCredentialMapping> {
9089
Ok(AppCredentialMapping {
9190
proxy: self.proxy.encrypt()?,
9291
target: self.target.encrypt()?,
@@ -111,9 +110,10 @@ impl CredentialStoreHandle {
111110
pub fn insert(
112111
&self,
113112
token: String,
114-
mapping: Option<AppCredentialMapping>,
113+
mapping: Option<CleartextAppCredentialMapping>,
115114
time_to_live: time::Duration,
116115
) -> anyhow::Result<Option<ArcCredentialEntry>> {
116+
let mapping = mapping.map(CleartextAppCredentialMapping::encrypt).transpose()?;
117117
self.0.lock().insert(token, mapping, time_to_live)
118118
}
119119

devolutions-gateway/src/rdp_proxy.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,8 @@ where
412412
username,
413413
password: decrypted_password.expose_secret().to_owned(),
414414
};
415-
// decrypted_password drops here, zeroizing memory.
415+
// decrypted_password drops here, zeroizing its buffer; note: a copy of the plaintext
416+
// remains in `credentials` above, which is a regular String (downstream API limitation).
416417

417418
let (mut sequence, mut ts_request) = ironrdp_connector::credssp::CredsspSequence::init(
418419
credentials,
@@ -572,7 +573,8 @@ where
572573
username,
573574
password: decrypted_password.expose_secret().to_owned().into(),
574575
};
575-
// decrypted_password drops here, zeroizing memory.
576+
// decrypted_password drops here, zeroizing its buffer; note: a copy of the plaintext
577+
// remains in `identity` above (downstream API limitation).
576578

577579
let mut sequence = ironrdp_acceptor::credssp::CredsspSequence::init(
578580
&identity,

0 commit comments

Comments
 (0)