openstack_keystone_core/assignment/
service.rs1use async_trait::async_trait;
15use std::sync::Arc;
16use validator::Validate;
17
18use crate::assignment::{AssignmentProviderError, backend::AssignmentBackend, types::*};
19use crate::config::Config;
20use crate::identity::IdentityApi;
21use crate::keystone::ServiceState;
22use crate::plugin_manager::PluginManagerApi;
23use crate::resource::ResourceApi;
24use crate::revoke::{RevokeApi, types::RevocationEventCreate};
25
26pub struct AssignmentService {
27 backend_driver: Arc<dyn AssignmentBackend>,
28}
29
30impl AssignmentService {
31 pub fn new<P: PluginManagerApi>(
32 config: &Config,
33 plugin_manager: &P,
34 ) -> Result<Self, AssignmentProviderError> {
35 let backend_driver = plugin_manager
36 .get_assignment_backend(config.assignment.driver.clone())?
37 .clone();
38 Ok(Self { backend_driver })
39 }
40}
41
42#[async_trait]
43impl AssignmentApi for AssignmentService {
44 #[tracing::instrument(level = "info", skip(self, state))]
46 async fn create_grant(
47 &self,
48 state: &ServiceState,
49 grant: AssignmentCreate,
50 ) -> Result<Assignment, AssignmentProviderError> {
51 self.backend_driver.create_grant(state, grant).await
52 }
53
54 #[tracing::instrument(level = "info", skip(self, state))]
56 async fn list_role_assignments(
57 &self,
58 state: &ServiceState,
59 params: &RoleAssignmentListParameters,
60 ) -> Result<Vec<Assignment>, AssignmentProviderError> {
61 params.validate()?;
62 let mut request = RoleAssignmentListForMultipleActorTargetParametersBuilder::default();
63 let mut actors: Vec<String> = Vec::new();
64 let mut targets: Vec<RoleAssignmentTarget> = Vec::new();
65 if let Some(role_id) = ¶ms.role_id {
66 request.role_id(role_id);
67 }
68 if let Some(uid) = ¶ms.user_id {
69 actors.push(uid.into());
70 }
71 if let Some(true) = ¶ms.effective
72 && let Some(uid) = ¶ms.user_id
73 {
74 let users = state
75 .provider
76 .get_identity_provider()
77 .list_groups_of_user(state, uid)
78 .await?;
79 actors.extend(users.into_iter().map(|x| x.id));
80 };
81 if let Some(val) = ¶ms.project_id {
82 targets.push(RoleAssignmentTarget {
83 id: val.clone(),
84 r#type: RoleAssignmentTargetType::Project,
85 inherited: Some(false),
86 });
87 if let Some(parents) = state
88 .provider
89 .get_resource_provider()
90 .get_project_parents(state, val)
91 .await?
92 {
93 parents.iter().for_each(|parent_project| {
94 targets.push(RoleAssignmentTarget {
95 id: parent_project.id.clone(),
96 r#type: RoleAssignmentTargetType::Project,
97 inherited: Some(true),
98 });
99 });
100 }
101 } else if let Some(val) = ¶ms.domain_id {
102 targets.push(RoleAssignmentTarget {
103 id: val.clone(),
104 r#type: RoleAssignmentTargetType::Domain,
105 inherited: Some(false),
106 });
107 } else if let Some(val) = ¶ms.system_id {
108 targets.push(RoleAssignmentTarget {
109 id: val.clone(),
110 r#type: RoleAssignmentTargetType::System,
111 inherited: Some(false),
112 })
113 }
114 request.targets(targets);
115 request.actors(actors);
116 self.backend_driver
117 .list_assignments_for_multiple_actors_and_targets(state, &request.build()?)
118 .await
119 }
120
121 #[tracing::instrument(level = "info", skip(self, state))]
123 async fn revoke_grant(
124 &self,
125 state: &ServiceState,
126 grant: Assignment,
127 ) -> Result<(), AssignmentProviderError> {
128 self.backend_driver.revoke_grant(state, &grant).await?;
130
131 let user_id = match &grant.r#type {
133 AssignmentType::UserDomain
134 | AssignmentType::UserProject
135 | AssignmentType::UserSystem => Some(grant.actor_id.clone()),
136
137 AssignmentType::GroupDomain
138 | AssignmentType::GroupProject
139 | AssignmentType::GroupSystem => None,
140 };
141
142 let (project_id, domain_id) = match &grant.r#type {
144 AssignmentType::UserProject | AssignmentType::GroupProject => {
145 (Some(grant.target_id.clone()), None)
146 }
147 AssignmentType::UserDomain | AssignmentType::GroupDomain => {
148 (None, Some(grant.target_id.clone()))
149 }
150 AssignmentType::UserSystem | AssignmentType::GroupSystem => (None, None),
151 };
152
153 let revocation_event = RevocationEventCreate {
154 domain_id,
155 project_id,
156 user_id,
157 role_id: Some(grant.role_id.clone()),
158 trust_id: None,
159 consumer_id: None,
160 access_token_id: None,
161 issued_before: chrono::Utc::now(),
162 expires_at: None,
163 audit_id: None,
164 audit_chain_id: None,
165 revoked_at: chrono::Utc::now(),
166 };
167
168 state
169 .provider
170 .get_revoke_provider()
171 .create_revocation_event(state, revocation_event)
172 .await?;
173
174 Ok(())
175 }
176}