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
30 changes: 15 additions & 15 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ serde = { version = "^1.0" }
serde_bytes = "0.11.16"
serde_json = { version = "^1.0" }
thiserror = { version = "^2.0" }
tokio = { version = "^1.43", features = ["fs", "macros", "signal", "rt-multi-thread"] }
tokio = { version = "^1.44", features = ["fs", "macros", "signal", "rt-multi-thread"] }
tower = { version = "^0.5" }
tower-http = { version = "^0.6", features = ["compression-full", "request-id", "sensitive-headers", "trace", "util"] }
tracing = { version = "^0.1" }
Expand Down
3 changes: 2 additions & 1 deletion deny.toml
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ feature-depth = 1
ignore = [
#"RUSTSEC-0000-0000",
"RUSTSEC-2023-0018",
"RUSTSEC-2023-0071"
"RUSTSEC-2023-0071",
"RUSTSEC-2024-0436"
#{ id = "RUSTSEC-0000-0000", reason = "you can specify a reason the advisory is ignored" },
#"a-crate-that-is-yanked@0.1.1", # you can also ignore yanked crate versions if you wish
#{ crate = "a-crate-that-is-yanked@0.1.1", reason = "you can specify why you are ignoring the yanked crate" },
Expand Down
42 changes: 23 additions & 19 deletions src/api/v3/role_assignment/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,20 @@ pub(super) fn openapi_router() -> OpenApiRouter<ServiceState> {
),
tag="roles"
)]
#[tracing::instrument(name = "api::role_assignment_list", level = "debug", skip(state))]
#[tracing::instrument(
name = "api::role_assignment_list",
level = "debug",
skip(state, _user_auth)
)]
async fn list(
Auth(user_auth): Auth,
Auth(_user_auth): Auth,
Query(query): Query<RoleAssignmentListParameters>,
State(state): State<ServiceState>,
) -> Result<impl IntoResponse, KeystoneApiError> {
let assignments: Result<Vec<Assignment>, _> = state
.provider
.get_assignment_provider()
.list_role_assignments(&state.db, &query.try_into()?)
.list_role_assignments(&state.db, &state.provider, &query.try_into()?)
.await
.map_err(KeystoneApiError::assignment)?
.into_iter()
Expand Down Expand Up @@ -87,7 +91,7 @@ mod tests {
use crate::config::Config;
use crate::identity::MockIdentityProvider;
use crate::keystone::{Service, ServiceState};
use crate::provider::ProviderBuilder;
use crate::provider::{Provider, ProviderBuilder};
use crate::resource::MockResourceProvider;
use crate::token::{MockTokenProvider, Token, UnscopedToken};

Expand Down Expand Up @@ -121,8 +125,8 @@ mod tests {
let mut assignment_mock = MockAssignmentProvider::default();
assignment_mock
.expect_list_role_assignments()
.withf(|_: &DatabaseConnection, _: &RoleAssignmentListParameters| true)
.returning(|_, _| {
.withf(|_: &DatabaseConnection, _: &Provider, _: &RoleAssignmentListParameters| true)
.returning(|_, _, _| {
Ok(vec![Assignment {
role_id: "role".into(),
actor_id: "actor".into(),
Expand Down Expand Up @@ -173,16 +177,16 @@ mod tests {
assignment_mock
.expect_list_role_assignments()
.withf(
|_: &DatabaseConnection, qp: &RoleAssignmentListParameters| {
|_: &DatabaseConnection, _: &Provider, qp: &RoleAssignmentListParameters| {
RoleAssignmentListParameters {
role_id: Some("role".into()),
actor_id: Some("user1".into()),
target_id: Some("project1".into()),
user_id: Some("user1".into()),
project_id: Some("project1".into()),
..Default::default()
} == *qp
},
)
.returning(|_, _| {
.returning(|_, _, _| {
Ok(vec![Assignment {
role_id: "role".into(),
actor_id: "actor".into(),
Expand All @@ -195,16 +199,16 @@ mod tests {
assignment_mock
.expect_list_role_assignments()
.withf(
|_: &DatabaseConnection, qp: &RoleAssignmentListParameters| {
|_: &DatabaseConnection, _: &Provider, qp: &RoleAssignmentListParameters| {
RoleAssignmentListParameters {
role_id: Some("role".into()),
actor_id: Some("user2".into()),
target_id: Some("domain2".into()),
user_id: Some("user2".into()),
domain_id: Some("domain2".into()),
..Default::default()
} == *qp
},
)
.returning(|_, _| {
.returning(|_, _, _| {
Ok(vec![Assignment {
role_id: "role".into(),
actor_id: "actor".into(),
Expand All @@ -217,15 +221,15 @@ mod tests {
assignment_mock
.expect_list_role_assignments()
.withf(
|_: &DatabaseConnection, qp: &RoleAssignmentListParameters| {
|_: &DatabaseConnection, _: &Provider, qp: &RoleAssignmentListParameters| {
RoleAssignmentListParameters {
actor_id: Some("user3".into()),
target_id: Some("project3".into()),
group_id: Some("group3".into()),
project_id: Some("project3".into()),
..Default::default()
} == *qp
},
)
.returning(|_, _| {
.returning(|_, _, _| {
Ok(vec![Assignment {
role_id: "role".into(),
actor_id: "actor".into(),
Expand Down Expand Up @@ -276,7 +280,7 @@ mod tests {
.as_service()
.oneshot(
Request::builder()
.uri("/?group.id=user3&scope.project.id=project3")
.uri("/?group.id=group3&scope.project.id=project3")
.header("x-auth-token", "foo")
.body(Body::empty())
.unwrap(),
Expand Down
43 changes: 33 additions & 10 deletions src/api/v3/role_assignment/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,37 +139,60 @@ impl IntoResponse for AssignmentList {
}
}

/// List role assignments query parameters
#[derive(Clone, Debug, Default, Deserialize, Serialize, IntoParams)]
pub struct RoleAssignmentListParameters {
#[serde(rename = "role.id")]
pub role_id: Option<String>,
#[serde(rename = "user.id")]
pub user_id: Option<String>,
/// Filters the response by a domain ID.
#[serde(rename = "scope.domain.id")]
pub domain_id: Option<String>,

/// Filters the response by a group ID.
#[serde(rename = "group.id")]
pub group_id: Option<String>,

/// Returns the effective assignments, including any assignments gained by virtue of group
/// membership.
pub effective: Option<bool>,

/// Filters the response by a project ID.
#[serde(rename = "scope.project.id")]
pub project_id: Option<String>,
#[serde(rename = "scope.domain.id")]
pub domain_id: Option<String>,

/// Filters the response by a role ID.
#[serde(rename = "role.id")]
pub role_id: Option<String>,

/// Filters the response by a user ID.
#[serde(rename = "user.id")]
pub user_id: Option<String>,
}

impl TryFrom<RoleAssignmentListParameters> for types::RoleAssignmentListParameters {
type Error = KeystoneApiError;

fn try_from(value: RoleAssignmentListParameters) -> Result<Self, Self::Error> {
let mut builder = types::RoleAssignmentListParametersBuilder::default();
// Filter by role
if let Some(val) = &value.role_id {
builder.role_id(val.clone());
}

// Filter by actor
if let Some(val) = &value.user_id {
builder.actor_id(val.clone());
builder.user_id(val.clone());
} else if let Some(val) = &value.group_id {
builder.actor_id(val.clone());
builder.group_id(val.clone());
}

// Filter by target
if let Some(val) = &value.project_id {
builder.target_id(val.clone());
builder.project_id(val.clone());
} else if let Some(val) = &value.domain_id {
builder.target_id(val.clone());
builder.domain_id(val.clone());
}

if let Some(val) = value.effective {
builder.effective(val);
}
Ok(builder.build()?)
}
Expand Down
10 changes: 10 additions & 0 deletions src/assignment/backends/sql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,14 @@ impl AssignmentBackend for SqlBackend {
) -> Result<Vec<Assignment>, AssignmentProviderError> {
Ok(assignment::list(&self.config, db, params).await?)
}

/// List role assignments for multiple actors/targets
#[tracing::instrument(level = "info", skip(self, db))]
async fn list_assignments_for_multiple_actors_and_targets(
&self,
db: &DatabaseConnection,
params: &RoleAssignmentListForMultipleActorTargetParameters,
) -> Result<Vec<Assignment>, AssignmentProviderError> {
Ok(assignment::list_for_multiple_actors_and_targets(&self.config, db, params).await?)
}
}
Loading