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