Skip to content

Commit

Permalink
Merge pull request #276 from hug-dev/multi-tests
Browse files Browse the repository at this point in the history
Add multitenancy tests
  • Loading branch information
hug-dev authored Oct 19, 2020
2 parents 690024b + 97bec3f commit 306c4fa
Show file tree
Hide file tree
Showing 13 changed files with 141 additions and 71 deletions.
8 changes: 3 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ users = "0.10.0"
libc = "0.2.77"
anyhow = "1.0.32"

[patch.crates-io]
psa-crypto = { git = "https://github.com/parallaxsecond/rust-psa-crypto", rev = "a1647d64e19e6e46baad708b84c2b5d0d3b543c7" }

[dev-dependencies]
rand = { version = "0.7.3", features = ["small_rng"] }

Expand Down
17 changes: 16 additions & 1 deletion ci.sh
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,23 @@ sleep 5
pgrep -f target/debug/parsec >/dev/null

if [ "$PROVIDER_NAME" = "all" ]; then
echo "Execute all-providers tests"
echo "Execute all-providers normal tests"
RUST_BACKTRACE=1 cargo test $TEST_FEATURES --manifest-path ./e2e_tests/Cargo.toml all_providers::normal

echo "Execute all-providers multi-tenancy tests"
su -c "RUST_BACKTRACE=1 cargo test $TEST_FEATURES --manifest-path ./e2e_tests/Cargo.toml --target-dir /home/parsec-client-1 all_providers::multitenancy::client1_before" parsec-client-1
su -c "RUST_BACKTRACE=1 cargo test $TEST_FEATURES --manifest-path ./e2e_tests/Cargo.toml --target-dir /home/parsec-client-2 all_providers::multitenancy::client2" parsec-client-2
su -c "RUST_BACKTRACE=1 cargo test $TEST_FEATURES --manifest-path ./e2e_tests/Cargo.toml --target-dir /home/parsec-client-1 all_providers::multitenancy::client1_after" parsec-client-1
# Change the authentication method
sed -i 's/^\(auth_type\s*=\s*\).*$/\1\"UnixPeerCredentials\"/' $CONFIG_PATH
pkill -SIGHUP parsec
sleep 5
su -c "RUST_BACKTRACE=1 cargo test $TEST_FEATURES --manifest-path ./e2e_tests/Cargo.toml --target-dir /home/parsec-client-1 all_providers::multitenancy::client1_before" parsec-client-1
su -c "RUST_BACKTRACE=1 cargo test $TEST_FEATURES --manifest-path ./e2e_tests/Cargo.toml --target-dir /home/parsec-client-2 all_providers::multitenancy::client2" parsec-client-2
su -c "RUST_BACKTRACE=1 cargo test $TEST_FEATURES --manifest-path ./e2e_tests/Cargo.toml --target-dir /home/parsec-client-1 all_providers::multitenancy::client1_after" parsec-client-1

# Last test as it changes the service configuration
echo "Execute all-providers config tests"
RUST_BACKTRACE=1 cargo test $TEST_FEATURES --manifest-path ./e2e_tests/Cargo.toml all_providers::config -- --test-threads=1
else
# Per provider tests
Expand Down
5 changes: 4 additions & 1 deletion e2e_tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,13 @@ publish = false

[dependencies]
serde = { version = "1.0.115", features = ["derive"] }
parsec-client = { git = "https://github.com/parallaxsecond/parsec-client-rust", rev = "dbd449a9e736f9f972e5489fb2d67949b93484dc", features = ["testing"] }
parsec-client = { git = "https://github.com/parallaxsecond/parsec-client-rust", rev = "3f7dfc7bd06bea7cb3aa38cdcb270af7b8899f89", features = ["testing"] }
log = "0.4.11"
rand = "0.7.3"

[patch.crates-io]
psa-crypto = { git = "https://github.com/parallaxsecond/rust-psa-crypto", rev = "22a505bedce1c21246ce5c3cf41ea97b0b781830" }

[dev-dependencies]
ring = "0.16.15"
env_logger = "0.7.1"
Expand Down
10 changes: 6 additions & 4 deletions e2e_tests/provider_cfg/all/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ RUN apt-get update && \
apt-get install -y git make gcc python3 python curl wget cmake && \
apt-get install -y automake autoconf libtool pkg-config libssl-dev && \
# These libraries are needed for bindgen as it uses libclang.so
apt-get install -y clang libclang-dev libc6-dev-i386
apt-get install -y clang libclang-dev libc6-dev-i386 && \
# Install cargo globally to not have to install it for each user for multitenancy tests
apt-get install -y cargo

WORKDIR /tmp
RUN wget https://github.com/ARMmbed/mbed-crypto/archive/mbedcrypto-2.0.0.tar.gz
Expand Down Expand Up @@ -44,6 +46,6 @@ RUN cd SoftHSMv2-2.5.0 \
# and is found with the find_slot_number script.
RUN softhsm2-util --init-token --slot 0 --label "Parsec Tests" --pin 123456 --so-pin 123456

# Install Rust toolchain
RUN curl https://sh.rustup.rs -sSf | bash -s -- -y
ENV PATH="/root/.cargo/bin:${PATH}"
# Add users for multitenancy tests
RUN useradd -m parsec-client-1
RUN useradd -m parsec-client-2
83 changes: 31 additions & 52 deletions e2e_tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pub use parsec_client::core::request_client::RequestClient;
pub use parsec_client::error;

use log::error;
use parsec_client::auth::AuthenticationData;
use parsec_client::auth::Authentication;
use parsec_client::core::basic_client::BasicClient;
use parsec_client::core::interface::operations::list_authenticators::AuthenticatorInfo;
use parsec_client::core::interface::operations::list_keys::KeyInfo;
Expand All @@ -24,7 +24,6 @@ use parsec_client::core::interface::operations::psa_key_attributes::{
};
use parsec_client::core::interface::requests::{Opcode, ProviderID, ResponseStatus, Result};
use parsec_client::core::ipc_handler::unix_socket;
use parsec_client::core::secrecy::{ExposeSecret, Secret};
use parsec_client::error::Error;
use std::collections::HashSet;
use std::time::Duration;
Expand All @@ -36,7 +35,7 @@ const TEST_TIMEOUT: Duration = Duration::from_secs(1);
#[derive(Debug)]
pub struct TestClient {
basic_client: BasicClient,
created_keys: Option<HashSet<(String, String, ProviderID)>>,
created_keys: Option<HashSet<(String, Option<String>, ProviderID)>>,
}

fn convert_error(err: Error) -> ResponseStatus {
Expand All @@ -52,47 +51,26 @@ fn convert_error(err: Error) -> ResponseStatus {

impl TestClient {
/// Creates a TestClient instance.
///
/// The implicit provider chosen for servicing cryptographic operations is decided through
/// a call to `list_providers`, followed by choosing the first non-Core provider.
pub fn new() -> TestClient {
let mut client = TestClient {
basic_client: BasicClient::new(AuthenticationData::AppIdentity(Secret::new(
String::from("root"),
))),
created_keys: Some(HashSet::new()),
};
let mut basic_client = BasicClient::new_naked();

let ipc_handler = unix_socket::Handler::new(TEST_SOCKET_PATH.into(), Some(TEST_TIMEOUT));
client.basic_client.set_ipc_handler(Box::from(ipc_handler));
basic_client.set_ipc_handler(Box::from(ipc_handler));
basic_client.set_timeout(Some(Duration::from_secs(10)));

let crypto_provider = client.find_crypto_provider();
client.set_provider(crypto_provider);
client
.basic_client
.set_timeout(Some(Duration::from_secs(10)));

client
}
basic_client.set_default_provider().unwrap();
basic_client
.set_default_auth(Some(String::from("root")))
.unwrap();

fn find_crypto_provider(&self) -> ProviderID {
let providers = self
.basic_client
.list_providers()
.expect("List providers failed");
for provider in providers {
if provider.id != ProviderID::Core {
return provider.id;
}
TestClient {
basic_client,
created_keys: Some(HashSet::new()),
}

ProviderID::Core
}

pub fn is_operation_supported(&mut self, op: Opcode) -> bool {
self.list_opcodes(self.provider().unwrap())
.unwrap()
.contains(&op)
self.list_opcodes(self.provider()).unwrap().contains(&op)
}

/// Manually set the provider to execute the requests.
Expand All @@ -101,22 +79,23 @@ impl TestClient {
}

/// Get client provider
pub fn provider(&self) -> Option<ProviderID> {
pub fn provider(&self) -> ProviderID {
self.basic_client.implicit_provider()
}

/// Set the client authentication string.
pub fn set_auth(&mut self, auth: String) {
self.basic_client
.set_auth_data(AuthenticationData::AppIdentity(Secret::new(auth)));
/// Set the client default authentication method
///
/// `auth` will get ignored if the default authenticator is not the Direct one.
pub fn set_default_auth(&mut self, auth: Option<String>) {
self.basic_client.set_default_auth(auth).unwrap();
}

/// Get client authentication string.
pub fn auth(&self) -> String {
if let AuthenticationData::AppIdentity(app_name) = self.basic_client.auth_data() {
app_name.expose_secret().to_string()
/// Get client application name if using direct authentication
pub fn get_direct_auth(&self) -> Option<String> {
if let Authentication::Direct(app_name) = self.basic_client.auth_data() {
Some(app_name)
} else {
panic!("Client should always be using AppIdentity-based authentication");
None
}
}

Expand All @@ -132,8 +111,8 @@ impl TestClient {
.psa_generate_key(key_name.clone(), attributes)
.map_err(convert_error)?;

let provider = self.provider().unwrap();
let auth = self.auth();
let provider = self.provider();
let auth = self.get_direct_auth();

if let Some(ref mut created_keys) = self.created_keys {
let _ = created_keys.insert((key_name, auth, provider));
Expand Down Expand Up @@ -427,8 +406,8 @@ impl TestClient {
.psa_import_key(key_name.clone(), &data, attributes)
.map_err(convert_error)?;

let provider = self.provider().unwrap();
let auth = self.auth();
let provider = self.provider();
let auth = self.get_direct_auth();

if let Some(ref mut created_keys) = self.created_keys {
let _ = created_keys.insert((key_name, auth, provider));
Expand Down Expand Up @@ -630,8 +609,8 @@ impl TestClient {
.psa_destroy_key(key_name.clone())
.map_err(convert_error)?;

let provider = self.provider().unwrap();
let auth = self.auth();
let provider = self.provider();
let auth = self.get_direct_auth();

if let Some(ref mut created_keys) = self.created_keys {
let _ = created_keys.remove(&(key_name, auth, provider));
Expand Down Expand Up @@ -927,7 +906,7 @@ impl Drop for TestClient {
if let Some(ref mut created_keys) = self.created_keys {
for (key_name, auth, provider) in created_keys.clone().iter() {
self.set_provider(*provider);
self.set_auth(auth.clone());
self.set_default_auth(auth.clone());
if self.destroy_key(key_name.clone()).is_err() {
error!("Failed to destroy key '{}'", key_name);
}
Expand Down
2 changes: 1 addition & 1 deletion e2e_tests/src/stress.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ impl StressTestWorker {
// Create unique client auth
let auth = generate_string(10);
info!("Worker with auth `{}` starting.", auth);
client.set_auth(auth);
client.set_default_auth(Some(auth));

// Create sign/verify key
let sign_key_name = generate_string(10);
Expand Down
1 change: 1 addition & 0 deletions e2e_tests/tests/all_providers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@

mod config;
mod cross;
mod multitenancy;
mod normal;
69 changes: 69 additions & 0 deletions e2e_tests/tests/all_providers/multitenancy.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright 2020 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0
use e2e_tests::TestClient;
use parsec_client::core::interface::requests::{ProviderID, ResponseStatus};

// These tests are executed by different users in the following order:
// 1. client1_before is executed as parsec-client-1
// 2. client2 is executed as parsec-client-2
// 3. client1_after is executed as parsec-client-1
//
// They are executed against all possible authenticators in Parsec.

#[test]
fn client1_before() {
// Create one key on each provider
let mut client = TestClient::new();
client.do_not_destroy_keys();
client.set_default_auth(Some("client1".to_string()));

let key = String::from("multitenant");

for provider in [ProviderID::MbedCrypto, ProviderID::Pkcs11, ProviderID::Tpm].iter() {
client.set_provider(*provider);
client.generate_rsa_sign_key(key.clone()).unwrap();
}
}

#[test]
fn client2() {
let mut client = TestClient::new();
client.set_default_auth(Some("client2".to_string()));

let key = String::from("multitenant");

// Try to list those keys
let keys = client.list_keys().unwrap();
assert!(keys.is_empty());

for provider in [ProviderID::MbedCrypto, ProviderID::Pkcs11, ProviderID::Tpm].iter() {
client.set_provider(*provider);
assert_eq!(
client.export_public_key(key.clone()).unwrap_err(),
ResponseStatus::PsaErrorDoesNotExist
);
assert_eq!(
client.destroy_key(key.clone()).unwrap_err(),
ResponseStatus::PsaErrorDoesNotExist
);
client.generate_rsa_sign_key(key.clone()).unwrap();
client.destroy_key(key.clone()).unwrap();
}
}

#[test]
fn client1_after() {
let mut client = TestClient::new();
client.set_default_auth(Some("client1".to_string()));

// Verify all keys are still there and can be used
let keys = client.list_keys().unwrap();
assert_eq!(keys.len(), 3);

// Destroy the keys
let key = String::from("multitenant");
for provider in [ProviderID::MbedCrypto, ProviderID::Pkcs11, ProviderID::Tpm].iter() {
client.set_provider(*provider);
client.destroy_key(key.clone()).unwrap();
}
}
2 changes: 1 addition & 1 deletion e2e_tests/tests/all_providers/normal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ fn sign_verify_with_provider_discovery() -> Result<()> {
#[test]
fn list_keys() {
let mut client = TestClient::new();
client.set_auth("list_keys test".to_string());
client.set_default_auth(Some("list_keys test".to_string()));

let keys = client.list_keys().expect("list_keys failed");

Expand Down
8 changes: 4 additions & 4 deletions e2e_tests/tests/per_provider/normal_tests/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ fn two_auths_same_key_name() -> Result<()> {
let auth1 = String::from("first_client");
let auth2 = String::from("second_client");

client.set_auth(auth1);
client.set_default_auth(Some(auth1));
client.generate_rsa_sign_key(key_name.clone())?;

client.set_auth(auth2);
client.set_default_auth(Some(auth2));
client.generate_rsa_sign_key(key_name)
}

Expand All @@ -25,10 +25,10 @@ fn delete_wrong_key() -> Result<()> {
let auth1 = String::from("first_client");
let auth2 = String::from("second_client");

client.set_auth(auth1);
client.set_default_auth(Some(auth1));
client.generate_rsa_sign_key(key_name.clone())?;

client.set_auth(auth2);
client.set_default_auth(Some(auth2));
let status = client
.destroy_key(key_name)
.expect_err("Destroying key should have failed");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ fn wrong_permitted_algorithm() {

// The Mbed Crypto provider currently does not support other algorithms than the RSA PKCS 1v15
// signing algorithm with hash when checking policies only.
if client.provider().unwrap() == ProviderID::MbedCrypto {
if client.provider() == ProviderID::MbedCrypto {
return;
}

Expand Down
2 changes: 1 addition & 1 deletion e2e_tests/tests/per_provider/persistent_after.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ fn reuse_to_sign() -> Result<()> {
fn should_have_been_deleted() {
let mut client = TestClient::new();

if client.provider().unwrap() == ProviderID::Tpm {
if client.provider() == ProviderID::Tpm {
// This test does not make sense for the TPM Provider.
return;
}
Expand Down

0 comments on commit 306c4fa

Please sign in to comment.