mod integ_utils; use crate::integ_utils::TestVault; use integ_utils::TlsConfiguration; use maplit::hashmap; use matches::assert_matches; use secrecy::{ExposeSecret, Secret}; use xand_secrets::{CheckHealthError, ReadSecretError, SecretKeyValueStore}; use xand_secrets_vault::{VaultConfiguration, VaultSecretKeyValueStore}; #[tokio::test] async fn integration_test_valid_read_over_http() { let handle = TestVault::start(TlsConfiguration::Disabled).await; handle.set_secrets( "/secret/test/path", hashmap! { String::from("username") => String::from("test_user"), String::from("password") => String::from("test_password"), }, ); let secret_store = VaultSecretKeyValueStore::create_from_config(VaultConfiguration { http_endpoint: handle.vault_address, token: Secret::new(handle.vault_token), additional_https_root_certificate_files: None, }) .unwrap(); assert_eq!( "test_user", secret_store .read("/secret/test/path/username") .await .unwrap() .expose_secret() ); assert_eq!( "test_password", secret_store .read("/secret/test/path/password") .await .unwrap() .expose_secret() ); } #[tokio::test] async fn integration_test_changing_secrets() { let handle = TestVault::start(TlsConfiguration::Disabled).await; handle.set_secrets( "/secret/test/path", hashmap! { String::from("password") => String::from("test_password"), }, ); let secret_store = VaultSecretKeyValueStore::create_from_config(VaultConfiguration { http_endpoint: handle.vault_address.clone(), token: Secret::new(handle.vault_token.clone()), additional_https_root_certificate_files: None, }) .unwrap(); assert_eq!( "test_password", secret_store .read("/secret/test/path/password") .await .unwrap() .expose_secret() ); handle.set_secrets( "/secret/test/path", hashmap! { String::from("password") => String::from("another_password"), }, ); assert_eq!( "another_password", secret_store .read("/secret/test/path/password") .await .unwrap() .expose_secret() ); } #[tokio::test] async fn integration_test_not_found() { let handle = TestVault::start(TlsConfiguration::Disabled).await; let secret_store = VaultSecretKeyValueStore::create_from_config(VaultConfiguration { http_endpoint: handle.vault_address, token: Secret::new(handle.vault_token), additional_https_root_certificate_files: None, }) .unwrap(); let read_result = secret_store.read("/secret/test/path/password").await; if let Err(ReadSecretError::KeyNotFound { key }) = read_result { assert_eq!("/secret/test/path/password", key); } else { panic!("Expected KeyNotFound error, found {:?}", read_result); } } #[tokio::test] async fn integration_test_incorrect_token() { let handle = TestVault::start(TlsConfiguration::Disabled).await; handle.set_secrets( "/secret/test/path", hashmap! { String::from("password") => String::from("test_password"), }, ); let secret_store = VaultSecretKeyValueStore::create_from_config(VaultConfiguration { http_endpoint: handle.vault_address, token: Secret::new(String::from("my-bad-token")), additional_https_root_certificate_files: None, }) .unwrap(); let read_result = secret_store.read("/secret/test/path/password").await; assert_matches!(read_result, Err(ReadSecretError::Authentication { .. })); } #[tokio::test] async fn integration_test_incorrect_endpoint() { let handle = TestVault::start(TlsConfiguration::Disabled).await; handle.set_secrets( "/secret/test/path", hashmap! { String::from("password") => String::from("test_password"), }, ); let secret_store = VaultSecretKeyValueStore::create_from_config(VaultConfiguration { http_endpoint: String::from("http://this-does-not-exist.foobar/"), token: Secret::new(handle.vault_token), additional_https_root_certificate_files: None, }) .unwrap(); let read_result = secret_store.read("/secret/test/path/password").await; assert_matches!(read_result, Err(ReadSecretError::Request { .. })); } #[tokio::test] async fn integration_test_valid_read_over_https() { let handle = TestVault::start(TlsConfiguration::Enabled).await; handle.set_secrets( "/secret/test/path", hashmap! { String::from("username") => String::from("test_user"), String::from("password") => String::from("test_password"), }, ); let secret_store = VaultSecretKeyValueStore::create_from_config(VaultConfiguration { http_endpoint: handle.vault_address, token: Secret::new(handle.vault_token), additional_https_root_certificate_files: Some(vec![String::from( "tests/certs/valid_test_cert_chain/rootCA.pem", )]), }) .unwrap(); assert_eq!( "test_user", secret_store .read("/secret/test/path/username") .await .unwrap() .expose_secret() ); assert_eq!( "test_password", secret_store .read("/secret/test/path/password") .await .unwrap() .expose_secret() ); } #[tokio::test] async fn integration_test_https_no_valid_cert() { let handle = TestVault::start(TlsConfiguration::Enabled).await; handle.set_secrets( "/secret/test/path", hashmap! { String::from("username") => String::from("test_user"), String::from("password") => String::from("test_password"), }, ); let secret_store = VaultSecretKeyValueStore::create_from_config(VaultConfiguration { http_endpoint: handle.vault_address, token: Secret::new(handle.vault_token), additional_https_root_certificate_files: Some(vec![String::from( "tests/certs/nonfunctional_dummy_root_ca.pem", )]), }) .unwrap(); let read_result = secret_store.read("/secret/test/path/password").await; assert_matches!(read_result, Err(ReadSecretError::Request { .. })); } #[tokio::test] async fn integration_test_check_health_healthy() { let handle = TestVault::start(TlsConfiguration::Disabled).await; let secret_store = VaultSecretKeyValueStore::create_from_config(VaultConfiguration { http_endpoint: handle.vault_address, token: Secret::new(handle.vault_token), additional_https_root_certificate_files: None, }) .unwrap(); secret_store.check_health().await.unwrap(); } #[tokio::test] async fn integration_test_check_health_bad_token() { let handle = TestVault::start(TlsConfiguration::Disabled).await; let secret_store = VaultSecretKeyValueStore::create_from_config(VaultConfiguration { http_endpoint: handle.vault_address, token: Secret::new(String::from("my-bad-test-token")), additional_https_root_certificate_files: None, }) .unwrap(); let health_result = secret_store.check_health().await; assert_matches!(health_result, Err(CheckHealthError::Authentication { .. })); } #[tokio::test] async fn integration_test_check_health_uninitialized() { let handle = TestVault::start(TlsConfiguration::Disabled).await; let secret_store = VaultSecretKeyValueStore::create_from_config(VaultConfiguration { http_endpoint: handle.vault_address.clone(), token: Secret::new(handle.vault_token.clone()), additional_https_root_certificate_files: None, }) .unwrap(); handle.seal_vault(); let health_result = secret_store.check_health().await; assert_eq!( "the remote endpoint signalled an internal health issue. \ An error code was returned while making an HTTP request to path \"/v1/sys/health\". \ Status code: 503.", format!("{}", health_result.unwrap_err()) ); } #[tokio::test] async fn integration_test_check_health_healthy_https() { let handle = TestVault::start(TlsConfiguration::Enabled).await; let secret_store = VaultSecretKeyValueStore::create_from_config(VaultConfiguration { http_endpoint: handle.vault_address, token: Secret::new(handle.vault_token), additional_https_root_certificate_files: Some(vec![String::from( "tests/certs/valid_test_cert_chain/rootCA.pem", )]), }) .unwrap(); secret_store.check_health().await.unwrap(); } #[tokio::test] async fn integration_test_check_health_https_no_cert() { let handle = TestVault::start(TlsConfiguration::Enabled).await; let secret_store = VaultSecretKeyValueStore::create_from_config(VaultConfiguration { http_endpoint: handle.vault_address, token: Secret::new(handle.vault_token), additional_https_root_certificate_files: None, }) .unwrap(); let health_result = secret_store.check_health().await; assert_matches!(health_result, Err(CheckHealthError::Unreachable { .. })); }