Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/api/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,8 @@ pub trait QueryParameterPagination {
fn set_marker(&mut self, marker: String) -> &mut Self;
}

/// Trait for the resource to expose the unique identifier that can be used for building the
/// marker pagination.
/// Trait for the resource to expose the unique identifier that can be used for
/// building the marker pagination.
pub trait ResourceIdentifier {
/// Get the unique resource identifier.
fn get_id(&self) -> String;
Expand Down
15 changes: 15 additions & 0 deletions src/api/v3/auth/token/token_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,21 @@ impl Token {
);
}
}
ProviderToken::Trust(token) => {
if project.is_none() {
project = Some(
state
.provider
.get_resource_provider()
.get_project(state, &token.project_id)
.await?
.ok_or_else(|| KeystoneApiError::NotFound {
resource: "project".into(),
identifier: token.project_id.clone(),
})?,
);
}
}
}

if let Some(domain) = domain {
Expand Down
15 changes: 15 additions & 0 deletions src/api/v4/auth/token/token_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,21 @@ impl Token {
);
}
}
ProviderToken::Trust(token) => {
if project.is_none() {
project = Some(
state
.provider
.get_resource_provider()
.get_project(state, &token.project_id)
.await?
.ok_or_else(|| KeystoneApiError::NotFound {
resource: "project".into(),
identifier: token.project_id.clone(),
})?,
);
}
}
}

if let Some(domain) = domain {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ pub(crate) mod tests {
unrestricted: Some(true),
}
}

pub fn get_application_credential_mock_from_active(
active: application_credential::ActiveModel,
internal_id: i32,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ mod tests {
"app_cred_id",
Some(12345),
)]])
.append_query_results([vec![get_role_mock("role_id".into())]])
.append_query_results([vec![get_role_mock("role_id")]])
.append_query_results([vec![get_access_rule_mock("app_cred_rule_id", None)]])
.into_connection();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ pub async fn list(
let roles = roles_handle
.context("fetching roles for application credential list")?
.into_iter()
.map(|apc| {
apc.into_iter()
.map(|apr| {
apr.into_iter()
.map(TryInto::<Role>::try_into)
.collect::<Result<Vec<_>, _>>()
})
Expand Down Expand Up @@ -133,10 +133,7 @@ mod tests {
role_id: "role_id2".into(),
},
]])
.append_query_results([vec![
get_role_mock("role_id1".into()),
get_role_mock("role_id2".into()),
]])
.append_query_results([vec![get_role_mock("role_id1"), get_role_mock("role_id2")]])
.append_query_results([vec![
db_application_credential_access_rule::Model {
application_credential_id: 1,
Expand Down
12 changes: 6 additions & 6 deletions src/assignment/backend/sql/role.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,9 @@ pub(crate) mod tests {

use super::*;

pub(crate) fn get_role_mock(id: String) -> role::Model {
pub fn get_role_mock<S: AsRef<str>>(id: S) -> role::Model {
role::Model {
id: id.clone(),
id: id.as_ref().into(),
domain_id: "foo_domain".into(),
name: "foo".into(),
..Default::default()
Expand All @@ -77,7 +77,7 @@ pub(crate) mod tests {
let db = MockDatabase::new(DatabaseBackend::Postgres)
.append_query_results([
// First query result - select user itself
vec![get_role_mock("1".into())],
vec![get_role_mock("1")],
])
.into_connection();
let config = Config::default();
Expand Down Expand Up @@ -108,15 +108,15 @@ pub(crate) mod tests {
let db = MockDatabase::new(DatabaseBackend::Postgres)
.append_query_results([
// First query result - select user itself
vec![get_role_mock("1".into())],
vec![get_role_mock("1")],
])
.append_query_results([
// First query result - select user itself
vec![get_role_mock("1".into())],
vec![get_role_mock("1")],
])
.append_query_results([
// First query result - select user itself
vec![get_role_mock("1".into())],
vec![get_role_mock("1")],
])
.into_connection();
let config = Config::default();
Expand Down
3 changes: 2 additions & 1 deletion src/assignment/backend/sql/role/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,8 @@ mod tests {
let created = create(&db, role_create).await.unwrap();

assert_eq!(created.name, "Global Role");
// domain_id should be None in the returned Role (because TryFrom filters NULL_DOMAIN_ID)
// domain_id should be None in the returned Role (because TryFrom filters
// NULL_DOMAIN_ID)
assert_eq!(created.domain_id, None);
}

Expand Down
20 changes: 20 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ pub struct Config {
/// Token provider configuration.
#[serde(default)]
pub token: TokenProvider,

/// Trust provider configuration.
#[serde(default)]
pub trust: TrustProvider,
}

/// Default configuration section.
Expand Down Expand Up @@ -588,6 +592,22 @@ pub enum TokenProviderDriver {
Fernet,
}

/// Trust provider.
#[derive(Debug, Deserialize, Clone)]
pub struct TrustProvider {
/// Trust provider driver.
#[serde(default = "default_sql_driver")]
pub driver: String,
}

impl Default for TrustProvider {
fn default() -> Self {
Self {
driver: default_sql_driver(),
}
}
}

impl Config {
pub fn new(path: PathBuf) -> Result<Self, Report> {
let mut builder = config::Config::builder();
Expand Down
25 changes: 22 additions & 3 deletions src/db/entity/trust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,34 @@ pub struct Model {
pub impersonation: bool,
pub deleted_at: Option<DateTime>,
pub expires_at: Option<DateTime>,
pub remaining_uses: Option<i32>,
pub remaining_uses: Option<u32>,
#[sea_orm(column_type = "Text", nullable)]
pub extra: Option<String>,
pub expires_at_int: Option<i64>,
pub redelegated_trust_id: Option<String>,
pub redelegation_count: Option<i32>,
pub redelegation_count: Option<u32>,
}

#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {}
pub enum Relation {
#[sea_orm(has_many = "super::trust_role::Entity")]
TrustRole,
}

impl ActiveModelBehavior for ActiveModel {}

impl Related<super::trust_role::Entity> for Entity {
fn to() -> RelationDef {
Relation::TrustRole.def()
}
}

impl Related<super::role::Entity> for Entity {
fn to() -> RelationDef {
super::trust_role::Relation::Role.def()
}

fn via() -> Option<RelationDef> {
Some(super::trust_role::Relation::Trust.def().rev())
}
}
31 changes: 30 additions & 1 deletion src/db/entity/trust_role.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,35 @@ pub struct Model {
}

#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {}
pub enum Relation {
#[sea_orm(
belongs_to = "super::trust::Entity",
from = "Column::TrustId",
to = "super::trust::Column::Id",
on_update = "NoAction",
on_delete = "Cascade"
)]
Trust,
#[sea_orm(
belongs_to = "super::role::Entity",
from = "Column::RoleId",
to = "super::role::Column::Id",
on_update = "NoAction",
on_delete = "Cascade"
)]
Role,
}

impl ActiveModelBehavior for ActiveModel {}

impl Related<super::trust::Entity> for Entity {
fn to() -> RelationDef {
Relation::Trust.def()
}
}

impl Related<super::role::Entity> for Entity {
fn to() -> RelationDef {
Relation::Role.def()
}
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ pub mod provider;
pub mod resource;
pub mod revoke;
pub mod token;
pub mod trust;
pub mod webauthn;

#[cfg(test)]
Expand Down
9 changes: 9 additions & 0 deletions src/plugin_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ use crate::federation::backend::FederationBackend;
use crate::identity::backends::IdentityBackend;
use crate::resource::types::ResourceBackend;
use crate::revoke::backend::RevokeBackend;
use crate::trust::backend::TrustBackend;

/// Plugin manager allowing to pass custom backend plugins implementing required
/// trait during the service start.
Expand All @@ -48,6 +49,8 @@ pub struct PluginManager {
resource_backends: HashMap<String, Box<dyn ResourceBackend>>,
/// Revoke backend plugins.
revoke_backends: HashMap<String, Box<dyn RevokeBackend>>,
/// Trust backend plugins.
trust_backends: HashMap<String, Box<dyn TrustBackend>>,
}

impl PluginManager {
Expand Down Expand Up @@ -117,4 +120,10 @@ impl PluginManager {
pub fn get_revoke_backend<S: AsRef<str>>(&self, name: S) -> Option<&Box<dyn RevokeBackend>> {
self.revoke_backends.get(name.as_ref())
}

/// Get registered trust backend.
#[allow(clippy::borrowed_box)]
pub fn get_trust_backend<S: AsRef<str>>(&self, name: S) -> Option<&Box<dyn TrustBackend>> {
self.trust_backends.get(name.as_ref())
}
}
31 changes: 30 additions & 1 deletion src/token/backend/fernet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,14 @@ use crate::token::{
federation_domain_scoped::FederationDomainScopePayload,
federation_project_scoped::FederationProjectScopePayload,
federation_unscoped::FederationUnscopedPayload, project_scoped::ProjectScopePayload,
restricted::RestrictedPayload, unscoped::UnscopedPayload, *,
restricted::RestrictedPayload, trust::TrustPayload, unscoped::UnscopedPayload, *,
},
};
use utils::FernetUtils;

mod application_credential;
mod restricted;
mod trust;
pub mod utils;

#[derive(Clone)]
Expand Down Expand Up @@ -216,6 +217,7 @@ impl FernetTokenProvider {
0 => Ok(UnscopedPayload::disassemble(rd, self)?.into()),
1 => Ok(DomainScopePayload::disassemble(rd, self)?.into()),
2 => Ok(ProjectScopePayload::disassemble(rd, self)?.into()),
3 => Ok(TrustPayload::disassemble(rd, self)?.into()),
4 => Ok(FederationUnscopedPayload::disassemble(rd, self)?.into()),
5 => Ok(FederationProjectScopePayload::disassemble(rd, self)?.into()),
6 => Ok(FederationDomainScopePayload::disassemble(rd, self)?.into()),
Expand Down Expand Up @@ -256,6 +258,13 @@ impl FernetTokenProvider {
.map_err(|x| TokenProviderError::RmpEncode(x.to_string()))?;
data.assemble(&mut buf, self)?;
}
Token::Trust(data) => {
write_array_len(&mut buf, 7)
.map_err(|x| TokenProviderError::RmpEncode(x.to_string()))?;
write_pfix(&mut buf, 3)
.map_err(|x| TokenProviderError::RmpEncode(x.to_string()))?;
data.assemble(&mut buf, self)?;
}
Token::FederationUnscoped(data) => {
write_array_len(&mut buf, 8)
.map_err(|x| TokenProviderError::RmpEncode(x.to_string()))?;
Expand Down Expand Up @@ -770,4 +779,24 @@ pub(super) mod tests {
let dec_token = discard_issued_at(provider.decrypt(&encrypted).unwrap());
assert_eq!(token, dec_token);
}

#[tokio::test]
async fn test_trust_roundtrip() {
let token = Token::Trust(TrustPayload {
user_id: Uuid::new_v4().simple().to_string(),
methods: vec!["password".into()],
trust_id: Uuid::new_v4().simple().to_string(),
project_id: Uuid::new_v4().simple().to_string(),
audit_ids: vec!["Zm9vCg".into()],
expires_at: Local::now().trunc_subsecs(0).into(),
..Default::default()
});

let mut provider = FernetTokenProvider::new(setup_config());
provider.load_keys().unwrap();

let encrypted = provider.encrypt(&token).unwrap();
let dec_token = discard_issued_at(provider.decrypt(&encrypted).unwrap());
assert_eq!(token, dec_token);
}
}
Loading
Loading