Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Account credentials #7730

Merged
merged 8 commits into from
Mar 28, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,16 @@ 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 = CredentialIssuerWorker::new(members.clone(), node.credentials(), &issuer, None, None, None);
let credential_issuer = CredentialIssuerWorker::new(
members.clone(),
node.identities_attributes(),
node.credentials(),
&issuer,
"test".to_string(),
None,
None,
true,
);

let mut pre_trusted_identities = BTreeMap::<Identifier, PreTrustedIdentity>::new();
let attributes = PreTrustedIdentity::new(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use ockam::{node, Context, Result, TcpOutletOptions, TcpTransportExtension};
use ockam_api::authenticator::enrollment_tokens::TokenAcceptor;
use ockam_api::authenticator::one_time_code::OneTimeCode;
use ockam_api::nodes::NodeManager;
use ockam_api::{multiaddr_to_route, multiaddr_to_transport_route, DefaultAddress};
use ockam_api::{multiaddr_to_route, multiaddr_to_transport_route};
use ockam_core::AsyncTryClone;
use ockam_multiaddr::MultiAddr;

Expand Down Expand Up @@ -80,11 +80,11 @@ async fn start_node(ctx: Context, project_information_path: &str, token: OneTime
node.context().async_try_clone().await?,
Arc::new(tcp.clone()),
node.secure_channels(),
RemoteCredentialRetrieverInfo::new(
RemoteCredentialRetrieverInfo::create_for_project_member(
project.authority_identifier(),
project_authority_route,
DefaultAddress::CREDENTIAL_ISSUER.into(),
),
"test".to_string(),
));

// 3. create an access control policy checking the value of the "component" attribute of the caller
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use ockam::{route, Context, Result};
use ockam_api::authenticator::enrollment_tokens::TokenAcceptor;
use ockam_api::authenticator::one_time_code::OneTimeCode;
use ockam_api::nodes::NodeManager;
use ockam_api::{multiaddr_to_route, multiaddr_to_transport_route, DefaultAddress};
use ockam_api::{multiaddr_to_route, multiaddr_to_transport_route};
use ockam_core::compat::sync::Arc;
use ockam_core::AsyncTryClone;
use ockam_multiaddr::MultiAddr;
Expand Down Expand Up @@ -80,11 +80,11 @@ async fn start_node(ctx: Context, project_information_path: &str, token: OneTime
node.context().async_try_clone().await?,
Arc::new(tcp.clone()),
node.secure_channels(),
RemoteCredentialRetrieverInfo::new(
RemoteCredentialRetrieverInfo::create_for_project_member(
project.authority_identifier(),
project_authority_route,
DefaultAddress::CREDENTIAL_ISSUER.into(),
),
"test".to_string(),
));

// 3. create an access control policy checking the value of the "component" attribute of the caller
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::authenticator::direct::{OCKAM_ROLE_ATTRIBUTE_ENROLLER_VALUE, OCKAM_ROLE_ATTRIBUTE_KEY};
use crate::authenticator::AuthorityMembersRepository;
use ockam::identity::Identifier;
use ockam::identity::{Identifier, IdentitiesAttributes};
use ockam_core::Result;
use std::collections::BTreeMap;
use std::sync::Arc;
Expand Down Expand Up @@ -39,12 +39,11 @@ impl EnrollerAccessControlChecks {
false
}

pub(crate) async fn check_identifier(
pub(crate) async fn check_is_member(
members: Arc<dyn AuthorityMembersRepository>,
identifier: &Identifier,
account_authority: &Option<AccountAuthorityInfo>,
) -> Result<EnrollerCheckResult> {
let mut r = match members.get_member(identifier).await? {
let r = match members.get_member(identifier).await? {
Some(member) => {
let is_enroller = Self::check_bin_attributes_is_enroller(member.attributes());
EnrollerCheckResult {
Expand All @@ -61,9 +60,20 @@ impl EnrollerAccessControlChecks {
is_pre_trusted: false,
},
};

Ok(r)
}

pub(crate) async fn check_identifier(
members: Arc<dyn AuthorityMembersRepository>,
identities_attributes: Arc<IdentitiesAttributes>,
identifier: &Identifier,
account_authority: &Option<AccountAuthorityInfo>,
) -> Result<EnrollerCheckResult> {
let mut r = Self::check_is_member(members, identifier).await?;

if let Some(info) = account_authority {
if let Some(attrs) = info
.identities_attributes()
if let Some(attrs) = identities_attributes
.get_attributes(identifier, info.account_authority())
.await?
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::authenticator::direct::AccountAuthorityInfo;
use crate::authenticator::AuthorityMembersRepository;
use ockam::identity::models::{CredentialAndPurposeKey, CredentialSchemaIdentifier};
use ockam::identity::utils::AttributesBuilder;
use ockam::identity::{Attributes, Credentials, Identifier};
use ockam::identity::{Attributes, Credentials, Identifier, IdentitiesAttributes};
use ockam_core::compat::sync::Arc;
use ockam_core::Result;

Expand All @@ -20,6 +20,7 @@ pub const DEFAULT_CREDENTIAL_VALIDITY: Duration = Duration::from_secs(30 * 24 *
/// This struct runs as a Worker to issue credentials based on a request/response protocol
pub struct CredentialIssuer {
members: Arc<dyn AuthorityMembersRepository>,
identities_attributes: Arc<IdentitiesAttributes>,
credentials: Arc<Credentials>,
issuer: Identifier,
subject_attributes: Attributes,
Expand All @@ -30,17 +31,20 @@ pub struct CredentialIssuer {

impl CredentialIssuer {
/// Create a new credentials issuer
#[allow(clippy::too_many_arguments)]
#[instrument(skip_all, fields(issuer = %issuer, project_identifier = project_identifier.clone(), credential_ttl = credential_ttl.map_or("n/a".to_string(), |d| d.as_secs().to_string())))]
pub fn new(
members: Arc<dyn AuthorityMembersRepository>,
identities_attributes: Arc<IdentitiesAttributes>,
credentials: Arc<Credentials>,
issuer: &Identifier,
project_identifier: Option<String>, // Legacy value, should be removed when all clients are updated to the latest version
project_identifier: String,
credential_ttl: Option<Duration>,
account_authority: Option<AccountAuthorityInfo>,
disable_trust_context_id: bool,
) -> Self {
let subject_attributes = AttributesBuilder::with_schema(PROJECT_MEMBER_SCHEMA);
let subject_attributes = if let Some(project_identifier) = project_identifier {
let subject_attributes = if !disable_trust_context_id {
// Legacy value, should be removed when all clients are updated to the latest version
subject_attributes.with_attribute(
TRUST_CONTEXT_ID.to_vec(),
Expand All @@ -53,6 +57,7 @@ impl CredentialIssuer {

Self {
members,
identities_attributes,
credentials,
issuer: issuer.clone(),
subject_attributes,
Expand All @@ -68,8 +73,8 @@ impl CredentialIssuer {
) -> Result<Option<CredentialAndPurposeKey>> {
// Check if it has a valid project admin credential
if let Some(info) = self.account_authority.as_ref() {
if let Some(attrs) = info
.identities_attributes()
if let Some(attrs) = self
.identities_attributes
.get_attributes(subject, info.account_authority())
.await?
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ use tracing::trace;
use crate::authenticator::credential_issuer::CredentialIssuer;
use crate::authenticator::direct::AccountAuthorityInfo;
use crate::authenticator::AuthorityMembersRepository;
use ockam::identity::{Credentials, Identifier, IdentitySecureChannelLocalInfo};
use ockam::identity::{
Credentials, Identifier, IdentitiesAttributes, IdentitySecureChannelLocalInfo,
};
use ockam_core::api::{Method, RequestHeader, Response};
use ockam_core::compat::boxed::Box;
use ockam_core::compat::sync::Arc;
Expand All @@ -20,22 +22,27 @@ pub struct CredentialIssuerWorker {

impl CredentialIssuerWorker {
/// Create a new credentials issuer
#[allow(clippy::too_many_arguments)]
pub fn new(
members: Arc<dyn AuthorityMembersRepository>,
identities_attributes: Arc<IdentitiesAttributes>,
credentials: Arc<Credentials>,
issuer: &Identifier,
project_identifier: Option<String>, // Legacy value, should be removed when all clients are updated to the latest version
project_identifier: String,
credential_ttl: Option<Duration>,
account_authority: Option<AccountAuthorityInfo>,
disable_trust_context_id: bool,
) -> Self {
Self {
credential_issuer: CredentialIssuer::new(
members,
identities_attributes,
credentials,
issuer,
project_identifier,
credential_ttl,
account_authority,
disable_trust_context_id,
),
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use either::Either;
use ockam::identity::IdentitiesAttributes;
use std::collections::{BTreeMap, HashMap};

use ockam::identity::utils::now;
use ockam::identity::AttributesEntry;
use ockam::identity::Identifier;
use ockam::identity::{AttributesEntry, IdentitiesAttributes};
use ockam_core::compat::sync::Arc;
use ockam_core::Result;

Expand All @@ -24,34 +23,29 @@ pub type DirectAuthenticatorResult<T> = Either<T, DirectAuthenticatorError>;

pub struct DirectAuthenticator {
members: Arc<dyn AuthorityMembersRepository>,
identities_attributes: Arc<IdentitiesAttributes>,
account_authority: Option<AccountAuthorityInfo>,
}
#[derive(Clone)]
pub struct AccountAuthorityInfo {
identities_attributes: Arc<IdentitiesAttributes>,
account_authority: Identifier,
project_identifier: String,
enforce_admin_checks: bool,
}

impl AccountAuthorityInfo {
pub fn new(
identities_attributes: Arc<IdentitiesAttributes>,
account_authority: Identifier,
project_identifier: String,
enforce_admin_checks: bool,
) -> Self {
Self {
identities_attributes,
account_authority,
project_identifier,
enforce_admin_checks,
}
}

pub fn identities_attributes(&self) -> Arc<IdentitiesAttributes> {
self.identities_attributes.clone()
}
pub fn account_authority(&self) -> &Identifier {
&self.account_authority
}
Expand All @@ -66,10 +60,12 @@ impl AccountAuthorityInfo {
impl DirectAuthenticator {
pub fn new(
members: Arc<dyn AuthorityMembersRepository>,
identities_attributes: Arc<IdentitiesAttributes>,
account_authority: Option<AccountAuthorityInfo>,
) -> Self {
Self {
members,
identities_attributes,
account_authority,
}
}
Expand All @@ -83,6 +79,7 @@ impl DirectAuthenticator {
) -> Result<DirectAuthenticatorResult<()>> {
let check = EnrollerAccessControlChecks::check_identifier(
self.members.clone(),
self.identities_attributes.clone(),
enroller,
&self.account_authority,
)
Expand Down Expand Up @@ -143,6 +140,7 @@ impl DirectAuthenticator {
) -> Result<DirectAuthenticatorResult<HashMap<Identifier, AttributesEntry>>> {
let check = EnrollerAccessControlChecks::check_identifier(
self.members.clone(),
self.identities_attributes.clone(),
enroller,
&self.account_authority,
)
Expand Down Expand Up @@ -179,6 +177,7 @@ impl DirectAuthenticator {
) -> Result<DirectAuthenticatorResult<()>> {
let check_enroller = EnrollerAccessControlChecks::check_identifier(
self.members.clone(),
self.identities_attributes.clone(),
enroller,
&self.account_authority,
)
Expand All @@ -196,6 +195,7 @@ impl DirectAuthenticator {

let check_member = EnrollerAccessControlChecks::check_identifier(
self.members.clone(),
self.identities_attributes.clone(),
identifier,
&self.account_authority,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use either::Either;
use minicbor::Decoder;
use tracing::trace;

use ockam::identity::{Identifier, IdentitySecureChannelLocalInfo};
use ockam::identity::{Identifier, IdentitiesAttributes, IdentitySecureChannelLocalInfo};
use ockam_core::api::{Method, RequestHeader, Response};
use ockam_core::compat::sync::Arc;
use ockam_core::{Result, Routed, Worker};
Expand All @@ -21,10 +21,15 @@ pub struct DirectAuthenticatorWorker {
impl DirectAuthenticatorWorker {
pub fn new(
members: Arc<dyn AuthorityMembersRepository>,
identities_attributes: Arc<IdentitiesAttributes>,
account_authority: Option<AccountAuthorityInfo>,
) -> Self {
Self {
authenticator: DirectAuthenticator::new(members, account_authority),
authenticator: DirectAuthenticator::new(
members,
identities_attributes,
account_authority,
),
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@ impl EnrollmentTokenAcceptor {
from: &Identifier,
) -> Result<EnrollmentTokenAcceptorResult<()>> {
let check =
EnrollerAccessControlChecks::check_identifier(self.members.clone(), from, &None)
.await?;
EnrollerAccessControlChecks::check_is_member(self.members.clone(), from).await?;

// Not allow updating existing members
if check.is_member {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use rand::Rng;
use std::collections::BTreeMap;

use ockam::identity::utils::now;
use ockam::identity::Identifier;
use ockam::identity::{Identifier, IdentitiesAttributes};
use ockam_core::compat::sync::Arc;
use ockam_core::compat::time::Duration;
use ockam_core::Result;
Expand All @@ -25,18 +25,21 @@ pub type EnrollmentTokenIssuerResult<T> = Either<T, EnrollmentTokenIssuerError>;
pub struct EnrollmentTokenIssuer {
pub(super) tokens: Arc<dyn AuthorityEnrollmentTokenRepository>,
pub(super) members: Arc<dyn AuthorityMembersRepository>,
pub(super) identities_attributes: Arc<IdentitiesAttributes>,
pub(super) account_authority: Option<AccountAuthorityInfo>,
}

impl EnrollmentTokenIssuer {
pub fn new(
tokens: Arc<dyn AuthorityEnrollmentTokenRepository>,
members: Arc<dyn AuthorityMembersRepository>,
identities_attributes: Arc<IdentitiesAttributes>,
account_authority: Option<AccountAuthorityInfo>,
) -> Self {
Self {
tokens,
members,
identities_attributes,
account_authority,
}
}
Expand All @@ -51,6 +54,7 @@ impl EnrollmentTokenIssuer {
) -> Result<EnrollmentTokenIssuerResult<OneTimeCode>> {
let check = EnrollerAccessControlChecks::check_identifier(
self.members.clone(),
self.identities_attributes.clone(),
enroller,
&self.account_authority,
)
Expand Down
Loading
Loading