use ockam::identity::utils::now;
use ockam::identity::{secure_channels, AttributesEntry, Identifier, SecureChannels};
use ockam::AsyncTryClone;
use ockam_api::authenticator::enrollment_tokens::Members;
use ockam_api::authority_node;
use ockam_api::authority_node::{Authority, Configuration};
use ockam_api::bootstrapped_identities_store::PreTrustedIdentities;
use ockam_api::cloud::AuthorityNode;
use ockam_api::config::lookup::InternetAddress;
use ockam_api::nodes::service::default_address::DefaultAddress;
use ockam_api::nodes::NodeManager;
use ockam_core::{Address, Result};
use ockam_multiaddr::MultiAddr;
use ockam_node::Context;
use ockam_transport_tcp::TcpTransport;
use rand::{thread_rng, Rng};
use std::collections::BTreeMap;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::time::Duration;
use tempfile::NamedTempFile;
#[ockam_macros::test]
async fn authority_starts_with_default_configuration(ctx: &mut Context) -> Result<()> {
let configuration = default_configuration().await?;
authority_node::start_node(ctx, &configuration).await?;
let workers = ctx.list_workers().await?;
assert!(!workers.contains(&Address::from(DefaultAddress::DIRECT_AUTHENTICATOR)));
ctx.stop().await?;
Ok(())
}
#[ockam_macros::test]
async fn controlling_authority_by_member_times_out(ctx: &mut Context) -> Result<()> {
use std::collections::HashMap;
let secure_channels = secure_channels().await?;
let admins = setup(ctx, secure_channels.clone(), 1).await?;
let admin = &admins[0];
let member = secure_channels
.identities()
.identities_creation()
.create_identity()
.await?;
let mut attributes = HashMap::<&str, &str>::default();
attributes.insert("key", "value");
admin
.client
.add_member(ctx, member.clone(), attributes)
.await
.unwrap();
let authority_node = NodeManager::authority_node(
&TcpTransport::create(ctx).await?,
secure_channels.clone(),
&admin.identifier,
&MultiAddr::try_from("/secure/api")?,
&member,
)
.await?;
let timeout = Arc::new(AtomicBool::new(true));
let timeout_clone = timeout.clone();
let ctx_clone = ctx.async_try_clone().await?;
ctx.runtime().spawn(async move {
let _ = authority_node.list_member_ids(&ctx_clone).await;
timeout_clone.store(false, Ordering::Relaxed)
});
ctx.sleep(Duration::from_millis(50)).await;
assert!(timeout.load(Ordering::Relaxed));
ctx.stop().await?;
Ok(())
}
#[ockam_macros::test]
async fn one_admin_test_api(ctx: &mut Context) -> Result<()> {
let secure_channels = secure_channels().await?;
let admins = setup(ctx, secure_channels.clone(), 1).await?;
let admin = &admins[0];
let now = now()?;
let members = admin.client.list_member_ids(ctx).await.unwrap();
assert_eq!(members.len(), 1);
assert_eq!(members[0], admin.identifier);
let members = admin.client.list_members(ctx).await.unwrap();
assert_eq!(members.len(), 1);
let attrs = members.get(&admin.identifier).unwrap();
assert!(attrs.added().abs_diff(now) < 5.into());
assert!(attrs.expires().is_none());
assert!(attrs.attested_by().is_none());
admin
.client
.delete_member(ctx, admin.identifier.clone())
.await
.unwrap();
let members = admin.client.list_member_ids(ctx).await.unwrap();
assert_eq!(members.len(), 1);
assert_eq!(members[0], admin.identifier);
ctx.stop().await?;
Ok(())
}
#[ockam_macros::test]
async fn test_one_admin_one_member(ctx: &mut Context) -> Result<()> {
use std::collections::HashMap;
let secure_channels = secure_channels().await?;
let admins = setup(ctx, secure_channels.clone(), 1).await?;
let admin = &admins[0];
let now = now()?;
let member = secure_channels
.identities()
.identities_creation()
.create_identity()
.await?;
let mut attributes = HashMap::<&str, &str>::default();
attributes.insert("key", "value");
admin
.client
.add_member(ctx, member.clone(), attributes)
.await
.unwrap();
let members = admin.client.list_member_ids(ctx).await.unwrap();
assert_eq!(members.len(), 2);
assert!(members.contains(&admin.identifier));
assert!(members.contains(&member));
let members = admin.client.list_members(ctx).await.unwrap();
assert_eq!(members.len(), 2);
assert!(members.get(&admin.identifier).is_some());
let attrs = members.get(&member).unwrap();
assert_eq!(attrs.attrs().len(), 2);
assert_eq!(
attrs.attrs().get("trust_context_id".as_bytes()),
Some(&b"123456".to_vec())
);
assert_eq!(
attrs.attrs().get("key".as_bytes()),
Some(&b"value".to_vec())
);
assert!(attrs.added().abs_diff(now) < 5.into());
assert!(attrs.expires().is_none());
assert_eq!(attrs.attested_by(), Some(admin.identifier.clone()));
admin
.client
.delete_member(ctx, member.clone())
.await
.unwrap();
let members = admin.client.list_member_ids(ctx).await.unwrap();
assert_eq!(members.len(), 1);
assert_eq!(members[0], admin.identifier);
let members = admin.client.list_members(ctx).await.unwrap();
assert_eq!(members.len(), 1);
assert!(members.get(&admin.identifier).is_some());
ctx.stop().await?;
Ok(())
}
#[ockam_macros::test]
async fn two_admins_two_members_exist_in_one_global_scope(ctx: &mut Context) -> Result<()> {
use std::collections::HashMap;
let secure_channels = secure_channels().await?;
let admins = setup(ctx, secure_channels.clone(), 2).await?;
let admin1 = &admins[0];
let admin2 = &admins[1];
let member1 = secure_channels
.identities()
.identities_creation()
.create_identity()
.await?;
let member2 = secure_channels
.identities()
.identities_creation()
.create_identity()
.await?;
let mut attributes1 = HashMap::<&str, &str>::default();
attributes1.insert("key1", "value1");
let mut attributes2 = HashMap::<&str, &str>::default();
attributes2.insert("key2", "value2");
let now = now()?;
admin1
.client
.add_member(ctx, member1.clone(), attributes1)
.await
.unwrap();
admin2
.client
.add_member(ctx, member2.clone(), attributes2)
.await
.unwrap();
let mut members1 = admin1.client.list_member_ids(ctx).await.unwrap();
let mut members2 = admin2.client.list_member_ids(ctx).await.unwrap();
members1.sort();
members2.sort();
assert_eq!(members1, members2);
assert_eq!(members1.len(), 4);
assert!(members1.contains(&member1));
assert!(members1.contains(&member2));
assert!(members1.contains(&admin1.identifier));
assert!(members1.contains(&admin2.identifier));
let members1 = admin1.client.list_members(ctx).await.unwrap();
let members2 = admin2.client.list_members(ctx).await.unwrap();
assert_eq!(members1, members2);
assert_eq!(members1.len(), 4);
assert!(members1.get(&admin1.identifier).is_some());
assert!(members1.get(&admin2.identifier).is_some());
let attrs = members1.get(&member1).unwrap();
assert_eq!(attrs.attrs().len(), 2);
assert_eq!(
attrs.attrs().get("trust_context_id".as_bytes()),
Some(&b"123456".to_vec())
);
assert_eq!(
attrs.attrs().get("key1".as_bytes()),
Some(&b"value1".to_vec())
);
assert!(attrs.added().abs_diff(now) < 5.into());
assert!(attrs.expires().is_none());
assert_eq!(attrs.attested_by(), Some(admin1.identifier.clone()));
let attrs = members1.get(&member2).unwrap();
assert_eq!(attrs.attrs().len(), 2);
assert_eq!(
attrs.attrs().get("trust_context_id".as_bytes()),
Some(&b"123456".to_vec())
);
assert_eq!(
attrs.attrs().get("key2".as_bytes()),
Some(&b"value2".to_vec())
);
assert!(attrs.added().abs_diff(now) < 5.into());
assert!(attrs.expires().is_none());
assert_eq!(attrs.attested_by(), Some(admin2.identifier.clone()));
admin1
.client
.delete_member(ctx, member2.clone())
.await
.unwrap();
admin2
.client
.delete_member(ctx, member1.clone())
.await
.unwrap();
let mut members1 = admin1.client.list_member_ids(ctx).await.unwrap();
let mut members2 = admin2.client.list_member_ids(ctx).await.unwrap();
members1.sort();
members2.sort();
assert_eq!(members1, members2);
assert_eq!(members1.len(), 2);
assert!(members1.contains(&admin1.identifier));
assert!(members1.contains(&admin2.identifier));
let members1 = admin1.client.list_members(ctx).await.unwrap();
let members2 = admin2.client.list_members(ctx).await.unwrap();
assert_eq!(members1, members2);
assert_eq!(members1.len(), 2);
assert!(members1.get(&admin1.identifier).is_some());
assert!(members1.get(&admin2.identifier).is_some());
ctx.stop().await?;
Ok(())
}
async fn default_configuration() -> Result<Configuration> {
let storage_path = NamedTempFile::new().unwrap().keep().unwrap().1;
let port = thread_rng().gen_range(10000..65535);
let trusted_identities =
"{\"I3bab350b6c9ad9c624e54dba4b2e53b2ed95967ba1b2c3d4e5f6a6b5c4d3e2f1\": {\"attribute1\": \"value1\"}}";
let trusted_identities = PreTrustedIdentities::new_from_string(trusted_identities)?;
let mut configuration = authority_node::Configuration {
identifier: "I4dba4b2e53b2ed95967b3bab350b6c9ad9c624e5a1b2c3d4e5f6a6b5c4d3e2f1"
.try_into()?,
database_path: storage_path,
project_identifier: "123456".to_string(),
tcp_listener_address: InternetAddress::new(&format!("127.0.0.1:{}", port)).unwrap(),
secure_channel_listener_name: None,
authenticator_name: None,
trusted_identities,
no_direct_authentication: true,
no_token_enrollment: true,
okta: None,
};
let authority_sc_temp = Authority::create(&configuration).await?.secure_channels();
let authority_identifier = authority_sc_temp
.identities()
.identities_creation()
.create_identity()
.await?;
configuration.identifier = authority_identifier;
Ok(configuration)
}
struct Admin {
identifier: Identifier,
client: AuthorityNode,
}
async fn setup(
ctx: &Context,
secure_channels: Arc<SecureChannels>,
number_of_admins: usize,
) -> Result<Vec<Admin>> {
use ockam_core::compat::collections::HashMap;
let now = now()?;
let mut admin_ids = vec![];
let mut trusted_identities = HashMap::<Identifier, AttributesEntry>::new();
let mut attrs = BTreeMap::<Vec<u8>, Vec<u8>>::new();
attrs.insert(b"ockam-role".to_vec(), b"enroller".to_vec());
attrs.insert(b"trust_context_id".to_vec(), b"123456".to_vec());
for _ in 0..number_of_admins {
let admin = secure_channels
.identities()
.identities_creation()
.create_identity()
.await?;
let entry = AttributesEntry::new(attrs.clone(), now, None, None);
trusted_identities.insert(admin.clone(), entry);
admin_ids.push(admin);
}
let mut configuration = default_configuration().await?;
configuration.no_direct_authentication = false;
configuration.trusted_identities = PreTrustedIdentities::Fixed(trusted_identities);
authority_node::start_node(ctx, &configuration).await?;
let mut admins = vec![];
for admin_id in admin_ids {
let authority_node = NodeManager::authority_node(
&TcpTransport::create(ctx).await?,
secure_channels.clone(),
&configuration.identifier,
&MultiAddr::try_from("/secure/api")?,
&admin_id,
)
.await?;
admins.push(Admin {
identifier: admin_id,
client: authority_node,
});
}
Ok(admins)
}