Skip to content

Commit cfe2f09

Browse files
authored
feat: Implement grant deletion provider api (#524)
Enable user-project-role grant deletion
1 parent 457ef4e commit cfe2f09

File tree

17 files changed

+1018
-4
lines changed

17 files changed

+1018
-4
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package identity.project.user.role.revoke
2+
3+
import data.identity
4+
import data.identity.assignment
5+
6+
# Revoke user a role on a project
7+
8+
default allow := false
9+
10+
allow if {
11+
"admin" in input.credentials.roles
12+
}
13+
14+
allow if {
15+
"manager" in input.credentials.roles
16+
assignment.project_role_domain_matches
17+
}
18+
19+
20+
violation contains {"field": "domain_id", "msg": "revoking a role from a user on a project requires admin or manager role in the domain scope."} if {
21+
not "admin" in input.credentials.roles
22+
not "manager" in input.credentials.roles
23+
}
24+
25+
violation contains {"field": "domain_id", "msg": "revoking a role from a user on a project requires domain scope matching the domain_id of the target project and role (or a global role)."} if {
26+
assignment.project_role_domain_matches
27+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package test_project_user_role_revoke
2+
3+
import data.identity.project.user.role.revoke
4+
5+
test_allowed if {
6+
revoke.allow with input as {"credentials": {"roles": ["admin"]}}
7+
revoke.allow with input as {"credentials": {"roles": ["manager"], "domain_id": "foo"}, "target": {"user": {"domain_id": "foo"}, "project": {"domain_id": "foo"}, "role": {"domain_id": null}}}
8+
revoke.allow with input as {"credentials": {"roles": ["manager"], "domain_id": "foo"}, "target": {"user": {"domain_id": "foo"}, "project": {"domain_id": "foo"}, "role": {"domain_id": "foo"}}}
9+
}
10+
11+
test_forbidden if {
12+
not revoke.allow with input as {"credentials": {"roles": []}}
13+
not revoke.allow with input as {"credentials": {"roles": ["reader"], "system": "foo"}}
14+
not revoke.allow with input as {"credentials": {"roles": ["reader"], "domain_id": "foo"}, "target": {"user": {"domain_id": "foo1"}, "project": {"domain_id": "foo"}, "role": {"domain_id": "foo"}}}
15+
not revoke.allow with input as {"credentials": {"roles": ["reader"], "domain_id": "foo"}, "target": {"user": {"domain_id": "foo1"}, "project": {"domain_id": "foo1"}, "role": {"domain_id": "foo1"}}}
16+
not revoke.allow with input as {"credentials": {"roles": ["reader"], "domain_id": "foo"}, "target": {"user": {"domain_id": "foo"}, "project": {"domain_id": "foo1"}, "role": {"domain_id": "foo1"}}}
17+
not revoke.allow with input as {"credentials": {"roles": ["reader"], "domain_id": "foo"}, "target": {"user": {"domain_id": "foo1"}, "project": {"domain_id": "foo1"}, "role": {"domain_id": "foo1"}}}
18+
not revoke.allow with input as {"credentials": {"roles": ["reader"], "domain_id": "foo"}, "target": {"project": {"domain_id": "foo"}, "role": {"domain_id": "foo"}}}
19+
not revoke.allow with input as {"credentials": {"roles": ["member"], "domain_id": "foo"}, "target": {"project": {"domain_id": "foo"}, "role": {"domain_id": "foo"}, "user": {"domain_id": "foo"}}}
20+
}

src/api/error.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,10 @@ impl From<AuthenticationError> for KeystoneApiError {
175175
impl From<AssignmentProviderError> for KeystoneApiError {
176176
fn from(source: AssignmentProviderError) -> Self {
177177
match source {
178+
AssignmentProviderError::AssignmentNotFound(x) => Self::NotFound {
179+
resource: "assignment".into(),
180+
identifier: x,
181+
},
178182
AssignmentProviderError::RoleNotFound(x) => Self::NotFound {
179183
resource: "role".into(),
180184
identifier: x,

src/api/v3/role_assignment/project/user/role.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ use crate::keystone::ServiceState;
1818

1919
mod check;
2020
mod grant;
21+
mod revoke;
2122

2223
pub(crate) fn openapi_router() -> OpenApiRouter<ServiceState> {
23-
OpenApiRouter::new().routes(routes!(check::check, grant::grant))
24+
OpenApiRouter::new().routes(routes!(check::check, grant::grant, revoke::revoke))
2425
}

src/api/v3/role_assignment/project/user/role/grant.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,15 @@ use crate::{
3333
resource::ResourceApi,
3434
};
3535

36-
/// Assign role to group on project
36+
/// Assign role to user on project
3737
///
38-
/// Assigns a role to a group on a project.
38+
/// Assigns a role to a user on a project.
3939
#[utoipa::path(
4040
put,
4141
path = "/projects/{project_id}/users/{user_id}/roles/{role_id}",
4242
operation_id = "/project/user/role:put",
4343
params(
44-
("role_id" = String, Path, description = "The user ID."),
44+
("role_id" = String, Path, description = "The role ID."),
4545
("project_id" = String, Path, description = "The project ID."),
4646
("user_id" = String, Path, description = "The user ID.")
4747
),

0 commit comments

Comments
 (0)