diff --git a/proto/st-peter-admin.proto b/proto/st-peter-admin.proto index 1131019..f8cf139 100644 --- a/proto/st-peter-admin.proto +++ b/proto/st-peter-admin.proto @@ -30,6 +30,10 @@ service AuthAdminService { rpc GetRoleScopes (GetRoleScopesRequest) returns (GetRoleScopesResponse); rpc GetUserWithRoles (GetUserWithRolesRequest) returns (GetUserWithRolesResponse); rpc GetAssignableRoles (GetAssignableRolesRequest) returns (GetAssignableRolesResponse); + // §role-grant-history — everyone who EVER held one of role_names for + // target_id (revoked grants included when include_deleted). Actor-gated: + // requested roles untargeted (all targets) or targeted at target_id. + rpc GetRoleGrantHistory (GetRoleGrantHistoryRequest) returns (GetRoleGrantHistoryResponse); rpc UpdateUserInfo (UpdateUserInfoRequest) returns (UpdateUserInfoResponse); rpc GetScopeAncestors (GetScopeAncestorsRequest) returns (GetScopeAncestorsResponse); rpc GetScopeDescendants (GetScopeDescendantsRequest) returns (GetScopeDescendantsResponse); @@ -554,3 +558,22 @@ message ClearUserSessionsResponse { string message = 3; int32 cleared_count = 4; } + +message GetRoleGrantHistoryRequest { + string actor_token = 1; + repeated string role_names = 2; + string target_id = 3; // uuid of the entity (e.g. an advertiser) + bool include_deleted = 4; +} + +message RoleGrantUser { + string user_id = 1; + string display_name = 2; +} + +message GetRoleGrantHistoryResponse { + bool success = 1; + ResultCode result_code = 2; + string message = 3; + repeated RoleGrantUser users = 4; +} diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 7e8de81..8fcf51c 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "st-peter-client" -version = "0.2.3" +version = "0.2.4" edition = "2021" description = "Official Rust client for st-peter (aura-users) — authentication over gRPC with a token-verify cache" repository = "https://git.awesomike.com/pub/st-peter-client" diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 5ea1bcf..c3d9a02 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -427,6 +427,35 @@ impl AdminClient { Ok(resp.users) } + /// §role-grant-history — everyone who EVER held one of `role_names` for + /// `target_id` (revoked grants included when `include_deleted`). Gated by + /// the ACTOR's own token: any requested role untargeted (all targets) or + /// targeted at `target_id`; otherwise the server returns FORBIDDEN in the + /// response envelope. Returns (user_id, display_name), PII-free. + pub async fn get_role_grant_history( + &self, + actor_token: &str, + role_names: Vec, + target_id: &str, + include_deleted: bool, + ) -> Result> { + let resp = self + .inner + .clone() + .get_role_grant_history(adminpb::GetRoleGrantHistoryRequest { + actor_token: actor_token.to_string(), + role_names, + target_id: target_id.to_string(), + include_deleted, + }) + .await? + .into_inner(); + if !resp.success { + return Err(Error::Rejected { code: resp.result_code, message: resp.message }); + } + Ok(resp.users) + } + /// Assign a role to a user — targeted when `target_id` is set (the /// multi-tenancy device: e.g. `cms-content-editor` for one organization), /// optionally time-bound via `expires_at`.