auth/
user_info.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::any::Any;
16use std::fmt::Debug;
17use std::sync::Arc;
18
19use crate::UserInfoRef;
20
21pub trait UserInfo: Debug + Sync + Send {
22    fn as_any(&self) -> &dyn Any;
23    fn username(&self) -> &str;
24}
25
26/// The user permission mode
27#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
28pub enum PermissionMode {
29    #[default]
30    ReadWrite,
31    ReadOnly,
32    WriteOnly,
33}
34
35impl PermissionMode {
36    /// Parse permission mode from string.
37    /// Supported values are:
38    /// - "rw", "readwrite", "read_write" => ReadWrite
39    /// - "ro", "readonly", "read_only" => ReadOnly
40    /// - "wo", "writeonly", "write_only" => WriteOnly
41    ///     Returns None if the input string is not a valid permission mode.
42    pub fn from_str(s: &str) -> Self {
43        match s.to_lowercase().as_str() {
44            "readwrite" | "read_write" | "rw" => PermissionMode::ReadWrite,
45            "readonly" | "read_only" | "ro" => PermissionMode::ReadOnly,
46            "writeonly" | "write_only" | "wo" => PermissionMode::WriteOnly,
47            _ => PermissionMode::ReadWrite,
48        }
49    }
50
51    /// Convert permission mode to string.
52    /// - ReadWrite => "rw"
53    /// - ReadOnly => "ro"
54    /// - WriteOnly => "wo"
55    ///     The returned string is a static string slice.
56    pub fn as_str(&self) -> &'static str {
57        match self {
58            PermissionMode::ReadWrite => "rw",
59            PermissionMode::ReadOnly => "ro",
60            PermissionMode::WriteOnly => "wo",
61        }
62    }
63
64    /// Returns true if the permission mode allows read operations.
65    pub fn can_read(&self) -> bool {
66        matches!(self, PermissionMode::ReadWrite | PermissionMode::ReadOnly)
67    }
68
69    /// Returns true if the permission mode allows write operations.
70    pub fn can_write(&self) -> bool {
71        matches!(self, PermissionMode::ReadWrite | PermissionMode::WriteOnly)
72    }
73}
74
75impl std::fmt::Display for PermissionMode {
76    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
77        write!(f, "{}", self.as_str())
78    }
79}
80
81#[derive(Debug)]
82pub(crate) struct DefaultUserInfo {
83    username: String,
84    permission_mode: PermissionMode,
85}
86
87impl DefaultUserInfo {
88    pub(crate) fn with_name(username: impl Into<String>) -> UserInfoRef {
89        Self::with_name_and_permission(username, PermissionMode::default())
90    }
91
92    /// Create a UserInfo with specified permission mode.
93    pub(crate) fn with_name_and_permission(
94        username: impl Into<String>,
95        permission_mode: PermissionMode,
96    ) -> UserInfoRef {
97        Arc::new(Self {
98            username: username.into(),
99            permission_mode,
100        })
101    }
102
103    pub(crate) fn permission_mode(&self) -> &PermissionMode {
104        &self.permission_mode
105    }
106}
107
108impl UserInfo for DefaultUserInfo {
109    fn as_any(&self) -> &dyn Any {
110        self
111    }
112
113    fn username(&self) -> &str {
114        self.username.as_str()
115    }
116}
117#[cfg(test)]
118mod tests {
119    use super::*;
120
121    #[test]
122    fn test_permission_mode_from_str() {
123        // Test ReadWrite variants
124        assert_eq!(
125            PermissionMode::from_str("readwrite"),
126            PermissionMode::ReadWrite
127        );
128        assert_eq!(
129            PermissionMode::from_str("read_write"),
130            PermissionMode::ReadWrite
131        );
132        assert_eq!(PermissionMode::from_str("rw"), PermissionMode::ReadWrite);
133        assert_eq!(
134            PermissionMode::from_str("ReadWrite"),
135            PermissionMode::ReadWrite
136        );
137        assert_eq!(PermissionMode::from_str("RW"), PermissionMode::ReadWrite);
138
139        // Test ReadOnly variants
140        assert_eq!(
141            PermissionMode::from_str("readonly"),
142            PermissionMode::ReadOnly
143        );
144        assert_eq!(
145            PermissionMode::from_str("read_only"),
146            PermissionMode::ReadOnly
147        );
148        assert_eq!(PermissionMode::from_str("ro"), PermissionMode::ReadOnly);
149        assert_eq!(
150            PermissionMode::from_str("ReadOnly"),
151            PermissionMode::ReadOnly
152        );
153        assert_eq!(PermissionMode::from_str("RO"), PermissionMode::ReadOnly);
154
155        // Test WriteOnly variants
156        assert_eq!(
157            PermissionMode::from_str("writeonly"),
158            PermissionMode::WriteOnly
159        );
160        assert_eq!(
161            PermissionMode::from_str("write_only"),
162            PermissionMode::WriteOnly
163        );
164        assert_eq!(PermissionMode::from_str("wo"), PermissionMode::WriteOnly);
165        assert_eq!(
166            PermissionMode::from_str("WriteOnly"),
167            PermissionMode::WriteOnly
168        );
169        assert_eq!(PermissionMode::from_str("WO"), PermissionMode::WriteOnly);
170
171        // Test invalid inputs default to ReadWrite
172        assert_eq!(
173            PermissionMode::from_str("invalid"),
174            PermissionMode::ReadWrite
175        );
176        assert_eq!(PermissionMode::from_str(""), PermissionMode::ReadWrite);
177        assert_eq!(PermissionMode::from_str("xyz"), PermissionMode::ReadWrite);
178    }
179
180    #[test]
181    fn test_permission_mode_as_str() {
182        assert_eq!(PermissionMode::ReadWrite.as_str(), "rw");
183        assert_eq!(PermissionMode::ReadOnly.as_str(), "ro");
184        assert_eq!(PermissionMode::WriteOnly.as_str(), "wo");
185    }
186
187    #[test]
188    fn test_permission_mode_default() {
189        assert_eq!(PermissionMode::default(), PermissionMode::ReadWrite);
190    }
191
192    #[test]
193    fn test_permission_mode_round_trip() {
194        let modes = [
195            PermissionMode::ReadWrite,
196            PermissionMode::ReadOnly,
197            PermissionMode::WriteOnly,
198        ];
199
200        for mode in modes {
201            let str_repr = mode.as_str();
202            let parsed = PermissionMode::from_str(str_repr);
203            assert_eq!(mode, parsed);
204        }
205    }
206
207    #[test]
208    fn test_default_user_info_with_name() {
209        let user_info = DefaultUserInfo::with_name("test_user");
210        assert_eq!(user_info.username(), "test_user");
211    }
212
213    #[test]
214    fn test_default_user_info_with_name_and_permission() {
215        let user_info =
216            DefaultUserInfo::with_name_and_permission("test_user", PermissionMode::ReadOnly);
217        assert_eq!(user_info.username(), "test_user");
218
219        // Cast to DefaultUserInfo to access permission_mode
220        let default_user = user_info
221            .as_any()
222            .downcast_ref::<DefaultUserInfo>()
223            .unwrap();
224        assert_eq!(default_user.permission_mode, PermissionMode::ReadOnly);
225    }
226
227    #[test]
228    fn test_user_info_as_any() {
229        let user_info = DefaultUserInfo::with_name("test_user");
230        let any_ref = user_info.as_any();
231        assert!(any_ref.downcast_ref::<DefaultUserInfo>().is_some());
232    }
233}