Skip to main content

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    fn is_admin(&self) -> bool {
26        false
27    }
28}
29
30/// The user permission mode
31#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
32pub enum PermissionMode {
33    #[default]
34    ReadWrite,
35    ReadOnly,
36    WriteOnly,
37}
38
39impl PermissionMode {
40    /// Parse permission mode from string.
41    /// Supported values are:
42    /// - "rw", "readwrite", "read_write" => ReadWrite
43    /// - "ro", "readonly", "read_only" => ReadOnly
44    /// - "wo", "writeonly", "write_only" => WriteOnly
45    ///
46    /// Returns `None` if the input string is not a valid permission mode.
47    pub fn from_str(s: &str) -> Option<Self> {
48        match s.to_lowercase().as_str() {
49            "readwrite" | "read_write" | "rw" => Some(PermissionMode::ReadWrite),
50            "readonly" | "read_only" | "ro" => Some(PermissionMode::ReadOnly),
51            "writeonly" | "write_only" | "wo" => Some(PermissionMode::WriteOnly),
52            _ => None,
53        }
54    }
55
56    /// Convert permission mode to string.
57    /// - ReadWrite => "rw"
58    /// - ReadOnly => "ro"
59    /// - WriteOnly => "wo"
60    ///     The returned string is a static string slice.
61    pub fn as_str(&self) -> &'static str {
62        match self {
63            PermissionMode::ReadWrite => "rw",
64            PermissionMode::ReadOnly => "ro",
65            PermissionMode::WriteOnly => "wo",
66        }
67    }
68
69    /// Returns true if the permission mode allows read operations.
70    pub fn can_read(&self) -> bool {
71        matches!(self, PermissionMode::ReadWrite | PermissionMode::ReadOnly)
72    }
73
74    /// Returns true if the permission mode allows write operations.
75    pub fn can_write(&self) -> bool {
76        matches!(self, PermissionMode::ReadWrite | PermissionMode::WriteOnly)
77    }
78}
79
80impl std::fmt::Display for PermissionMode {
81    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
82        write!(f, "{}", self.as_str())
83    }
84}
85
86#[derive(Debug)]
87pub(crate) struct DefaultUserInfo {
88    username: String,
89    permission_mode: PermissionMode,
90}
91
92impl DefaultUserInfo {
93    pub(crate) fn with_name(username: impl Into<String>) -> UserInfoRef {
94        Self::with_name_and_permission(username, PermissionMode::default())
95    }
96
97    /// Create a UserInfo with specified permission mode.
98    pub(crate) fn with_name_and_permission(
99        username: impl Into<String>,
100        permission_mode: PermissionMode,
101    ) -> UserInfoRef {
102        Arc::new(Self {
103            username: username.into(),
104            permission_mode,
105        })
106    }
107
108    pub(crate) fn permission_mode(&self) -> &PermissionMode {
109        &self.permission_mode
110    }
111}
112
113impl UserInfo for DefaultUserInfo {
114    fn as_any(&self) -> &dyn Any {
115        self
116    }
117
118    fn username(&self) -> &str {
119        self.username.as_str()
120    }
121}
122#[cfg(test)]
123mod tests {
124    use super::*;
125
126    #[test]
127    fn test_permission_mode_from_str() {
128        // Test ReadWrite variants
129        assert_eq!(
130            PermissionMode::from_str("readwrite"),
131            Some(PermissionMode::ReadWrite)
132        );
133        assert_eq!(
134            PermissionMode::from_str("read_write"),
135            Some(PermissionMode::ReadWrite)
136        );
137        assert_eq!(
138            PermissionMode::from_str("rw"),
139            Some(PermissionMode::ReadWrite)
140        );
141        assert_eq!(
142            PermissionMode::from_str("ReadWrite"),
143            Some(PermissionMode::ReadWrite)
144        );
145        assert_eq!(
146            PermissionMode::from_str("RW"),
147            Some(PermissionMode::ReadWrite)
148        );
149
150        // Test ReadOnly variants
151        assert_eq!(
152            PermissionMode::from_str("readonly"),
153            Some(PermissionMode::ReadOnly)
154        );
155        assert_eq!(
156            PermissionMode::from_str("read_only"),
157            Some(PermissionMode::ReadOnly)
158        );
159        assert_eq!(
160            PermissionMode::from_str("ro"),
161            Some(PermissionMode::ReadOnly)
162        );
163        assert_eq!(
164            PermissionMode::from_str("ReadOnly"),
165            Some(PermissionMode::ReadOnly)
166        );
167        assert_eq!(
168            PermissionMode::from_str("RO"),
169            Some(PermissionMode::ReadOnly)
170        );
171
172        // Test WriteOnly variants
173        assert_eq!(
174            PermissionMode::from_str("writeonly"),
175            Some(PermissionMode::WriteOnly)
176        );
177        assert_eq!(
178            PermissionMode::from_str("write_only"),
179            Some(PermissionMode::WriteOnly)
180        );
181        assert_eq!(
182            PermissionMode::from_str("wo"),
183            Some(PermissionMode::WriteOnly)
184        );
185        assert_eq!(
186            PermissionMode::from_str("WriteOnly"),
187            Some(PermissionMode::WriteOnly)
188        );
189        assert_eq!(
190            PermissionMode::from_str("WO"),
191            Some(PermissionMode::WriteOnly)
192        );
193
194        for invalid in ["readonyl", "", "xyz"] {
195            assert_eq!(PermissionMode::from_str(invalid), None);
196        }
197    }
198
199    #[test]
200    fn test_permission_mode_as_str() {
201        assert_eq!(PermissionMode::ReadWrite.as_str(), "rw");
202        assert_eq!(PermissionMode::ReadOnly.as_str(), "ro");
203        assert_eq!(PermissionMode::WriteOnly.as_str(), "wo");
204    }
205
206    #[test]
207    fn test_permission_mode_default() {
208        assert_eq!(PermissionMode::default(), PermissionMode::ReadWrite);
209    }
210
211    #[test]
212    fn test_permission_mode_round_trip() {
213        let modes = [
214            PermissionMode::ReadWrite,
215            PermissionMode::ReadOnly,
216            PermissionMode::WriteOnly,
217        ];
218
219        for mode in modes {
220            let str_repr = mode.as_str();
221            let parsed = PermissionMode::from_str(str_repr);
222            assert_eq!(Some(mode), parsed);
223        }
224    }
225
226    #[test]
227    fn test_user_info_as_any() {
228        let user_info = DefaultUserInfo::with_name("test_user");
229        let any_ref = user_info.as_any();
230        assert!(any_ref.downcast_ref::<DefaultUserInfo>().is_some());
231    }
232}