1use std::fmt::Debug;
16use std::sync::Arc;
17
18use api::v1::greptime_request::Request;
19use common_telemetry::debug;
20use sql::statements::statement::Statement;
21
22use crate::error::{PermissionDeniedSnafu, Result};
23use crate::user_info::DefaultUserInfo;
24use crate::{PermissionCheckerRef, UserInfo, UserInfoRef};
25
26#[derive(Debug, Clone)]
27pub enum PermissionReq<'a> {
28 GrpcRequest(&'a Request),
29 SqlStatement(&'a Statement),
30 PromQuery,
31 LogQuery,
32 Opentsdb,
33 LineProtocol,
34 PromStoreWrite,
35 PromStoreRead,
36 Otlp,
37 LogWrite,
38 BulkInsert,
39}
40
41impl<'a> PermissionReq<'a> {
42 pub fn is_readonly(&self) -> bool {
44 match self {
45 PermissionReq::GrpcRequest(Request::Query(_))
46 | PermissionReq::PromQuery
47 | PermissionReq::LogQuery
48 | PermissionReq::PromStoreRead => true,
49 PermissionReq::SqlStatement(stmt) => stmt.is_readonly(),
50
51 PermissionReq::GrpcRequest(_)
52 | PermissionReq::Opentsdb
53 | PermissionReq::LineProtocol
54 | PermissionReq::PromStoreWrite
55 | PermissionReq::Otlp
56 | PermissionReq::LogWrite
57 | PermissionReq::BulkInsert => false,
58 }
59 }
60
61 pub fn is_write(&self) -> bool {
63 !self.is_readonly()
64 }
65}
66
67#[derive(Debug)]
68pub enum PermissionResp {
69 Allow,
70 Reject,
71}
72
73pub trait PermissionChecker: Send + Sync {
74 fn check_permission(
75 &self,
76 user_info: UserInfoRef,
77 req: PermissionReq,
78 ) -> Result<PermissionResp>;
79}
80
81impl PermissionChecker for Option<&PermissionCheckerRef> {
82 fn check_permission(
83 &self,
84 user_info: UserInfoRef,
85 req: PermissionReq,
86 ) -> Result<PermissionResp> {
87 match self {
88 Some(checker) => match checker.check_permission(user_info, req) {
89 Ok(PermissionResp::Reject) => PermissionDeniedSnafu.fail(),
90 Ok(PermissionResp::Allow) => Ok(PermissionResp::Allow),
91 Err(e) => Err(e),
92 },
93 None => Ok(PermissionResp::Allow),
94 }
95 }
96}
97
98pub struct DefaultPermissionChecker;
101
102impl DefaultPermissionChecker {
103 pub fn arc() -> PermissionCheckerRef {
105 Arc::new(DefaultPermissionChecker)
106 }
107}
108
109impl PermissionChecker for DefaultPermissionChecker {
110 fn check_permission(
111 &self,
112 user_info: UserInfoRef,
113 req: PermissionReq,
114 ) -> Result<PermissionResp> {
115 if let Some(default_user) = user_info.as_any().downcast_ref::<DefaultUserInfo>() {
116 let permission_mode = default_user.permission_mode();
117
118 if req.is_readonly() && !permission_mode.can_read() {
119 debug!(
120 "Permission denied: read operation not allowed, user = {}, permission = {}",
121 default_user.username(),
122 permission_mode.as_str()
123 );
124 return Ok(PermissionResp::Reject);
125 }
126
127 if req.is_write() && !permission_mode.can_write() {
128 debug!(
129 "Permission denied: write operation not allowed, user = {}, permission = {}",
130 default_user.username(),
131 permission_mode.as_str()
132 );
133 return Ok(PermissionResp::Reject);
134 }
135 }
136
137 Ok(PermissionResp::Allow)
139 }
140}
141#[cfg(test)]
142mod tests {
143 use super::*;
144 use crate::user_info::PermissionMode;
145
146 #[test]
147 fn test_default_permission_checker_allow_all_operations() {
148 let checker = DefaultPermissionChecker;
149 let user_info =
150 DefaultUserInfo::with_name_and_permission("test_user", PermissionMode::ReadWrite);
151
152 let read_req = PermissionReq::PromQuery;
153 let write_req = PermissionReq::PromStoreWrite;
154
155 let read_result = checker
156 .check_permission(user_info.clone(), read_req)
157 .unwrap();
158 let write_result = checker.check_permission(user_info, write_req).unwrap();
159
160 assert!(matches!(read_result, PermissionResp::Allow));
161 assert!(matches!(write_result, PermissionResp::Allow));
162 }
163
164 #[test]
165 fn test_default_permission_checker_readonly_user() {
166 let checker = DefaultPermissionChecker;
167 let user_info =
168 DefaultUserInfo::with_name_and_permission("readonly_user", PermissionMode::ReadOnly);
169
170 let read_req = PermissionReq::PromQuery;
171 let write_req = PermissionReq::PromStoreWrite;
172
173 let read_result = checker
174 .check_permission(user_info.clone(), read_req)
175 .unwrap();
176 let write_result = checker.check_permission(user_info, write_req).unwrap();
177
178 assert!(matches!(read_result, PermissionResp::Allow));
179 assert!(matches!(write_result, PermissionResp::Reject));
180 }
181
182 #[test]
183 fn test_default_permission_checker_writeonly_user() {
184 let checker = DefaultPermissionChecker;
185 let user_info =
186 DefaultUserInfo::with_name_and_permission("writeonly_user", PermissionMode::WriteOnly);
187
188 let read_req = PermissionReq::LogQuery;
189 let write_req = PermissionReq::LogWrite;
190
191 let read_result = checker
192 .check_permission(user_info.clone(), read_req)
193 .unwrap();
194 let write_result = checker.check_permission(user_info, write_req).unwrap();
195
196 assert!(matches!(read_result, PermissionResp::Reject));
197 assert!(matches!(write_result, PermissionResp::Allow));
198 }
199}