From 389cabb89ef6df3ebdc6986257d7f0527fe9bc31 Mon Sep 17 00:00:00 2001 From: Oleksandr Deundiak Date: Tue, 22 Aug 2023 20:45:17 +0200 Subject: [PATCH] Update `reference/libraries/rust/credentials.rs` to align with the new identity design --- reference/libraries/rust/credentials.md | 137 +++++++++++++++--------- 1 file changed, 89 insertions(+), 48 deletions(-) diff --git a/reference/libraries/rust/credentials.md b/reference/libraries/rust/credentials.md index d2e89d1d..3b6d0b49 100644 --- a/reference/libraries/rust/credentials.md +++ b/reference/libraries/rust/credentials.md @@ -45,26 +45,37 @@ In a later guide, we'll explore how Ockam enables you to define various pluggabl // examples/06-credentials-exchange-issuer.rs use ockam::access_control::AllowAll; use ockam::access_control::IdentityIdAccessControl; -use ockam::identity::CredentialsIssuer; -use ockam::identity::SecureChannelListenerOptions; -use ockam::TcpTransportExtension; -use ockam::{node, Context, Result, TcpListenerOptions}; +use ockam::identity::{CredentialsIssuer, SecureChannelListenerOptions, Vault}; +use ockam::vault::{Secret, SecretAttributes, SoftwareSigningVault}; +use ockam::{Context, Result, TcpListenerOptions}; +use ockam::{Node, TcpTransportExtension}; #[ockam::node] async fn main(ctx: Context) -> Result<()> { - // Create a node with default implementations - let node = node(ctx); + let identity_vault = SoftwareSigningVault::create(); + // Import the signing secret key to the Vault + let secret = identity_vault + .import_key( + Secret::new(hex::decode("0127359911708ef4de9adaaf27c357501473c4a10a5326a69c1f7f874a0cd82e").unwrap()), + SecretAttributes::Ed25519, + ) + .await?; + + // Create a default Vault but use the signing vault with our secret in it + let mut vault = Vault::create(); + vault.identity_vault = identity_vault; + + let node = Node::builder().with_vault(vault).build(ctx).await?; - let issuer_identity = "0180370b91c5d0aa4af34580a9ab4b8fb2a28351bed061525c96b4f07e75c0ee18000547c93239ba3d818ec26c9cdadd2a35cbdf1fa3b6d1a731e06164b1079fb7b8084f434b414d5f524b03012000000020236f79490d3f683e0c3bf458a7381c366c99a8f2b2ac406db1ef8c130111f12703010140b23fddceb11cea25602aa681b6ef6abda036722c27a6dee291f1d6b2234a127af21cc79de2252201f27e7e34e0bf5064adbf3d01eb355aff4bf5c90b8f1fd80a"; - let secret = "9278735d525efceef16bfd9143d3534759f3d388e460e6002134b9541e06489f"; - let issuer = node.import_private_identity(issuer_identity, secret).await?; + let issuer_identity = hex::decode("81a201583ba20101025835a4028201815820afbca9cf5d440147450f9f0d0a038a337b3fe5c17086163f2c54509558b62ef403f4041a64dd404a051a77a9434a0282018158407754214545cda6e7ff49136f67c9c7973ec309ca4087360a9f844aac961f8afe3f579a72c0c9530f3ff210f02b7c5f56e96ce12ee256b01d7628519800723805").unwrap(); + let issuer = node.import_private_identity(&issuer_identity, &secret).await?; println!("issuer identifier {}", issuer.identifier()); // Tell the credential issuer about a set of public identifiers that are // known, in advance, to be members of the production cluster. let known_identifiers = vec![ - "Pe92f183eb4c324804ef4d62962dea94cf095a265d4d28500c34e1a4e0d5ef638".try_into()?, - "Pada09e0f96e56580f6a0cb54f55ecbde6c973db6732e30dfb39b178760aed041".try_into()?, + "I6342c580429b9a0733880bea4fa18f8055871130".try_into()?, // Client Identifier + "I2c3b0ef15c12fe43d405497fcfc46318da46d0f5".try_into()?, // Server Identifier ]; // Tell this credential issuer about the attributes to include in credentials @@ -77,12 +88,17 @@ async fn main(ctx: Context) -> Result<()> { // // For a different application this attested attribute set can be different and // distinct for each identifier, but for this example we'll keep things simple. - let credential_issuer = - CredentialsIssuer::new(node.identities(), issuer.identifier(), "trust_context".into()).await?; + let credential_issuer = CredentialsIssuer::new( + node.identities().repository(), + node.credentials(), + issuer.identifier(), + "trust_context".into(), + ) + .await?; for identifier in known_identifiers.iter() { node.identities() .repository() - .put_attribute_value(identifier, "cluster", "production") + .put_attribute_value(identifier, b"cluster".to_vec(), b"production".to_vec()) .await?; } @@ -94,7 +110,7 @@ async fn main(ctx: Context) -> Result<()> { // Start a secure channel listener that only allows channels where the identity // at the other end of the channel can authenticate with the latest private key // corresponding to one of the above known public identifiers. - node.create_secure_channel_listener(&issuer.identifier(), "secure", sc_listener_options) + node.create_secure_channel_listener(issuer.identifier(), "secure", sc_listener_options) .await?; // Start a credential issuer worker that will only accept incoming requests from @@ -136,27 +152,40 @@ use hello_ockam::Echoer; use ockam::abac::AbacAccessControl; use ockam::access_control::AllowAll; use ockam::identity::{ - AuthorityService, CredentialsIssuerClient, SecureChannelListenerOptions, SecureChannelOptions, TrustContext, + AuthorityService, CredentialsIssuerClient, SecureChannelListenerOptions, SecureChannelOptions, TrustContext, Vault, }; -use ockam::TcpTransportExtension; -use ockam::{node, route, Context, Result, TcpConnectionOptions, TcpListenerOptions}; +use ockam::vault::{Secret, SecretAttributes, SoftwareSigningVault}; +use ockam::{route, Context, Result, TcpConnectionOptions, TcpListenerOptions}; +use ockam::{Node, TcpTransportExtension}; #[ockam::node] async fn main(ctx: Context) -> Result<()> { - // Create a node with default implementations - let node = node(ctx); + let identity_vault = SoftwareSigningVault::create(); + // Import the signing secret key to the Vault + let secret = identity_vault + .import_key( + Secret::new(hex::decode("5FB3663DF8405379981462BABED7507E3D53A8D061188105E3ADBD70E0A74B8A").unwrap()), + SecretAttributes::Ed25519, + ) + .await?; + + // Create a default Vault but use the signing vault with our secret in it + let mut vault = Vault::create(); + vault.identity_vault = identity_vault; + + let node = Node::builder().with_vault(vault).build(ctx).await?; + // Initialize the TCP Transport let tcp = node.create_tcp_transport().await?; // Create an Identity representing the server // Load an identity corresponding to the following public identifier - // Pe92f183eb4c324804ef4d62962dea94cf095a265d4d28500c34e1a4e0d5ef638 + // I2c3b0ef15c12fe43d405497fcfc46318da46d0f5 // // We're hard coding this specific identity because its public identifier is known // to the credential issuer as a member of the production cluster. - let change_history = "01ed8a5b1303f975c1296c990d1bd3c1946cfef328de20531e3511ec5604ce0dd9000547c93239ba3d818ec26c9cdadd2a35cbdf1fa3b6d1a731e06164b1079fb7b8084f434b414d5f524b03012000000020e8c328bc0cc07a374762091d037e69c36fdd4d2e1a651abd4d43a1362d3f800503010140a349968063d7337d0c965969fa9c640824c01a6d37fe130d4ab963b0271b9d5bbf0923faa5e27f15359554f94f08676df01b99d997944e4feaf0caaa1189480e"; - let secret = "5b2b3f2abbd1787704d8f8b363529f8e2d8f423b6dd4b96a2c462e4f0e04ee18"; - let server = node.import_private_identity(change_history, secret).await?; + let change_history = hex::decode("81a201583ba20101025835a40282018158201d387ce453816d91159740a55e9a62ad3b58be9ecf7ef08760c42c0d885b6c2e03f4041a64dd4074051a77a9437402820181584053de69d82c9c4b12476c889b437be1d9d33bd0041655c4836a3a57ac5a67703e7f500af5bacaed291cfd6783d255fe0f0606638577d087a5612bfb4671f2b70a").unwrap(); + let server = node.import_private_identity(&change_history, &secret).await?; // Connect with the credential issuer and authenticate using the latest private // key of this program's hardcoded identity. @@ -167,7 +196,7 @@ async fn main(ctx: Context) -> Result<()> { let issuer_connection = tcp.connect("127.0.0.1:5000", TcpConnectionOptions::new()).await?; let issuer_channel = node .create_secure_channel( - &server.identifier(), + server.identifier(), route![issuer_connection, "secure"], SecureChannelOptions::new(), ) @@ -175,24 +204,23 @@ async fn main(ctx: Context) -> Result<()> { let issuer_client = CredentialsIssuerClient::new(route![issuer_channel, "issuer"], node.context()).await?; let credential = issuer_client.credential().await?; - println!("Credential:\n{credential}"); // Verify that the received credential has indeed be signed by the issuer. // The issuer identity must be provided out-of-band from a trusted source // and match the identity used to start the issuer node - let issuer_identity = "0180370b91c5d0aa4af34580a9ab4b8fb2a28351bed061525c96b4f07e75c0ee18000547c93239ba3d818ec26c9cdadd2a35cbdf1fa3b6d1a731e06164b1079fb7b8084f434b414d5f524b03012000000020236f79490d3f683e0c3bf458a7381c366c99a8f2b2ac406db1ef8c130111f12703010140b23fddceb11cea25602aa681b6ef6abda036722c27a6dee291f1d6b2234a127af21cc79de2252201f27e7e34e0bf5064adbf3d01eb355aff4bf5c90b8f1fd80a"; + let issuer_identity = "81a201583ba20101025835a4028201815820afbca9cf5d440147450f9f0d0a038a337b3fe5c17086163f2c54509558b62ef403f4041a64dd404a051a77a9434a0282018158407754214545cda6e7ff49136f67c9c7973ec309ca4087360a9f844aac961f8afe3f579a72c0c9530f3ff210f02b7c5f56e96ce12ee256b01d7628519800723805"; let issuer = node.import_identity_hex(issuer_identity).await?; node.credentials() - .verify_credential(&server.identifier(), &[issuer.clone()], credential.clone()) + .credentials_verification() + .verify_credential(Some(server.identifier()), &[issuer.identifier().clone()], &credential) .await?; // Create a trust context that will be used to authenticate credential exchanges let trust_context = TrustContext::new( "trust_context_id".to_string(), Some(AuthorityService::new( - node.identities().identities_reader(), node.credentials(), - issuer.identifier(), + issuer.identifier().clone(), None, )), ); @@ -209,13 +237,13 @@ async fn main(ctx: Context) -> Result<()> { node.flow_controls() .add_consumer("echoer", &sc_listener_options.spawner_flow_control_id()); - let allow_production = AbacAccessControl::create(node.repository(), "cluster", "production"); + let allow_production = AbacAccessControl::create(node.identities_repository(), "cluster", "production"); node.start_worker_with_access_control("echoer", Echoer, allow_production, AllowAll) .await?; // Start a secure channel listener that only allows channels with // authenticated identities. - node.create_secure_channel_listener(&server.identifier(), "secure", sc_listener_options) + node.create_secure_channel_listener(server.identifier(), "secure", sc_listener_options) .await?; // Create a TCP listener and wait for incoming connections @@ -242,26 +270,40 @@ touch examples/06-credential-exchange-client.rs {% code lineNumbers="true" %} ```rust // examples/06-credentials-exchange-client.rs -use ockam::identity::{AuthorityService, CredentialsIssuerClient, SecureChannelOptions, TrustContext}; -use ockam::TcpTransportExtension; -use ockam::{node, route, Context, Result, TcpConnectionOptions}; +use ockam::identity::{AuthorityService, CredentialsIssuerClient, SecureChannelOptions, TrustContext, Vault}; +use ockam::vault::{Secret, SecretAttributes, SoftwareSigningVault}; +use ockam::{route, Context, Result, TcpConnectionOptions}; +use ockam::{Node, TcpTransportExtension}; #[ockam::node] async fn main(ctx: Context) -> Result<()> { - // Create a node with default implementations - let mut node = node(ctx); + let identity_vault = SoftwareSigningVault::create(); + // Import the signing secret key to the Vault + let secret = identity_vault + .import_key( + Secret::new(hex::decode("31FF4E1CD55F17735A633FBAB4B838CF88D1252D164735CB3185A6E315438C2C").unwrap()), + SecretAttributes::Ed25519, + ) + .await?; + + // Create a default Vault but use the signing vault with our secret in it + let mut vault = Vault::create(); + vault.identity_vault = identity_vault; + + let mut node = Node::builder().with_vault(vault).build(ctx).await?; // Initialize the TCP Transport let tcp = node.create_tcp_transport().await?; // Create an Identity representing the client // We preload the client vault with a change history and secret key corresponding to the identity identifier - // Pe92f183eb4c324804ef4d62962dea94cf095a265d4d28500c34e1a4e0d5ef638 + // I6342c580429b9a0733880bea4fa18f8055871130 // which is an identifier known to the credential issuer, with some preset attributes + // // We're hard coding this specific identity because its public identifier is known // to the credential issuer as a member of the production cluster. - let change_history = "01dcf392551f796ef1bcb368177e53f9a5875a962f67279259207d24a01e690721000547c93239ba3d818ec26c9cdadd2a35cbdf1fa3b6d1a731e06164b1079fb7b8084f434b414d5f524b03012000000020a0d205f09cab9a9467591fcee560429aab1215d8136e5c985a6b7dc729e6f08203010140b098463a727454c0e5292390d8f4cbd4dd0cae5db95606832f3d0a138936487e1da1489c40d8a0995fce71cc1948c6bcfd67186467cdd78eab7e95c080141505"; - let secret = "41b6873b20d95567bf958e6bab2808e9157720040882630b1bb37a72f4015cd2"; - let client = node.import_private_identity(change_history, secret).await?; + let change_history = hex::decode("81a201583ba20101025835a4028201815820530d1c2e9822433b679a66a60b9c2ed47c370cd0ce51cbe1a7ad847b5835a96303f4041a64dd4060051a77a94360028201815840042fff8f6c80603fb1cec4a3cf1ff169ee36889d3ed76184fe1dfbd4b692b02892df9525c61c2f1286b829586d13d5abf7d18973141f734d71c1840520d40a0e").unwrap(); + let client = node.import_private_identity(&change_history, &secret).await?; + println!("issuer identifier {}", client.identifier()); // Connect with the credential issuer and authenticate using the latest private // key of this program's hardcoded identity. @@ -272,7 +314,7 @@ async fn main(ctx: Context) -> Result<()> { let issuer_connection = tcp.connect("127.0.0.1:5000", TcpConnectionOptions::new()).await?; let issuer_channel = node .create_secure_channel( - &client.identifier(), + client.identifier(), route![issuer_connection, "secure"], SecureChannelOptions::new(), ) @@ -280,24 +322,23 @@ async fn main(ctx: Context) -> Result<()> { let issuer_client = CredentialsIssuerClient::new(route![issuer_channel, "issuer"], node.context()).await?; let credential = issuer_client.credential().await?; - println!("Credential:\n{credential}"); // Verify that the received credential has indeed be signed by the issuer. // The issuer identity must be provided out-of-band from a trusted source // and match the identity used to start the issuer node - let issuer_identity = "0180370b91c5d0aa4af34580a9ab4b8fb2a28351bed061525c96b4f07e75c0ee18000547c93239ba3d818ec26c9cdadd2a35cbdf1fa3b6d1a731e06164b1079fb7b8084f434b414d5f524b03012000000020236f79490d3f683e0c3bf458a7381c366c99a8f2b2ac406db1ef8c130111f12703010140b23fddceb11cea25602aa681b6ef6abda036722c27a6dee291f1d6b2234a127af21cc79de2252201f27e7e34e0bf5064adbf3d01eb355aff4bf5c90b8f1fd80a"; + let issuer_identity = "81a201583ba20101025835a4028201815820afbca9cf5d440147450f9f0d0a038a337b3fe5c17086163f2c54509558b62ef403f4041a64dd404a051a77a9434a0282018158407754214545cda6e7ff49136f67c9c7973ec309ca4087360a9f844aac961f8afe3f579a72c0c9530f3ff210f02b7c5f56e96ce12ee256b01d7628519800723805"; let issuer = node.import_identity_hex(issuer_identity).await?; node.credentials() - .verify_credential(&client.identifier(), &[issuer.clone()], credential.clone()) + .credentials_verification() + .verify_credential(Some(client.identifier()), &[issuer.identifier().clone()], &credential) .await?; // Create a trust context that will be used to authenticate credential exchanges let trust_context = TrustContext::new( "trust_context_id".to_string(), Some(AuthorityService::new( - node.identities().identities_reader(), node.credentials(), - issuer.identifier(), + issuer.identifier().clone(), None, )), ); @@ -306,7 +347,7 @@ async fn main(ctx: Context) -> Result<()> { let server_connection = tcp.connect("127.0.0.1:4000", TcpConnectionOptions::new()).await?; let channel = node .create_secure_channel( - &client.identifier(), + client.identifier(), route![server_connection, "secure"], SecureChannelOptions::new() .with_trust_context(trust_context)