diff --git a/src/connectors/ssh.rs b/src/connectors/ssh.rs index 1d9074c6..898717e1 100644 --- a/src/connectors/ssh.rs +++ b/src/connectors/ssh.rs @@ -23,7 +23,6 @@ pub struct SshConnectorConfig { pub port: u16, pub username: String, pub auth: SshAuth, - #[serde(default)] pub server_key_verification: ServerKeyVerification, #[serde(default = "default_connector_timeout")] pub inactivity_timeout_secs: u64, @@ -46,31 +45,13 @@ pub enum SshAuth { #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] #[serde(tag = "type")] -#[derive(Default)] pub enum ServerKeyVerification { #[serde(rename = "fingerprint")] Fingerprint { fingerprint: String }, #[serde(rename = "insecureAcceptAny")] - #[default] InsecureAcceptAny, } -impl Default for SshConnectorConfig { - fn default() -> Self { - Self { - name: String::new(), - server: String::new(), - port: 22, - username: String::new(), - auth: SshAuth::Password { - password: String::new(), - }, - server_key_verification: ServerKeyVerification::default(), - inactivity_timeout_secs: default_connector_timeout(), - } - } -} - #[derive(Debug, Clone, Serialize)] pub struct SshConnector { #[serde(flatten)] @@ -249,6 +230,8 @@ username: testuser auth: type: password password: testpass +serverKeyVerification: + type: insecureAcceptAny "#; let value: Value = serde_yaml_ng::from_str(yaml).expect("Failed to parse test YAML"); let connector = from_value(&value).expect("Failed to deserialize SSH connector config"); @@ -267,6 +250,8 @@ auth: type: privateKey path: /path/to/key passphrase: keypass +serverKeyVerification: + type: insecureAcceptAny "#; let value: Value = serde_yaml_ng::from_str(yaml).expect("Failed to parse test YAML"); let connector = from_value(&value).expect("Failed to deserialize SSH connector config"); @@ -284,6 +269,8 @@ username: keyuser auth: type: privateKey path: /path/to/key +serverKeyVerification: + type: insecureAcceptAny "#; let value: Value = serde_yaml_ng::from_str(yaml).expect("Failed to parse test YAML"); let _connector = from_value(&value).expect("Failed to deserialize SSH connector config"); @@ -317,6 +304,8 @@ username: testuser auth: type: password password: testpass +serverKeyVerification: + type: insecureAcceptAny "#; let value: Value = serde_yaml_ng::from_str(yaml).expect("Failed to parse test YAML"); let result = from_value(&value); @@ -334,6 +323,8 @@ username: testuser auth: type: password password: testpass +serverKeyVerification: + type: insecureAcceptAny "#; let value: Value = serde_yaml_ng::from_str(yaml).expect("Failed to parse test YAML"); let _connector = from_value(&value).expect("Failed to deserialize SSH connector config"); diff --git a/src/rules/mod.rs b/src/rules/mod.rs index 46135508..46c0c170 100644 --- a/src/rules/mod.rs +++ b/src/rules/mod.rs @@ -120,16 +120,15 @@ impl Rule { rules_metrics().execute_time.start_timer() }; let t = Instant::now(); - let ret = if self.filter.is_none() { - true - } else { - match self.filter.as_ref().unwrap().evaluate(request).await { + let ret = match &self.filter { + None => true, + Some(f) => match f.evaluate(request).await { Ok(b) => b, Err(e) => { trace!("error evaluating filter: {:?}", e); false } - } + }, }; let t = t.elapsed().as_nanos() as u64; #[cfg(feature = "metrics")] diff --git a/tests/comprehensive/scripts/generate_matrix_config.py b/tests/comprehensive/scripts/generate_matrix_config.py index 0e92d31b..2013e7db 100644 --- a/tests/comprehensive/scripts/generate_matrix_config.py +++ b/tests/comprehensive/scripts/generate_matrix_config.py @@ -148,6 +148,9 @@ def _define_connectors(self) -> List[ConnectorConfig]: "auth": { "type": "password", "password": "proxy123" + }, + "serverKeyVerification": { + "type": "insecureAcceptAny" } } ), diff --git a/tests/ssh_security.rs b/tests/ssh_security.rs new file mode 100644 index 00000000..b72a9b60 --- /dev/null +++ b/tests/ssh_security.rs @@ -0,0 +1,73 @@ +use redproxy_rs::connectors::ssh::{ServerKeyVerification, SshConnectorConfig}; +use serde_yaml_ng::Value; + +#[test] +fn test_missing_verification_fails() { + let yaml = r#" +name: test-ssh +type: ssh +server: ssh.example.com +port: 22 +username: testuser +auth: + type: password + password: testpass +"#; + let result: Result = serde_yaml_ng::from_str(yaml); + assert!( + result.is_err(), + "Deserialization should fail when serverKeyVerification is missing" + ); + let err = result.err().unwrap().to_string(); + assert!( + err.contains("missing field `serverKeyVerification`"), + "Error message should mention missing field: {}", + err + ); +} + +#[test] +fn test_explicit_insecure_verification_succeeds() { + let yaml = r#" +name: test-ssh +type: ssh +server: ssh.example.com +port: 22 +username: testuser +auth: + type: password + password: testpass +serverKeyVerification: + type: insecureAcceptAny +"#; + let config: SshConnectorConfig = serde_yaml_ng::from_str(yaml) + .expect("Deserialization should succeed with explicit insecureAcceptAny"); + assert!(matches!( + config.server_key_verification, + ServerKeyVerification::InsecureAcceptAny + )); +} + +#[test] +fn test_explicit_fingerprint_verification_succeeds() { + let yaml = r#" +name: test-ssh +type: ssh +server: ssh.example.com +port: 22 +username: testuser +auth: + type: password + password: testpass +serverKeyVerification: + type: fingerprint + fingerprint: "SHA256:abcd" +"#; + let config: SshConnectorConfig = serde_yaml_ng::from_str(yaml) + .expect("Deserialization should succeed with explicit fingerprint"); + if let ServerKeyVerification::Fingerprint { fingerprint } = config.server_key_verification { + assert_eq!(fingerprint, "SHA256:abcd"); + } else { + panic!("Expected Fingerprint variant"); + } +}