1use std::collections::{BTreeMap, BTreeSet};
11use std::sync::LazyLock;
12
13use mz_auth::AuthenticatorKind;
14use mz_repr::role_id::RoleId;
15use mz_repr::user::{ExternalUserMetadata, InternalUserMetadata};
16use serde::Serialize;
17
18pub const SYSTEM_USER_NAME: &str = "mz_system";
19pub static SYSTEM_USER: LazyLock<User> = LazyLock::new(|| User {
20 name: SYSTEM_USER_NAME.into(),
21 external_metadata: None,
22 internal_metadata: None,
23 authenticator_kind: None,
24 groups: None,
25});
26
27pub const SUPPORT_USER_NAME: &str = "mz_support";
28pub static SUPPORT_USER: LazyLock<User> = LazyLock::new(|| User {
29 name: SUPPORT_USER_NAME.into(),
30 external_metadata: None,
31 internal_metadata: None,
32 authenticator_kind: None,
33 groups: None,
34});
35
36pub const ANALYTICS_USER_NAME: &str = "mz_analytics";
37pub static ANALYTICS_USER: LazyLock<User> = LazyLock::new(|| User {
38 name: ANALYTICS_USER_NAME.into(),
39 external_metadata: None,
40 internal_metadata: None,
41 authenticator_kind: None,
42 groups: None,
43});
44
45pub static INTERNAL_USER_NAMES: LazyLock<BTreeSet<String>> = LazyLock::new(|| {
46 [&SYSTEM_USER, &SUPPORT_USER, &ANALYTICS_USER]
47 .into_iter()
48 .map(|user| user.name.clone())
49 .collect()
50});
51
52pub static INTERNAL_USER_NAME_TO_DEFAULT_CLUSTER: LazyLock<BTreeMap<String, String>> =
53 LazyLock::new(|| {
54 [
55 (&SYSTEM_USER, "mz_system"),
56 (&SUPPORT_USER, "mz_catalog_server"),
57 (&ANALYTICS_USER, "mz_analytics"),
58 ]
59 .into_iter()
60 .map(|(user, cluster)| (user.name.clone(), cluster.to_string()))
61 .collect()
62 });
63
64pub static HTTP_DEFAULT_USER: LazyLock<User> = LazyLock::new(|| User {
65 name: "anonymous_http_user".into(),
66 external_metadata: None,
67 internal_metadata: None,
68 authenticator_kind: None,
69 groups: None,
70});
71
72#[derive(Debug, Clone, Serialize)]
74pub struct User {
75 pub name: String,
77 pub external_metadata: Option<ExternalUserMetadata>,
79 pub internal_metadata: Option<InternalUserMetadata>,
82 pub authenticator_kind: Option<AuthenticatorKind>,
85 pub groups: Option<Vec<String>>,
88}
89
90impl From<&User> for mz_pgwire_common::UserMetadata {
91 fn from(user: &User) -> mz_pgwire_common::UserMetadata {
92 mz_pgwire_common::UserMetadata {
93 is_admin: user.is_external_admin(),
94 should_limit_connections: user.limit_max_connections(),
95 }
96 }
97}
98
99impl PartialEq for User {
100 fn eq(&self, other: &User) -> bool {
101 self.name == other.name
102 }
103}
104
105impl User {
106 pub fn is_internal(&self) -> bool {
108 INTERNAL_USER_NAMES.contains(&self.name)
109 }
110
111 pub fn is_external_admin(&self) -> bool {
113 self.external_metadata
114 .as_ref()
115 .map(|metadata| metadata.admin)
116 .clone()
117 .unwrap_or(false)
118 }
119
120 pub fn is_internal_admin(&self) -> bool {
121 self.internal_metadata
122 .as_ref()
123 .map(|metadata| metadata.superuser)
124 .clone()
125 .unwrap_or(false)
126 }
127
128 pub fn is_superuser(&self) -> bool {
130 matches!(self.kind(), UserKind::Superuser)
131 }
132
133 pub fn is_system_user(&self) -> bool {
135 self == &*SYSTEM_USER
136 }
137
138 pub fn limit_max_connections(&self) -> bool {
140 !self.is_internal()
141 }
142
143 pub fn kind(&self) -> UserKind {
145 if self.is_external_admin() || self.is_system_user() || self.is_internal_admin() {
146 UserKind::Superuser
147 } else {
148 UserKind::Regular
149 }
150 }
151}
152
153#[derive(Debug, Copy, Clone)]
154pub enum UserKind {
155 Regular,
156 Superuser,
157}
158
159pub const MZ_SYSTEM_ROLE_ID: RoleId = RoleId::System(1);
160pub const MZ_SUPPORT_ROLE_ID: RoleId = RoleId::System(2);
161pub const MZ_ANALYTICS_ROLE_ID: RoleId = RoleId::System(3);
162pub const MZ_JWT_SYNC_ROLE_ID: RoleId = RoleId::System(4);
165pub const JWT_SYNC_ROLE_NAME: &str = "mz_jwt_sync";
166pub const MZ_MONITOR_ROLE_ID: RoleId = RoleId::Predefined(1);
167pub const MZ_MONITOR_REDACTED_ROLE_ID: RoleId = RoleId::Predefined(2);
168
169#[derive(Debug, Clone)]
174pub struct RoleMetadata {
175 pub authenticated_role: RoleId,
177 pub session_role: RoleId,
181 pub current_role: RoleId,
184}
185
186impl RoleMetadata {
187 pub fn new(id: RoleId) -> RoleMetadata {
189 RoleMetadata {
190 authenticated_role: id,
191 session_role: id,
192 current_role: id,
193 }
194 }
195}