alibi_plugins/organization/
extensions.rs1use alibi_core::store::TeamStore;
3use alibi_core::types::{
4 CreateTeam, Organization, OrganizationPermissions, Team, TeamMember, UpdateTeam,
5};
6use alibi_core::wire::{SessionView, UserView};
7use alibi_core::{AuthRequest, AuthResult};
8use async_trait::async_trait;
9use std::sync::Arc;
10
11#[derive(Debug, Clone, Default)]
12pub struct TeamLimitContext {
13 pub organization_id: String,
14 pub team_id: Option<String>,
15 pub session: Option<SessionView>,
16 pub user: Option<UserView>,
17 pub request: Option<AuthRequest>,
19}
20
21#[async_trait]
29pub trait OrganizationLimitResolver: std::fmt::Debug + Send + Sync {
30 async fn maximum_teams(&self, _context: &TeamLimitContext) -> AuthResult<Option<f64>> {
31 Ok(None)
32 }
33 async fn maximum_team_members(&self, _context: &TeamLimitContext) -> AuthResult<Option<f64>> {
34 Ok(None)
35 }
36 async fn maximum_roles(&self, _organization_id: &str) -> AuthResult<Option<f64>> {
37 Ok(None)
38 }
39}
40
41#[derive(Debug, Clone)]
42pub struct TeamHookContext {
43 pub organization: Organization,
44 pub user: Option<UserView>,
45}
46
47#[async_trait]
48pub trait OrganizationTeamHooks: std::fmt::Debug + Send + Sync {
49 async fn before_create(
50 &self,
51 _data: &mut CreateTeam,
52 _context: &TeamHookContext,
53 ) -> AuthResult<()> {
54 Ok(())
55 }
56 async fn after_create(&self, _team: &Team, _context: &TeamHookContext) -> AuthResult<()> {
57 Ok(())
58 }
59 async fn before_update(
60 &self,
61 _team: &Team,
62 _updates: &mut UpdateTeam,
63 _context: &TeamHookContext,
64 ) -> AuthResult<()> {
65 Ok(())
66 }
67 async fn after_update(&self, _team: &Team, _context: &TeamHookContext) -> AuthResult<()> {
68 Ok(())
69 }
70 async fn before_delete(&self, _team: &Team, _context: &TeamHookContext) -> AuthResult<()> {
71 Ok(())
72 }
73 async fn after_delete(&self, _team: &Team, _context: &TeamHookContext) -> AuthResult<()> {
74 Ok(())
75 }
76 async fn before_add_member(
77 &self,
78 _team: &Team,
79 _user: &UserView,
80 _context: &TeamHookContext,
81 ) -> AuthResult<()> {
82 Ok(())
83 }
84 async fn after_add_member(
85 &self,
86 _member: &TeamMember,
87 _team: &Team,
88 _user: &UserView,
89 _context: &TeamHookContext,
90 ) -> AuthResult<()> {
91 Ok(())
92 }
93 async fn before_remove_member(
94 &self,
95 _member: &TeamMember,
96 _team: &Team,
97 _user: &UserView,
98 _context: &TeamHookContext,
99 ) -> AuthResult<()> {
100 Ok(())
101 }
102 async fn after_remove_member(
103 &self,
104 _member: &TeamMember,
105 _team: &Team,
106 _user: &UserView,
107 _context: &TeamHookContext,
108 ) -> AuthResult<()> {
109 Ok(())
110 }
111}
112
113#[derive(Clone)]
114pub struct DefaultTeamContext {
115 pub request: Option<AuthRequest>,
116 pub user: UserView,
117 pub session: Option<SessionView>,
118 pub config: Arc<alibi_core::AuthConfig>,
119}
120
121impl std::fmt::Debug for DefaultTeamContext {
122 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
123 f.debug_struct("DefaultTeamContext").finish_non_exhaustive()
124 }
125}
126
127#[async_trait]
128pub trait DefaultTeamFactory: std::fmt::Debug + Send + Sync {
129 async fn create(
130 &self,
131 organization: &Organization,
132 context: &DefaultTeamContext,
133 store: &dyn TeamStore,
134 ) -> AuthResult<Option<Team>>;
135}
136
137#[derive(Debug, Clone)]
138pub struct TeamsConfig {
139 pub enabled: bool,
140 pub create_default_team: bool,
141 pub allow_removing_all_teams: bool,
142 pub maximum_teams: Option<f64>,
147 pub maximum_members_per_team: Option<f64>,
152 pub limit_resolver: Option<Arc<dyn OrganizationLimitResolver>>,
153 pub hooks: Option<Arc<dyn OrganizationTeamHooks>>,
154 pub default_team_factory: Option<Arc<dyn DefaultTeamFactory>>,
155}
156impl Default for TeamsConfig {
157 fn default() -> Self {
158 Self {
159 enabled: false,
160 create_default_team: true,
161 allow_removing_all_teams: false,
162 maximum_teams: None,
163 maximum_members_per_team: None,
164 limit_resolver: None,
165 hooks: None,
166 default_team_factory: None,
167 }
168 }
169}
170
171#[derive(Debug, Clone, Default)]
172pub struct DynamicAccessControlConfig {
173 pub enabled: bool,
174 pub maximum_roles_per_organization: Option<f64>,
179 pub limit_resolver: Option<Arc<dyn OrganizationLimitResolver>>,
180}
181
182#[must_use]
183pub fn default_organization_statements() -> OrganizationPermissions {
184 [
185 ("organization", vec!["update", "delete"]),
186 ("member", vec!["create", "update", "delete"]),
187 ("invitation", vec!["create", "cancel"]),
188 ("team", vec!["create", "update", "delete"]),
189 ("ac", vec!["create", "read", "update", "delete"]),
190 ]
191 .into_iter()
192 .map(|(resource, actions)| {
193 (
194 resource.to_owned(),
195 actions.into_iter().map(str::to_owned).collect(),
196 )
197 })
198 .collect()
199}
200
201pub(super) fn team_callback_error(error: alibi_core::AuthError) -> alibi_core::AuthError {
204 match error {
205 error @ (alibi_core::AuthError::Api { .. }
206 | alibi_core::AuthError::Upstream { .. }
207 | alibi_core::AuthError::CallbackFailure(_)) => error,
208 error if error.status_code() != 500 => error,
209 error => alibi_core::AuthError::CallbackFailure(Box::new(error)),
210 }
211}