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