1use async_trait::async_trait;
23use base64::{Engine as _, engine::general_purpose::URL_SAFE_NO_PAD};
24use chrono::{DateTime, TimeDelta, Utc};
25use std::collections::HashSet;
26use std::sync::Arc;
27use tracing::{debug, trace};
28use uuid::Uuid;
29
30use crate::auth::{AuthenticatedInfo, AuthenticationError, AuthzInfo};
31use crate::config::{Config, TokenProviderDriver};
32use crate::identity::IdentityApi;
33use crate::keystone::ServiceState;
34use crate::plugin_manager::PluginManagerApi;
35use crate::resource::{
36 ResourceApi,
37 types::{Domain, Project},
38};
39use crate::revoke::RevokeApi;
40use crate::token::{
41 TokenProviderError,
42 backend::{TokenBackend, TokenRestrictionBackend, fernet::FernetTokenProvider},
43};
44use crate::{
45 application_credential::ApplicationCredentialApi,
46 assignment::{
47 AssignmentApi,
48 error::AssignmentProviderError,
49 types::{RoleAssignmentListParameters, RoleAssignmentListParametersBuilder},
50 },
51 role::{RoleApi, types::RoleRef},
52 trust::{TrustApi, types::Trust},
53};
54
55pub use crate::token::types::*;
56
57pub struct TokenService {
58 config: Config,
59 backend_driver: Arc<dyn TokenBackend>,
60 tr_backend_driver: Arc<dyn TokenRestrictionBackend>,
61}
62
63impl TokenService {
64 pub fn new<P: PluginManagerApi>(
65 config: &Config,
66 plugin_manager: &P,
67 ) -> Result<Self, TokenProviderError> {
68 let backend_driver = match config.token.provider {
69 TokenProviderDriver::Fernet => FernetTokenProvider::new(config.clone()),
70 };
71 let tr_backend_driver = plugin_manager
72 .get_token_restriction_backend(&config.token_restriction.driver)?
73 .clone();
74 Ok(Self {
75 config: config.clone(),
76 backend_driver: Arc::new(backend_driver),
77 tr_backend_driver,
78 })
79 }
80
81 fn get_new_token_expiry(
82 &self,
83 auth_expiration: &Option<DateTime<Utc>>,
84 ) -> Result<DateTime<Utc>, TokenProviderError> {
85 let default_expiry = Utc::now()
86 .checked_add_signed(TimeDelta::seconds(self.config.token.expiration as i64))
87 .ok_or(TokenProviderError::ExpiryCalculation)?;
88 Ok(auth_expiration
89 .map(|x| std::cmp::min(x, default_expiry))
90 .unwrap_or(default_expiry))
91 }
92
93 fn create_unscoped_token(
95 &self,
96 authentication_info: &AuthenticatedInfo,
97 ) -> Result<Token, TokenProviderError> {
98 Ok(Token::Unscoped(
99 UnscopedPayloadBuilder::default()
100 .user_id(authentication_info.user_id.clone())
101 .user(authentication_info.user.clone())
102 .methods(authentication_info.methods.clone().iter())
103 .audit_ids(authentication_info.audit_ids.clone().iter())
104 .expires_at(self.get_new_token_expiry(&authentication_info.expires_at)?)
105 .build()?,
106 ))
107 }
108
109 fn create_project_scope_token(
111 &self,
112 authentication_info: &AuthenticatedInfo,
113 project: &Project,
114 ) -> Result<Token, TokenProviderError> {
115 let token_expiry = self.get_new_token_expiry(&authentication_info.expires_at)?;
116 if let Some(application_credential) = &authentication_info.application_credential {
117 Ok(Token::ApplicationCredential(
119 ApplicationCredentialPayloadBuilder::default()
120 .application_credential_id(application_credential.id.clone())
121 .application_credential(application_credential.clone())
122 .user_id(authentication_info.user_id.clone())
123 .user(authentication_info.user.clone())
124 .methods(authentication_info.methods.clone().iter())
125 .audit_ids(authentication_info.audit_ids.clone().iter())
126 .expires_at(
127 application_credential
128 .expires_at
129 .map(|ac_expiry| std::cmp::min(token_expiry, ac_expiry))
130 .unwrap_or(token_expiry),
131 )
132 .project_id(project.id.clone())
133 .project(project.clone())
134 .build()?,
135 ))
136 } else {
137 Ok(Token::ProjectScope(
139 ProjectScopePayloadBuilder::default()
140 .user_id(authentication_info.user_id.clone())
141 .user(authentication_info.user.clone())
142 .methods(authentication_info.methods.clone().iter())
143 .audit_ids(authentication_info.audit_ids.clone().iter())
144 .expires_at(token_expiry)
145 .project_id(project.id.clone())
146 .project(project.clone())
147 .build()?,
148 ))
149 }
150 }
151
152 fn create_domain_scope_token(
154 &self,
155 authentication_info: &AuthenticatedInfo,
156 domain: &Domain,
157 ) -> Result<Token, TokenProviderError> {
158 Ok(Token::DomainScope(
159 DomainScopePayloadBuilder::default()
160 .user_id(authentication_info.user_id.clone())
161 .user(authentication_info.user.clone())
162 .methods(authentication_info.methods.clone().iter())
163 .audit_ids(authentication_info.audit_ids.clone().iter())
164 .expires_at(self.get_new_token_expiry(&authentication_info.expires_at)?)
165 .domain_id(domain.id.clone())
166 .domain(domain.clone())
167 .build()?,
168 ))
169 }
170
171 fn create_federated_unscoped_token(
173 &self,
174 authentication_info: &AuthenticatedInfo,
175 ) -> Result<Token, TokenProviderError> {
176 if let (Some(idp_id), Some(protocol_id)) = (
177 authentication_info.idp_id.clone(),
178 authentication_info.protocol_id.clone(),
179 ) {
180 Ok(Token::FederationUnscoped(
181 FederationUnscopedPayloadBuilder::default()
182 .user_id(authentication_info.user_id.clone())
183 .user(authentication_info.user.clone())
184 .methods(authentication_info.methods.clone().iter())
185 .audit_ids(authentication_info.audit_ids.clone().iter())
186 .expires_at(self.get_new_token_expiry(&authentication_info.expires_at)?)
187 .idp_id(idp_id)
188 .protocol_id(protocol_id)
189 .group_ids(vec![])
190 .build()?,
191 ))
192 } else {
193 Err(TokenProviderError::FederatedPayloadMissingData)
194 }
195 }
196
197 fn create_federated_project_scope_token(
199 &self,
200 authentication_info: &AuthenticatedInfo,
201 project: &Project,
202 ) -> Result<Token, TokenProviderError> {
203 if let (Some(idp_id), Some(protocol_id)) = (
204 authentication_info.idp_id.clone(),
205 authentication_info.protocol_id.clone(),
206 ) {
207 Ok(Token::FederationProjectScope(
208 FederationProjectScopePayloadBuilder::default()
209 .user_id(authentication_info.user_id.clone())
210 .user(authentication_info.user.clone())
211 .methods(authentication_info.methods.clone().iter())
212 .audit_ids(authentication_info.audit_ids.clone().iter())
213 .expires_at(self.get_new_token_expiry(&authentication_info.expires_at)?)
214 .idp_id(idp_id)
215 .protocol_id(protocol_id)
216 .group_ids(
217 authentication_info
218 .user_groups
219 .clone()
220 .iter()
221 .map(|grp| grp.id.clone())
222 .collect::<Vec<_>>(),
223 )
224 .project_id(project.id.clone())
225 .project(project.clone())
226 .build()?,
227 ))
228 } else {
229 Err(TokenProviderError::FederatedPayloadMissingData)
230 }
231 }
232
233 fn create_federated_domain_scope_token(
235 &self,
236 authentication_info: &AuthenticatedInfo,
237 domain: &Domain,
238 ) -> Result<Token, TokenProviderError> {
239 if let (Some(idp_id), Some(protocol_id)) = (
240 authentication_info.idp_id.clone(),
241 authentication_info.protocol_id.clone(),
242 ) {
243 Ok(Token::FederationDomainScope(
244 FederationDomainScopePayloadBuilder::default()
245 .user_id(authentication_info.user_id.clone())
246 .user(authentication_info.user.clone())
247 .methods(authentication_info.methods.clone().iter())
248 .audit_ids(authentication_info.audit_ids.clone().iter())
249 .expires_at(self.get_new_token_expiry(&authentication_info.expires_at)?)
250 .idp_id(idp_id)
251 .protocol_id(protocol_id)
252 .group_ids(
253 authentication_info
254 .user_groups
255 .clone()
256 .iter()
257 .map(|grp| grp.id.clone())
258 .collect::<Vec<_>>(),
259 )
260 .domain_id(domain.id.clone())
261 .domain(domain.clone())
262 .build()?,
263 ))
264 } else {
265 Err(TokenProviderError::FederatedPayloadMissingData)
266 }
267 }
268
269 fn create_restricted_token(
271 &self,
272 authentication_info: &AuthenticatedInfo,
273 authz_info: &AuthzInfo,
274 restriction: &TokenRestriction,
275 ) -> Result<Token, TokenProviderError> {
276 Ok(Token::Restricted(
277 RestrictedPayloadBuilder::default()
278 .user_id(
279 restriction
280 .user_id
281 .as_ref()
282 .unwrap_or(&authentication_info.user_id.clone()),
283 )
284 .user(authentication_info.user.clone())
285 .methods(authentication_info.methods.clone().iter())
286 .audit_ids(authentication_info.audit_ids.clone().iter())
287 .expires_at(self.get_new_token_expiry(&authentication_info.expires_at)?)
288 .token_restriction_id(restriction.id.clone())
289 .project_id(
290 restriction
291 .project_id
292 .as_ref()
293 .or(match authz_info {
294 AuthzInfo::Project(project) => Some(&project.id),
295 _ => None,
296 })
297 .ok_or_else(|| TokenProviderError::RestrictedTokenNotProjectScoped)?,
298 )
299 .allow_renew(restriction.allow_renew)
300 .allow_rescope(restriction.allow_rescope)
301 .roles(restriction.roles.clone())
302 .build()?,
303 ))
304 }
305
306 fn create_system_scoped_token(
308 &self,
309 authentication_info: &AuthenticatedInfo,
310 ) -> Result<Token, TokenProviderError> {
311 Ok(Token::SystemScope(
312 SystemScopePayloadBuilder::default()
313 .user_id(authentication_info.user_id.clone())
314 .user(authentication_info.user.clone())
315 .methods(authentication_info.methods.clone().iter())
316 .audit_ids(authentication_info.audit_ids.clone().iter())
317 .system_id("system")
318 .expires_at(self.get_new_token_expiry(&authentication_info.expires_at)?)
319 .build()?,
320 ))
321 }
322
323 fn create_trust_token(
325 &self,
326 authentication_info: &AuthenticatedInfo,
327 trust: &Trust,
328 ) -> Result<Token, TokenProviderError> {
329 if let Some(project_id) = &trust.project_id {
330 Ok(Token::Trust(
331 TrustPayloadBuilder::default()
332 .user_id(authentication_info.user_id.clone())
333 .user(authentication_info.user.clone())
334 .methods(authentication_info.methods.clone().iter())
335 .audit_ids(authentication_info.audit_ids.clone().iter())
336 .expires_at(self.get_new_token_expiry(&authentication_info.expires_at)?)
337 .trust_id(trust.id.clone())
338 .project_id(project_id.clone())
339 .build()?,
340 ))
341 } else {
342 Ok(Token::Unscoped(
344 UnscopedPayloadBuilder::default()
345 .user_id(authentication_info.user_id.clone())
346 .user(authentication_info.user.clone())
347 .methods(authentication_info.methods.clone().iter())
348 .audit_ids(authentication_info.audit_ids.clone().iter())
349 .expires_at(self.get_new_token_expiry(&authentication_info.expires_at)?)
350 .build()?,
351 ))
352 }
353 }
354
355 async fn expand_user_information(
357 &self,
358 state: &ServiceState,
359 token: &mut Token,
360 ) -> Result<(), TokenProviderError> {
361 if token.user().is_none() {
362 let user = state
363 .provider
364 .get_identity_provider()
365 .get_user(state, token.user_id())
366 .await?;
367 match token {
368 Token::ApplicationCredential(data) => {
369 data.user = user;
370 }
371 Token::Unscoped(data) => {
372 data.user = user;
373 }
374 Token::ProjectScope(data) => {
375 data.user = user;
376 }
377 Token::DomainScope(data) => {
378 data.user = user;
379 }
380 Token::FederationUnscoped(data) => {
381 data.user = user;
382 }
383 Token::FederationProjectScope(data) => {
384 data.user = user;
385 }
386 Token::FederationDomainScope(data) => {
387 data.user = user;
388 }
389 Token::Restricted(data) => {
390 data.user = user;
391 }
392 Token::SystemScope(data) => {
393 data.user = user;
394 }
395 Token::Trust(data) => {
396 data.user = if let Some(trust) = &data.trust
397 && trust.impersonation
398 {
399 state
400 .provider
401 .get_identity_provider()
402 .get_user(state, &trust.trustor_user_id)
403 .await?
404 } else {
405 user
406 };
407 }
408 }
409 }
410 Ok(())
411 }
412
413 async fn expand_scope_information(
415 &self,
416 state: &ServiceState,
417 token: &mut Token,
418 ) -> Result<(), TokenProviderError> {
419 match token {
420 Token::ProjectScope(data) => {
421 if data.project.is_none() {
422 let project = state
423 .provider
424 .get_resource_provider()
425 .get_project(state, &data.project_id)
426 .await?;
427
428 data.project = project;
429 }
430 }
431 Token::ApplicationCredential(data) => {
432 if data.application_credential.is_none() {
433 data.application_credential = Some(
434 state
435 .provider
436 .get_application_credential_provider()
437 .get_application_credential(state, &data.application_credential_id)
438 .await?
439 .ok_or_else(|| {
440 TokenProviderError::ApplicationCredentialNotFound(
441 data.application_credential_id.clone(),
442 )
443 })?,
444 );
445 }
446 if data.project.is_none() {
447 let project = state
448 .provider
449 .get_resource_provider()
450 .get_project(state, &data.project_id)
451 .await?;
452
453 data.project = project;
454 }
455 }
456 Token::FederationProjectScope(data) => {
457 if data.project.is_none() {
458 let project = state
459 .provider
460 .get_resource_provider()
461 .get_project(state, &data.project_id)
462 .await?;
463
464 data.project = project;
465 }
466 }
467 Token::DomainScope(data) => {
468 if data.domain.is_none() {
469 let domain = state
470 .provider
471 .get_resource_provider()
472 .get_domain(state, &data.domain_id)
473 .await?;
474
475 data.domain = domain;
476 }
477 }
478 Token::FederationDomainScope(data) => {
479 if data.domain.is_none() {
480 let domain = state
481 .provider
482 .get_resource_provider()
483 .get_domain(state, &data.domain_id)
484 .await?;
485
486 data.domain = domain;
487 }
488 }
489 Token::Restricted(data) => {
490 if data.project.is_none() {
491 let project = state
492 .provider
493 .get_resource_provider()
494 .get_project(state, &data.project_id)
495 .await?;
496
497 data.project = project;
498 }
499 }
500 Token::SystemScope(_data) => {}
501 Token::Trust(data) => {
502 if data.trust.is_none() {
503 data.trust = state
504 .provider
505 .get_trust_provider()
506 .get_trust(state, &data.trust_id)
507 .await?;
508 }
509 if data.project.is_none() {
510 data.project = state
511 .provider
512 .get_resource_provider()
513 .get_project(state, &data.project_id)
514 .await?;
515 }
516 }
517
518 _ => {}
519 };
520 Ok(())
521 }
522
523 async fn _populate_role_assignments(
525 &self,
526 state: &ServiceState,
527 token: &mut Token,
528 ) -> Result<(), TokenProviderError> {
529 match token {
530 Token::ApplicationCredential(data) => {
531 if data.application_credential.is_none() {
532 data.application_credential = Some(
533 state
534 .provider
535 .get_application_credential_provider()
536 .get_application_credential(state, &data.application_credential_id)
537 .await?
538 .ok_or_else(|| {
539 TokenProviderError::ApplicationCredentialNotFound(
540 data.application_credential_id.clone(),
541 )
542 })?,
543 );
544 }
545 if let Some(ref mut ac) = data.application_credential {
546 let user_role_ids: HashSet<String> = state
547 .provider
548 .get_assignment_provider()
549 .list_role_assignments(
550 state,
551 &RoleAssignmentListParametersBuilder::default()
552 .user_id(&data.user_id)
553 .project_id(&ac.project_id)
554 .include_names(false)
555 .effective(true)
556 .build()
557 .map_err(AssignmentProviderError::from)?,
558 )
559 .await?
560 .into_iter()
561 .map(|x| x.role_id.clone())
562 .collect();
563
564 let mut final_roles: Vec<RoleRef> = Vec::new();
567 for role in ac.roles.iter() {
568 if user_role_ids.contains(&role.id) {
569 final_roles.push(role.clone());
570 }
571 }
572 if final_roles.is_empty() {
573 return Err(TokenProviderError::ActorHasNoRolesOnTarget);
574 }
575 data.roles = Some(final_roles);
576 };
577 }
578 Token::DomainScope(data) => {
579 data.roles = Some(
580 state
581 .provider
582 .get_assignment_provider()
583 .list_role_assignments(
584 state,
585 &RoleAssignmentListParametersBuilder::default()
586 .user_id(&data.user_id)
587 .domain_id(&data.domain_id)
588 .include_names(true)
589 .effective(true)
590 .build()
591 .map_err(AssignmentProviderError::from)?,
592 )
593 .await?
594 .into_iter()
595 .map(|x| RoleRef {
596 id: x.role_id.clone(),
597 name: x.role_name.clone(),
598 domain_id: None,
599 })
600 .collect(),
601 );
602 if data.roles.as_ref().is_none_or(|roles| roles.is_empty()) {
603 return Err(TokenProviderError::ActorHasNoRolesOnTarget);
604 }
605 }
606 Token::FederationProjectScope(data) => {
607 data.roles = Some(
608 state
609 .provider
610 .get_assignment_provider()
611 .list_role_assignments(
612 state,
613 &RoleAssignmentListParametersBuilder::default()
614 .user_id(&data.user_id)
615 .project_id(&data.project_id)
616 .include_names(true)
617 .effective(true)
618 .build()
619 .map_err(AssignmentProviderError::from)?,
620 )
621 .await?
622 .into_iter()
623 .map(|x| RoleRef {
624 id: x.role_id.clone(),
625 name: x.role_name.clone(),
626 domain_id: None,
627 })
628 .collect(),
629 );
630 if data.roles.as_ref().is_none_or(|roles| roles.is_empty()) {
631 return Err(TokenProviderError::ActorHasNoRolesOnTarget);
632 }
633 }
634 Token::FederationDomainScope(data) => {
635 data.roles = Some(
636 state
637 .provider
638 .get_assignment_provider()
639 .list_role_assignments(
640 state,
641 &RoleAssignmentListParametersBuilder::default()
642 .user_id(&data.user_id)
643 .domain_id(&data.domain_id)
644 .include_names(true)
645 .effective(true)
646 .build()
647 .map_err(AssignmentProviderError::from)?,
648 )
649 .await?
650 .into_iter()
651 .map(|x| RoleRef {
652 id: x.role_id.clone(),
653 name: x.role_name.clone(),
654 domain_id: None,
655 })
656 .collect(),
657 );
658 if data.roles.as_ref().is_none_or(|roles| roles.is_empty()) {
659 return Err(TokenProviderError::ActorHasNoRolesOnTarget);
660 }
661 }
662 Token::ProjectScope(data) => {
663 data.roles = Some(
664 state
665 .provider
666 .get_assignment_provider()
667 .list_role_assignments(
668 state,
669 &RoleAssignmentListParametersBuilder::default()
670 .user_id(&data.user_id)
671 .project_id(&data.project_id)
672 .include_names(true)
673 .effective(true)
674 .build()
675 .map_err(AssignmentProviderError::from)?,
676 )
677 .await?
678 .into_iter()
679 .map(|x| RoleRef {
680 id: x.role_id.clone(),
681 name: x.role_name.clone(),
682 domain_id: None,
683 })
684 .collect(),
685 );
686 if data.roles.as_ref().is_none_or(|roles| roles.is_empty()) {
687 return Err(TokenProviderError::ActorHasNoRolesOnTarget);
688 }
689 }
690 Token::Restricted(data) => {
691 if data.roles.is_none() {
692 self.get_token_restriction(state, &data.token_restriction_id, true)
693 .await?
694 .inspect(|restrictions| data.roles = restrictions.roles.clone())
695 .ok_or(TokenProviderError::TokenRestrictionNotFound(
696 data.token_restriction_id.clone(),
697 ))?;
698 }
699 }
700 Token::SystemScope(data) => {
701 data.roles = Some(
702 state
703 .provider
704 .get_assignment_provider()
705 .list_role_assignments(
706 state,
707 &RoleAssignmentListParametersBuilder::default()
708 .user_id(&data.user_id)
709 .system_id(&data.system_id)
710 .include_names(true)
711 .effective(true)
712 .build()
713 .map_err(AssignmentProviderError::from)?,
714 )
715 .await?
716 .into_iter()
717 .map(|x| RoleRef {
718 id: x.role_id.clone(),
719 name: x.role_name.clone(),
720 domain_id: None,
721 })
722 .collect(),
723 );
724 if data.roles.as_ref().is_none_or(|roles| roles.is_empty()) {
725 return Err(TokenProviderError::ActorHasNoRolesOnTarget);
726 }
727 }
728 Token::Trust(data) => {
729 if let Some(ref mut trust) = data.trust {
732 let trustor_roles: HashSet<String> = state
733 .provider
734 .get_assignment_provider()
735 .list_role_assignments(
736 state,
737 &RoleAssignmentListParameters {
738 user_id: Some(trust.trustor_user_id.clone()),
739 project_id: Some(data.project_id.clone()),
740 effective: Some(true),
741 ..Default::default()
742 },
743 )
744 .await?
745 .into_iter()
746 .map(|x| x.role_id.clone())
747 .collect();
748 if let Some(ref mut trust_roles) = trust.roles {
749 state
755 .provider
756 .get_role_provider()
757 .expand_implied_roles(state, trust_roles)
758 .await?;
759 if !trust_roles
760 .iter()
761 .all(|role| trustor_roles.contains(&role.id))
762 {
763 debug!(
764 "Trust roles {:?} are missing for the trustor {:?}",
765 trust_roles, trustor_roles
766 );
767 return Err(TokenProviderError::ActorHasNoRolesOnTarget);
768 }
769 trust_roles.retain_mut(|role| role.domain_id.is_none());
770 }
771 }
772 }
773 _ => {}
774 }
775
776 Ok(())
777 }
778}
779
780#[async_trait]
781impl TokenApi for TokenService {
782 #[tracing::instrument(level = "info", skip(self, state, credential))]
784 async fn authenticate_by_token<'a>(
785 &self,
786 state: &ServiceState,
787 credential: &'a str,
788 allow_expired: Option<bool>,
789 window_seconds: Option<i64>,
790 ) -> Result<AuthenticatedInfo, TokenProviderError> {
791 let token = self
793 .validate_token(state, credential, allow_expired, window_seconds)
794 .await?;
795 if let Token::Restricted(restriction) = &token
796 && !restriction.allow_renew
797 {
798 return Err(AuthenticationError::TokenRenewalForbidden)?;
799 }
800 let mut auth_info_builder = AuthenticatedInfo::builder();
801 auth_info_builder.user_id(token.user_id());
802 auth_info_builder.methods(token.methods().clone());
803 auth_info_builder.audit_ids(token.audit_ids().clone());
804 auth_info_builder.expires_at(*token.expires_at());
805 if let Token::Restricted(restriction) = &token {
806 auth_info_builder.token_restriction_id(restriction.token_restriction_id.clone());
807 }
808 Ok(auth_info_builder
809 .build()
810 .map_err(AuthenticationError::from)?)
811 }
812
813 #[tracing::instrument(level = "info", skip(self, state, credential))]
815 async fn validate_token<'a>(
816 &self,
817 state: &ServiceState,
818 credential: &'a str,
819 allow_expired: Option<bool>,
820 window_seconds: Option<i64>,
821 ) -> Result<Token, TokenProviderError> {
822 let mut token = self.backend_driver.decode(credential)?;
823 let latest_expiration_cutof = Utc::now()
824 .checked_add_signed(TimeDelta::seconds(window_seconds.unwrap_or(0)))
825 .unwrap_or(Utc::now());
826 if !allow_expired.unwrap_or_default() && *token.expires_at() < latest_expiration_cutof {
827 trace!(
828 "Token has expired at {:?} with cutof: {:?}",
829 token.expires_at(),
830 latest_expiration_cutof
831 );
832 return Err(TokenProviderError::Expired);
833 }
834
835 token = self.expand_token_information(state, &token).await?;
837
838 if state
839 .provider
840 .get_revoke_provider()
841 .is_token_revoked(state, &token)
842 .await?
843 {
844 return Err(TokenProviderError::TokenRevoked);
845 }
846
847 token.validate_subject(state).await?;
848 token.validate_scope(state).await?;
849
850 Ok(token)
851 }
852
853 #[tracing::instrument(level = "debug", skip(self))]
855 fn issue_token(
856 &self,
857 authentication_info: AuthenticatedInfo,
858 authz_info: AuthzInfo,
859 token_restrictions: Option<&TokenRestriction>,
860 ) -> Result<Token, TokenProviderError> {
861 authentication_info.validate()?;
865
866 let mut authentication_info = authentication_info;
869 authentication_info
870 .audit_ids
871 .push(URL_SAFE_NO_PAD.encode(Uuid::new_v4().as_bytes()));
872 if let Some(token_restrictions) = &token_restrictions {
873 self.create_restricted_token(&authentication_info, &authz_info, token_restrictions)
874 } else if authentication_info.idp_id.is_some() && authentication_info.protocol_id.is_some()
875 {
876 match &authz_info {
877 AuthzInfo::Domain(domain) => {
878 self.create_federated_domain_scope_token(&authentication_info, domain)
879 }
880 AuthzInfo::Project(project) => {
881 self.create_federated_project_scope_token(&authentication_info, project)
882 }
883 AuthzInfo::Trust(_trust) => Err(TokenProviderError::Conflict {
884 message: "cannot create trust token with an identity provider in scope".into(),
885 context: "issuing token".into(),
886 }),
887 AuthzInfo::System => Err(TokenProviderError::Conflict {
888 message: "cannot create system scope token with an identity provider in scope"
889 .into(),
890 context: "issuing token".into(),
891 }),
892 AuthzInfo::Unscoped => self.create_federated_unscoped_token(&authentication_info),
893 }
894 } else {
895 match &authz_info {
896 AuthzInfo::Domain(domain) => {
897 self.create_domain_scope_token(&authentication_info, domain)
898 }
899 AuthzInfo::Project(project) => {
900 self.create_project_scope_token(&authentication_info, project)
901 }
902 AuthzInfo::Trust(trust) => self.create_trust_token(&authentication_info, trust),
903 AuthzInfo::System => self.create_system_scoped_token(&authentication_info),
904 AuthzInfo::Unscoped => self.create_unscoped_token(&authentication_info),
905 }
906 }
907 }
908
909 fn encode_token(&self, token: &Token) -> Result<String, TokenProviderError> {
913 self.backend_driver.encode(token)
914 }
915
916 async fn populate_role_assignments(
918 &self,
919 state: &ServiceState,
920 token: &mut Token,
921 ) -> Result<(), TokenProviderError> {
922 self._populate_role_assignments(state, token).await
923 }
924
925 async fn expand_token_information(
930 &self,
931 state: &ServiceState,
932 token: &Token,
933 ) -> Result<Token, TokenProviderError> {
934 let mut new_token = token.clone();
935 self.expand_user_information(state, &mut new_token).await?;
936 self.expand_scope_information(state, &mut new_token).await?;
937 self.populate_role_assignments(state, &mut new_token)
938 .await?;
939 Ok(new_token)
940 }
941
942 async fn get_token_restriction<'a>(
944 &self,
945 state: &ServiceState,
946 id: &'a str,
947 expand_roles: bool,
948 ) -> Result<Option<TokenRestriction>, TokenProviderError> {
949 self.tr_backend_driver
950 .get_token_restriction(state, id, expand_roles)
951 .await
952 }
953
954 async fn create_token_restriction<'a>(
956 &self,
957 state: &ServiceState,
958 restriction: TokenRestrictionCreate,
959 ) -> Result<TokenRestriction, TokenProviderError> {
960 let mut restriction = restriction;
961 if restriction.id.is_empty() {
962 restriction.id = Uuid::new_v4().simple().to_string();
963 }
964 self.tr_backend_driver
965 .create_token_restriction(state, restriction)
966 .await
967 }
968
969 async fn list_token_restrictions<'a>(
971 &self,
972 state: &ServiceState,
973 params: &TokenRestrictionListParameters,
974 ) -> Result<Vec<TokenRestriction>, TokenProviderError> {
975 self.tr_backend_driver
976 .list_token_restrictions(state, params)
977 .await
978 }
979
980 async fn update_token_restriction<'a>(
982 &self,
983 state: &ServiceState,
984 id: &'a str,
985 restriction: TokenRestrictionUpdate,
986 ) -> Result<TokenRestriction, TokenProviderError> {
987 self.tr_backend_driver
988 .update_token_restriction(state, id, restriction)
989 .await
990 }
991
992 async fn delete_token_restriction<'a>(
994 &self,
995 state: &ServiceState,
996 id: &'a str,
997 ) -> Result<(), TokenProviderError> {
998 self.tr_backend_driver
999 .delete_token_restriction(state, id)
1000 .await
1001 }
1002}
1003
1004#[cfg(test)]
1005mod tests {
1006 use chrono::Utc;
1007 use eyre::{Result, eyre};
1008 use std::sync::Arc;
1009 use tracing_test::traced_test;
1010 use uuid::Uuid;
1011
1012 use super::super::tests::setup_config;
1013 use super::*;
1014 use crate::application_credential::{
1015 MockApplicationCredentialProvider, types::ApplicationCredential,
1016 };
1017 use crate::assignment::{
1018 MockAssignmentProvider,
1019 types::{Assignment, AssignmentType, RoleAssignmentListParameters},
1020 };
1021 use crate::auth::AuthenticatedInfoBuilder;
1022 use crate::config::Config;
1023 use crate::identity::{MockIdentityProvider, types::UserResponseBuilder};
1024 use crate::provider::Provider;
1025 use crate::resource::{MockResourceProvider, types::*};
1026 use crate::revoke::MockRevokeProvider;
1027 use crate::tests::get_mocked_state;
1028 use crate::token::backend::MockTokenRestrictionBackend;
1029 use crate::trust::types::*;
1030
1031 fn generate_token(validity: Option<TimeDelta>) -> Result<Token> {
1033 Ok(Token::ProjectScope(ProjectScopePayload {
1034 methods: vec!["password".into()],
1035 user_id: Uuid::new_v4().simple().to_string(),
1036 project_id: Uuid::new_v4().simple().to_string(),
1037 audit_ids: vec!["Zm9vCg".into()],
1038 expires_at: Utc::now()
1039 .checked_add_signed(validity.unwrap_or_default())
1040 .ok_or(eyre!("timedelta apply failed"))?,
1041 ..Default::default()
1042 }))
1043 }
1044
1045 fn get_provider(config: &Config) -> TokenService {
1046 TokenService {
1047 config: config.clone(),
1048 backend_driver: Arc::new(FernetTokenProvider::new(config.clone())),
1049 tr_backend_driver: Arc::new(MockTokenRestrictionBackend::default()),
1050 }
1051 }
1052
1053 #[tokio::test]
1054 async fn test_populate_role_assignments() {
1055 let token_provider = get_provider(&Config::default());
1056 let mut assignment_mock = MockAssignmentProvider::default();
1057 assignment_mock
1058 .expect_list_role_assignments()
1059 .withf(|_, q: &RoleAssignmentListParameters| {
1060 q.project_id == Some("project_id".to_string())
1061 })
1062 .returning(|_, q: &RoleAssignmentListParameters| {
1063 Ok(vec![Assignment {
1064 role_id: "rid".into(),
1065 role_name: Some("role_name".into()),
1066 actor_id: q.user_id.clone().unwrap(),
1067 target_id: q.project_id.clone().unwrap(),
1068 r#type: AssignmentType::UserProject,
1069 inherited: false,
1070 implied_via: None,
1071 }])
1072 });
1073 assignment_mock
1074 .expect_list_role_assignments()
1075 .withf(|_, q: &RoleAssignmentListParameters| {
1076 q.domain_id == Some("domain_id".to_string())
1077 })
1078 .returning(|_, q: &RoleAssignmentListParameters| {
1079 Ok(vec![Assignment {
1080 role_id: "rid".into(),
1081 role_name: Some("role_name".into()),
1082 actor_id: q.user_id.clone().unwrap(),
1083 target_id: q.domain_id.clone().unwrap(),
1084 r#type: AssignmentType::UserProject,
1085 inherited: false,
1086 implied_via: None,
1087 }])
1088 });
1089 let provider = Provider::mocked_builder().mock_assignment(assignment_mock);
1090
1091 let state = get_mocked_state(None, Some(provider));
1092
1093 let mut ptoken = Token::ProjectScope(ProjectScopePayload {
1094 user_id: "bar".into(),
1095 project_id: "project_id".into(),
1096 ..Default::default()
1097 });
1098 token_provider
1099 .populate_role_assignments(&state, &mut ptoken)
1100 .await
1101 .unwrap();
1102
1103 if let Token::ProjectScope(data) = ptoken {
1104 assert_eq!(
1105 data.roles.unwrap(),
1106 vec![RoleRef {
1107 id: "rid".into(),
1108 name: Some("role_name".into()),
1109 domain_id: None
1110 }]
1111 );
1112 } else {
1113 panic!("Not project scope");
1114 }
1115
1116 let mut dtoken = Token::DomainScope(DomainScopePayload {
1117 user_id: "bar".into(),
1118 domain_id: "domain_id".into(),
1119 ..Default::default()
1120 });
1121 token_provider
1122 .populate_role_assignments(&state, &mut dtoken)
1123 .await
1124 .unwrap();
1125
1126 if let Token::DomainScope(data) = dtoken {
1127 assert_eq!(
1128 data.roles.unwrap(),
1129 vec![RoleRef {
1130 id: "rid".into(),
1131 name: Some("role_name".into()),
1132 domain_id: None
1133 }]
1134 );
1135 } else {
1136 panic!("Not domain scope");
1137 }
1138
1139 let mut utoken = Token::Unscoped(UnscopedPayload {
1140 user_id: "bar".into(),
1141 ..Default::default()
1142 });
1143 assert!(
1144 token_provider
1145 .populate_role_assignments(&state, &mut utoken)
1146 .await
1147 .is_ok()
1148 );
1149 }
1150
1151 #[tokio::test]
1153 #[traced_test]
1154 async fn test_validate_token_revoked() {
1155 let token = generate_token(Some(TimeDelta::hours(1))).unwrap();
1156
1157 let config = setup_config();
1158 let token_provider = get_provider(&config);
1159 let mut revoke_mock = MockRevokeProvider::default();
1160 revoke_mock
1162 .expect_is_token_revoked()
1163 .returning(|_, _| Ok(true));
1168
1169 let mut identity_mock = MockIdentityProvider::default();
1170 let token_clone = token.clone();
1171 identity_mock
1172 .expect_get_user()
1173 .withf(move |_, id: &'_ str| id == token_clone.user_id())
1174 .returning(|_, id: &'_ str| {
1175 Ok(Some(
1176 UserResponseBuilder::default()
1177 .domain_id("user_domain_id")
1178 .enabled(true)
1179 .name("name")
1180 .id(id)
1181 .build()
1182 .unwrap(),
1183 ))
1184 });
1185 let mut resource_mock = MockResourceProvider::default();
1186 let token_clone2 = token.clone();
1187 resource_mock
1188 .expect_get_project()
1189 .withf(move |_, id: &'_ str| id == token_clone2.project_id().unwrap())
1190 .returning(|_, id: &'_ str| {
1191 Ok(Some(Project {
1192 id: id.to_string(),
1193 name: "project".to_string(),
1194 ..Default::default()
1195 }))
1196 });
1197
1198 let mut assignment_mock = MockAssignmentProvider::default();
1199 let token_clone3 = token.clone();
1200 assignment_mock
1201 .expect_list_role_assignments()
1202 .withf(move |_, q: &RoleAssignmentListParameters| {
1203 q.project_id == token_clone3.project_id().cloned()
1204 })
1205 .returning(|_, q: &RoleAssignmentListParameters| {
1206 Ok(vec![Assignment {
1207 role_id: "rid".into(),
1208 role_name: Some("role_name".into()),
1209 actor_id: q.user_id.clone().unwrap(),
1210 target_id: q.project_id.clone().unwrap(),
1211 r#type: AssignmentType::UserProject,
1212 inherited: false,
1213 implied_via: None,
1214 }])
1215 });
1216 let provider = Provider::mocked_builder()
1217 .mock_assignment(assignment_mock)
1218 .mock_identity(identity_mock)
1219 .mock_revoke(revoke_mock)
1220 .mock_resource(resource_mock);
1221
1222 let state = get_mocked_state(Some(config), Some(provider));
1223
1224 let credential = token_provider.encode_token(&token).unwrap();
1225 match token_provider
1226 .validate_token(&state, &credential, Some(false), None)
1227 .await
1228 {
1229 Err(TokenProviderError::TokenRevoked) => {}
1230 _ => {
1231 panic!("token must be revoked")
1232 }
1233 }
1234 }
1235
1236 #[tokio::test]
1237 async fn test_populate_role_assignments_application_credential() {
1238 let token_provider = get_provider(&Config::default());
1239 let mut assignment_mock = MockAssignmentProvider::default();
1240 assignment_mock
1241 .expect_list_role_assignments()
1242 .withf(|_, q: &RoleAssignmentListParameters| {
1243 q.project_id == Some("project_id".to_string())
1244 && q.user_id == Some("bar".to_string())
1245 })
1246 .returning(|_, q: &RoleAssignmentListParameters| {
1247 Ok(vec![Assignment {
1248 role_id: "role_1".into(),
1249 role_name: Some("role_name".into()),
1250 actor_id: q.user_id.clone().unwrap(),
1251 target_id: q.project_id.clone().unwrap(),
1252 r#type: AssignmentType::UserProject,
1253 inherited: false,
1254 implied_via: None,
1255 }])
1256 });
1257 assignment_mock
1258 .expect_list_role_assignments()
1259 .withf(|_, q: &RoleAssignmentListParameters| {
1260 q.domain_id == Some("domain_id".to_string())
1261 })
1262 .returning(|_, q: &RoleAssignmentListParameters| {
1263 Ok(vec![Assignment {
1264 role_id: "rid".into(),
1265 role_name: Some("role_name".into()),
1266 actor_id: q.user_id.clone().unwrap(),
1267 target_id: q.domain_id.clone().unwrap(),
1268 r#type: AssignmentType::UserProject,
1269 inherited: false,
1270 implied_via: None,
1271 }])
1272 });
1273 let mut ac_mock = MockApplicationCredentialProvider::default();
1274 ac_mock
1275 .expect_get_application_credential()
1276 .withf(|_, id: &'_ str| id == "app_cred_id")
1277 .returning(|_, id: &'_ str| {
1278 Ok(Some(ApplicationCredential {
1279 access_rules: None,
1280 description: None,
1281 expires_at: None,
1282 id: id.into(),
1283 name: "foo".into(),
1284 project_id: "project_id".into(),
1285 roles: vec![
1286 RoleRef {
1287 id: "role_1".into(),
1288 name: Some("role_name_1".into()),
1289 domain_id: None,
1290 },
1291 RoleRef {
1292 id: "role_2".into(),
1293 name: Some("role_name_2".into()),
1294 domain_id: None,
1295 },
1296 ],
1297 unrestricted: false,
1298 user_id: "bar".into(),
1299 }))
1300 });
1301 ac_mock
1302 .expect_get_application_credential()
1303 .withf(|_, id: &'_ str| id == "app_cred_bad_roles")
1304 .returning(|_, id: &'_ str| {
1305 Ok(Some(ApplicationCredential {
1306 access_rules: None,
1307 description: None,
1308 expires_at: None,
1309 id: id.into(),
1310 name: "foo".into(),
1311 project_id: "project_id".into(),
1312 roles: vec![
1313 RoleRef {
1314 id: "-role_1".into(),
1315 name: Some("-role_name_1".into()),
1316 domain_id: None,
1317 },
1318 RoleRef {
1319 id: "-role_2".into(),
1320 name: Some("-role_name_2".into()),
1321 domain_id: None,
1322 },
1323 ],
1324 unrestricted: false,
1325 user_id: "bar".into(),
1326 }))
1327 });
1328 ac_mock
1329 .expect_get_application_credential()
1330 .withf(|_, id: &'_ str| id == "missing")
1331 .returning(|_, _| Ok(None));
1332 let provider = Provider::mocked_builder()
1333 .mock_application_credential(ac_mock)
1334 .mock_assignment(assignment_mock);
1335
1336 let state = get_mocked_state(None, Some(provider));
1337
1338 let mut token = Token::ApplicationCredential(ApplicationCredentialPayload {
1339 user_id: "bar".into(),
1340 project_id: "project_id".into(),
1341 application_credential_id: "app_cred_id".into(),
1342 ..Default::default()
1343 });
1344 token_provider
1345 .populate_role_assignments(&state, &mut token)
1346 .await
1347 .unwrap();
1348
1349 if let Token::ApplicationCredential(..) = &token {
1350 assert_eq!(
1351 token.effective_roles().unwrap(),
1352 &vec![RoleRef {
1353 id: "role_1".into(),
1354 name: Some("role_name_1".into()),
1355 domain_id: None,
1356 }],
1357 "only still active role assignment is returned"
1358 );
1359 } else {
1360 panic!("Not application credential scope");
1361 }
1362
1363 if let Err(TokenProviderError::ApplicationCredentialNotFound(id)) = token_provider
1365 .populate_role_assignments(
1366 &state,
1367 &mut Token::ApplicationCredential(ApplicationCredentialPayload {
1368 user_id: "bar".into(),
1369 project_id: "project_id".into(),
1370 application_credential_id: "missing".into(),
1371 ..Default::default()
1372 }),
1373 )
1374 .await
1375 {
1376 assert_eq!(id, "missing");
1377 } else {
1378 panic!("role expansion for missing application credential should fail");
1379 }
1380
1381 if let Err(TokenProviderError::ActorHasNoRolesOnTarget) = token_provider
1383 .populate_role_assignments(
1384 &state,
1385 &mut Token::ApplicationCredential(ApplicationCredentialPayload {
1386 user_id: "bar".into(),
1387 project_id: "project_id".into(),
1388 application_credential_id: "app_cred_bad_roles".into(),
1389 ..Default::default()
1390 }),
1391 )
1392 .await
1393 {
1394 } else {
1395 panic!(
1396 "role expansion for application credential with roles the user does not have anymore should fail"
1397 );
1398 }
1399 }
1400
1401 #[tokio::test]
1402 async fn test_create_unscoped_token() {
1403 let token_provider = get_provider(&Config::default());
1404 let now = Utc::now();
1405 let token = token_provider
1406 .create_unscoped_token(
1407 &AuthenticatedInfoBuilder::default()
1408 .user_id("uid")
1409 .expires_at(now)
1410 .build()
1411 .unwrap(),
1412 )
1413 .unwrap();
1414 assert_eq!(*token.expires_at(), now);
1415 assert_eq!(*token.user_id(), "uid");
1416 let token = token_provider
1417 .create_unscoped_token(
1418 &AuthenticatedInfoBuilder::default()
1419 .user_id("uid")
1420 .build()
1421 .unwrap(),
1422 )
1423 .unwrap();
1424 assert!(now < *token.expires_at());
1425 assert_eq!(*token.user_id(), "uid");
1426 assert!(token.project_id().is_none());
1427 }
1428
1429 #[tokio::test]
1430 async fn test_create_project_scope_token() {
1431 let token_provider = get_provider(&Config::default());
1432 let now = Utc::now();
1433 let token = token_provider
1434 .create_project_scope_token(
1435 &AuthenticatedInfoBuilder::default()
1436 .user_id("uid")
1437 .expires_at(now)
1438 .build()
1439 .unwrap(),
1440 &ProjectBuilder::default()
1441 .id("pid")
1442 .domain_id("did")
1443 .name("pname")
1444 .enabled(true)
1445 .build()
1446 .unwrap(),
1447 )
1448 .unwrap();
1449 assert_eq!(*token.expires_at(), now);
1450 assert_eq!(*token.user_id(), "uid");
1451 let token = token_provider
1452 .create_project_scope_token(
1453 &AuthenticatedInfoBuilder::default()
1454 .user_id("uid")
1455 .build()
1456 .unwrap(),
1457 &ProjectBuilder::default()
1458 .id("pid")
1459 .domain_id("did")
1460 .name("pname")
1461 .enabled(true)
1462 .build()
1463 .unwrap(),
1464 )
1465 .unwrap();
1466 assert!(now < *token.expires_at());
1467 assert_eq!(*token.user_id(), "uid");
1468 assert_eq!(*token.project_id().unwrap(), "pid");
1469 }
1470
1471 #[tokio::test]
1472 async fn test_create_domain_scope_token() {
1473 let token_provider = get_provider(&Config::default());
1474 let now = Utc::now();
1475 let token = token_provider
1476 .create_domain_scope_token(
1477 &AuthenticatedInfoBuilder::default()
1478 .user_id("uid")
1479 .expires_at(now)
1480 .build()
1481 .unwrap(),
1482 &DomainBuilder::default()
1483 .id("did")
1484 .name("pname")
1485 .enabled(true)
1486 .build()
1487 .unwrap(),
1488 )
1489 .unwrap();
1490 assert_eq!(*token.expires_at(), now);
1491 assert_eq!(*token.user_id(), "uid");
1492 let token = token_provider
1493 .create_domain_scope_token(
1494 &AuthenticatedInfoBuilder::default()
1495 .user_id("uid")
1496 .build()
1497 .unwrap(),
1498 &DomainBuilder::default()
1499 .id("did")
1500 .name("pname")
1501 .enabled(true)
1502 .build()
1503 .unwrap(),
1504 )
1505 .unwrap();
1506 assert!(now < *token.expires_at());
1507 assert_eq!(*token.user_id(), "uid");
1508 assert_eq!(token.domain().unwrap().id, "did");
1509 }
1510
1511 #[tokio::test]
1512 async fn test_create_system_token() {
1513 let token_provider = get_provider(&Config::default());
1514 let now = Utc::now();
1515 let token = token_provider
1516 .create_system_scoped_token(
1517 &AuthenticatedInfoBuilder::default()
1518 .user_id("uid")
1519 .expires_at(now)
1520 .build()
1521 .unwrap(),
1522 )
1523 .unwrap();
1524 assert_eq!(*token.expires_at(), now);
1525 assert_eq!(*token.user_id(), "uid");
1526 let token = token_provider
1527 .create_system_scoped_token(
1528 &AuthenticatedInfoBuilder::default()
1529 .user_id("uid")
1530 .build()
1531 .unwrap(),
1532 )
1533 .unwrap();
1534 assert!(now < *token.expires_at());
1535 assert_eq!(*token.user_id(), "uid");
1536 if let Token::SystemScope(data) = token {
1537 assert_eq!(data.system_id, "system");
1538 } else {
1539 panic!("wrong token type");
1540 }
1541 }
1542
1543 #[tokio::test]
1544 async fn test_create_trust_token() {
1545 let token_provider = get_provider(&Config::default());
1546 let now = Utc::now();
1547 let token = token_provider
1548 .create_trust_token(
1549 &AuthenticatedInfoBuilder::default()
1550 .user_id("uid")
1551 .expires_at(now)
1552 .build()
1553 .unwrap(),
1554 &TrustBuilder::default()
1555 .id("tid")
1556 .impersonation(false)
1557 .trustor_user_id("trustor_uid")
1558 .trustee_user_id("trustor_uid")
1559 .build()
1560 .unwrap(),
1561 )
1562 .unwrap();
1563 assert_eq!(*token.expires_at(), now);
1564 assert_eq!(*token.user_id(), "uid");
1565 let token = token_provider
1566 .create_trust_token(
1567 &AuthenticatedInfoBuilder::default()
1568 .user_id("uid")
1569 .build()
1570 .unwrap(),
1571 &TrustBuilder::default()
1572 .id("tid")
1573 .impersonation(false)
1574 .trustor_user_id("trustor_uid")
1575 .trustee_user_id("trustor_uid")
1576 .project_id("pid")
1577 .build()
1578 .unwrap(),
1579 )
1580 .unwrap();
1581 assert!(now < *token.expires_at());
1582 assert_eq!(*token.user_id(), "uid");
1583 if let Token::Trust(data) = token {
1584 assert_eq!(data.trust_id, "tid");
1585 } else {
1586 panic!("wrong token type");
1587 }
1588
1589 let token = token_provider
1591 .create_trust_token(
1592 &AuthenticatedInfoBuilder::default()
1593 .user_id("uid")
1594 .build()
1595 .unwrap(),
1596 &TrustBuilder::default()
1597 .id("tid")
1598 .impersonation(false)
1599 .trustor_user_id("trustor_uid")
1600 .trustee_user_id("trustor_uid")
1601 .build()
1602 .unwrap(),
1603 )
1604 .unwrap();
1605 assert!(now < *token.expires_at());
1606 assert_eq!(*token.user_id(), "uid");
1607 if let Token::Unscoped(_data) = token {
1608 } else {
1609 panic!("wrong token type");
1610 }
1611 }
1612
1613 #[tokio::test]
1614 async fn test_create_restricted_token() {
1615 let token_provider = get_provider(&Config::default());
1616 let now = Utc::now();
1617 let token = token_provider
1618 .create_restricted_token(
1619 &AuthenticatedInfoBuilder::default()
1620 .user_id("uid")
1621 .expires_at(now)
1622 .build()
1623 .unwrap(),
1624 &AuthzInfo::System,
1625 &TokenRestrictionBuilder::default()
1626 .id("rid")
1627 .domain_id("did")
1628 .project_id("pid")
1629 .allow_renew(true)
1630 .allow_rescope(true)
1631 .role_ids([])
1632 .build()
1633 .unwrap(),
1634 )
1635 .unwrap();
1636 assert_eq!(*token.expires_at(), now);
1637 assert_eq!(*token.user_id(), "uid");
1638 let token = token_provider
1639 .create_restricted_token(
1640 &AuthenticatedInfoBuilder::default()
1641 .user_id("uid")
1642 .build()
1643 .unwrap(),
1644 &AuthzInfo::System,
1645 &TokenRestrictionBuilder::default()
1646 .id("rid")
1647 .domain_id("did")
1648 .project_id("pid")
1649 .allow_renew(true)
1650 .allow_rescope(true)
1651 .role_ids([])
1652 .build()
1653 .unwrap(),
1654 )
1655 .unwrap();
1656 assert!(now < *token.expires_at());
1657 assert_eq!(*token.user_id(), "uid");
1658 if let Token::Restricted(data) = token {
1659 assert_eq!(data.token_restriction_id, "rid");
1660 } else {
1661 panic!("wrong token type");
1662 }
1663 }
1664}