test CLI credentials against main app

This commit is contained in:
Joseph Montanaro 2024-07-21 06:38:25 -04:00
parent 02ba19d709
commit 3b61aa924a
5 changed files with 131 additions and 13 deletions

View File

@ -10,7 +10,7 @@ pub use cli::{
pub(crate) use platform::connect; pub(crate) use platform::connect;
pub use platform::server_addr; pub use platform::server_addr;
mod proto; pub mod proto;
#[cfg(unix)] #[cfg(unix)]

View File

@ -49,7 +49,7 @@ pub enum CliCredential {
} }
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")] #[serde(rename_all = "PascalCase")]
pub struct AwsBaseCredential { pub struct AwsBaseCredential {
#[serde(default = "default_aws_version")] #[serde(default = "default_aws_version")]
@ -59,7 +59,7 @@ pub struct AwsBaseCredential {
} }
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")] #[serde(rename_all = "PascalCase")]
pub struct AwsSessionCredential { pub struct AwsSessionCredential {
#[serde(default = "default_aws_version")] #[serde(default = "default_aws_version")]

View File

@ -185,10 +185,16 @@ where S: Serializer
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use aws_sdk_sts::primitives::DateTimeFormat;
use creddy_cli::proto::{
AwsBaseCredential as CliBase,
AwsSessionCredential as CliSession,
};
use sqlx::SqlitePool; use sqlx::SqlitePool;
use sqlx::types::uuid::uuid; use sqlx::types::uuid::uuid;
fn creds() -> AwsBaseCredential { fn creds() -> AwsBaseCredential {
AwsBaseCredential::new( AwsBaseCredential::new(
"AKIAIOSFODNN7EXAMPLE".into(), "AKIAIOSFODNN7EXAMPLE".into(),
@ -242,4 +248,98 @@ mod tests {
assert_eq!(&creds().into_credential(), &list[0]); assert_eq!(&creds().into_credential(), &list[0]);
assert_eq!(&creds_2().into_credential(), &list[1]); assert_eq!(&creds_2().into_credential(), &list[1]);
} }
// In order to avoid the CLI depending on the main app (and thus defeating the purpose
// of having a separate CLI at all) it re-defines the credentials that need to be sent
// back and forth. To prevent the separate definitions from drifting aprt, we test
// serializing/deserializing in both directions.
#[test]
fn test_cli_to_app_base() {
let cli_base = CliBase {
version: 1,
access_key_id: "AKIAIOSFODNN7EXAMPLE".into(),
secret_access_key: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY".into(),
};
let json = serde_json::to_string(&cli_base).unwrap();
let computed: AwsBaseCredential = serde_json::from_str(&json)
.expect("Failed to deserialize base credentials from CLI -> main app");
assert_eq!(creds(), computed);
}
#[test]
fn test_app_to_cli_base() {
let base = creds();
let json = serde_json::to_string(&base).unwrap();
let computed: CliBase = serde_json::from_str(&json)
.expect("Failed to deserialize base credentials from main app -> CLI");
let expected = CliBase {
version: 1,
access_key_id: "AKIAIOSFODNN7EXAMPLE".into(),
secret_access_key: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY".into(),
};
assert_eq!(expected, computed);
}
#[test]
fn test_cli_to_app_session() {
let cli_session = CliSession {
version: 1,
access_key_id: "ASIAIOSFODNN7EXAMPLE".into(),
secret_access_key: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY".into(),
session_token: "JQ70sxbqnOGKu7+krevstYCLCaX2+alUAT60ARTBBnQ=ETC.".into(),
expiration: "2024-07-21T00:00:00Z".into(),
};
let json = serde_json::to_string(&cli_session).unwrap();
let computed: AwsSessionCredential = serde_json::from_str(&json)
.expect("Failed to deserialize session credentials from CLI -> main app");
let expected = AwsSessionCredential {
version: 1,
access_key_id: "ASIAIOSFODNN7EXAMPLE".into(),
secret_access_key: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY".into(),
session_token: "JQ70sxbqnOGKu7+krevstYCLCaX2+alUAT60ARTBBnQ=ETC.".into(),
expiration: DateTime::from_str(
"2024-07-21T00:00:00Z",
DateTimeFormat::DateTimeWithOffset
).unwrap(),
};
assert_eq!(expected, computed);
}
#[test]
fn test_app_to_cli_session() {
let session = AwsSessionCredential {
version: 1,
access_key_id: "ASIAIOSFODNN7EXAMPLE".into(),
secret_access_key: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY".into(),
session_token: "JQ70sxbqnOGKu7+krevstYCLCaX2+alUAT60ARTBBnQ=ETC.".into(),
expiration: DateTime::from_str(
"2024-07-21T00:00:00Z",
DateTimeFormat::DateTimeWithOffset
).unwrap(),
};
let json = serde_json::to_string(&session).unwrap();
let computed: CliSession = serde_json::from_str(&json)
.expect("Failed to deserialize session credentials from main app -> CLI");
let expected = CliSession {
version: 1,
access_key_id: "ASIAIOSFODNN7EXAMPLE".into(),
secret_access_key: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY".into(),
session_token: "JQ70sxbqnOGKu7+krevstYCLCaX2+alUAT60ARTBBnQ=ETC.".into(),
expiration: "2024-07-21T00:00:00Z".into(),
};
assert_eq!(expected, computed);
}
} }

View File

@ -1,3 +1,11 @@
INSERT INTO credentials (id, name, credential_type, is_default, created_at)
VALUES
(X'11111111111111111111111111111111', 'ssh-plain', 'ssh', 1, 1721557273),
(X'22222222222222222222222222222222', 'ssh-enc', 'ssh', 0, 1721557274),
(X'33333333333333333333333333333333', 'ed25519-plain', 'ssh', 0, 1721557275),
(X'44444444444444444444444444444444', 'ed25519-enc', 'ssh', 0, 1721557276);
INSERT INTO ssh_credentials (id, algorithm, comment, public_key, private_key_enc, nonce) INSERT INTO ssh_credentials (id, algorithm, comment, public_key, private_key_enc, nonce)
VALUES VALUES
( (

View File

@ -299,6 +299,8 @@ fn deserialize_algorithm<'de, D>(deserializer: D) -> Result<Algorithm, D::Error>
mod tests { mod tests {
use std::fs::{self, File}; use std::fs::{self, File};
use sqlx::types::uuid::uuid; use sqlx::types::uuid::uuid;
use crate::credentials::CredentialRecord;
use super::*; use super::*;
fn path(name: &str) -> String { fn path(name: &str) -> String {
@ -434,11 +436,14 @@ mod tests {
#[sqlx::test] #[sqlx::test]
async fn test_save_db(pool: SqlitePool) { async fn test_save_db(pool: SqlitePool) {
let crypto = Crypto::random(); let crypto = Crypto::random();
let k = rsa_plain(); let record = CredentialRecord {
let mut txn = pool.begin().await.unwrap(); id: random_uuid(),
k.save_details(&random_uuid(), &crypto, &mut txn).await name: "save_test".into(),
.expect("Failed to save SSH key to database"); is_default: false,
txn.commit().await.expect("Failed to finalize transaction"); credential: Credential::Ssh(rsa_plain()),
};
record.save(&crypto, &pool).await
.expect("Failed to save SSH key CredentialRecord to database");
} }
@ -454,13 +459,18 @@ mod tests {
#[sqlx::test] #[sqlx::test]
async fn test_save_load_db(pool: SqlitePool) { async fn test_save_load_db(pool: SqlitePool) {
let crypto = Crypto::random(); let crypto = Crypto::random();
let id = uuid!("7bc994dd-113a-4841-bcf7-b47c2fffdd25");
let known = ed25519_plain();
let mut txn = pool.begin().await.unwrap();
known.save_details(&id, &crypto, &mut txn).await.unwrap();
txn.commit().await.unwrap();
let id = random_uuid();
let record = CredentialRecord {
id,
name: "save_load_test".into(),
is_default: false,
credential: Credential::Ssh(ed25519_plain()),
};
record.save(&crypto, &pool).await.unwrap();
let loaded = SshKey::load(&id, &crypto, &pool).await.unwrap(); let loaded = SshKey::load(&id, &crypto, &pool).await.unwrap();
let known = ed25519_plain();
assert_eq!(known.algorithm, loaded.algorithm); assert_eq!(known.algorithm, loaded.algorithm);
assert_eq!(known.comment, loaded.comment); assert_eq!(known.comment, loaded.comment);