alibi_plugins/sso/
organization_provisioning.rs1#[derive(Clone, Debug)]
3pub struct SsoOrganizationProvisioning {
4 pub disabled: bool,
5 pub default_role: String,
6 pub get_role: Option<SsoRoleResolver>,
7}
8impl Default for SsoOrganizationProvisioning {
9 fn default() -> Self {
10 Self {
11 disabled: false,
12 default_role: "member".into(),
13 get_role: None,
14 }
15 }
16}
17
18impl super::SsoPlugin {
19 pub(super) async fn provision_organization<S: alibi_core::AuthSchema>(
20 &self,
21 user: &alibi_core::wire::UserView,
22 provider: &alibi_core::store::SsoProvider,
23 ctx: &alibi_core::AuthContext<S>,
24 profile: &serde_json::Value,
25 token: Option<&crate::oauth::OAuthTokenSet>,
26 ) -> alibi_core::AuthResult<()> {
27 if self.config.organization_provisioning.disabled
28 || ctx
29 .get_metadata(crate::organization::METADATA_ENABLED)
30 .is_none()
31 {
32 return Ok(());
33 }
34 let Some(organization_id) = provider
35 .organization_id
36 .as_deref()
37 .filter(|id| !id.is_empty())
38 else {
39 return Ok(());
40 };
41 if ctx
42 .database
43 .get_member(organization_id, &user.id)
44 .await?
45 .is_some()
46 {
47 return Ok(());
48 }
49 if let Some(email) = user.email.as_deref()
50 && ctx
51 .database
52 .get_pending_invitation(organization_id, &email.to_lowercase())
53 .await?
54 .is_some()
55 {
56 return Ok(());
57 }
58 let role = if let Some(resolver) = &self.config.organization_provisioning.get_role {
59 resolver
60 .0
61 .get_role(super::SsoProvisioningData {
62 user: user.clone(),
63 user_info: profile.clone(),
64 token: token.cloned(),
65 provider: provider.clone(),
66 })
67 .await?
68 } else {
69 let role = &self.config.organization_provisioning.default_role;
70 if role.is_empty() {
71 "member".into()
72 } else {
73 role.clone()
74 }
75 };
76 _ = ctx
77 .database
78 .create_member(alibi_core::CreateMember::new(
79 organization_id,
80 &user.id,
81 role,
82 ))
83 .await?;
84 Ok(())
85 }
86}
87
88#[async_trait::async_trait]
90pub trait SsoOrganizationRoleResolver: Send + Sync {
91 async fn get_role(&self, data: super::SsoProvisioningData) -> alibi_core::AuthResult<String>;
92}
93#[derive(Clone)]
94pub struct SsoRoleResolver(pub std::sync::Arc<dyn SsoOrganizationRoleResolver>);
95impl std::fmt::Debug for SsoRoleResolver {
96 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
97 formatter
98 .debug_struct("SsoRoleResolver")
99 .finish_non_exhaustive()
100 }
101}