Skip to main content

rocketmq_auth/authentication/context/
default_authentication_context.rs

1// Copyright 2023 The RocketMQ Rust Authors
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;
17
18use cheetah_string::CheetahString;
19use rocketmq_error::REDACTED;
20
21use crate::authentication::context::base_authentication_context::BaseAuthenticationContext;
22use crate::authentication::AsAny;
23use crate::authorization::context::authentication_context::AuthenticationContext;
24
25#[derive(Default)]
26pub struct DefaultAuthenticationContext {
27    pub base: BaseAuthenticationContext,
28
29    username: Option<CheetahString>,
30    content: Option<Vec<u8>>,
31    signature: Option<CheetahString>,
32    request_timestamp: Option<CheetahString>,
33    request_timestamp_millis: Option<i64>,
34    verified_transport_identity: Option<Vec<u8>>,
35}
36
37impl fmt::Debug for DefaultAuthenticationContext {
38    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
39        formatter
40            .debug_struct("DefaultAuthenticationContext")
41            .field("username", &self.username)
42            .field("content_len", &self.content.as_ref().map(Vec::len))
43            .field("signature", &self.signature.as_ref().map(|_| REDACTED))
44            .field("request_timestamp", &self.request_timestamp)
45            .field("request_timestamp_millis", &self.request_timestamp_millis)
46            .field(
47                "verified_transport_identity_len",
48                &self.verified_transport_identity.as_ref().map(Vec::len),
49            )
50            .finish_non_exhaustive()
51    }
52}
53
54impl DefaultAuthenticationContext {
55    pub fn new() -> Self {
56        Self::default()
57    }
58
59    pub fn username(&self) -> Option<&CheetahString> {
60        self.username.as_ref()
61    }
62
63    pub fn set_username(&mut self, username: CheetahString) {
64        self.username = Some(username);
65    }
66
67    pub fn content(&self) -> Option<&[u8]> {
68        self.content.as_deref()
69    }
70
71    pub fn set_content(&mut self, content: Vec<u8>) {
72        self.content = Some(content);
73    }
74
75    pub fn signature(&self) -> Option<&CheetahString> {
76        self.signature.as_ref()
77    }
78
79    pub fn set_signature(&mut self, signature: CheetahString) {
80        self.signature = Some(signature);
81    }
82
83    pub fn request_timestamp(&self) -> Option<&CheetahString> {
84        self.request_timestamp.as_ref()
85    }
86
87    pub fn set_request_timestamp(&mut self, request_timestamp: CheetahString) {
88        self.request_timestamp = Some(request_timestamp);
89    }
90
91    pub fn request_timestamp_millis(&self) -> Option<i64> {
92        self.request_timestamp_millis
93    }
94
95    pub fn set_request_timestamp_millis(&mut self, request_timestamp_millis: i64) {
96        self.request_timestamp_millis = Some(request_timestamp_millis);
97    }
98
99    /// Returns the transport-verified peer identity, when one was supplied by a trusted ingress.
100    pub fn verified_transport_identity(&self) -> Option<&[u8]> {
101        self.verified_transport_identity.as_deref()
102    }
103
104    /// Attaches a transport-verified identity proof to this authentication context.
105    pub fn set_verified_transport_identity(&mut self, identity: Vec<u8>) {
106        self.verified_transport_identity = Some(identity);
107    }
108}
109
110impl AsAny for DefaultAuthenticationContext {
111    fn as_any_mut(&mut self) -> &mut dyn Any {
112        self
113    }
114
115    fn as_any(&self) -> &dyn Any {
116        self
117    }
118}
119
120impl AuthenticationContext for DefaultAuthenticationContext {}
121
122#[cfg(test)]
123mod tests {
124    use super::*;
125
126    #[test]
127    fn test_default_authentication_context_default_and_new() {
128        let context = DefaultAuthenticationContext::default();
129        assert!(context.username().is_none());
130        assert!(context.content().is_none());
131        assert!(context.signature().is_none());
132        assert!(context.request_timestamp().is_none());
133        assert!(context.request_timestamp_millis().is_none());
134        assert!(context.verified_transport_identity().is_none());
135
136        let context = DefaultAuthenticationContext::new();
137        assert!(context.username().is_none());
138        assert!(context.content().is_none());
139        assert!(context.signature().is_none());
140        assert!(context.request_timestamp().is_none());
141        assert!(context.request_timestamp_millis().is_none());
142        assert!(context.verified_transport_identity().is_none());
143    }
144
145    #[test]
146    fn test_default_authentication_context_setters_and_getters() {
147        let mut context = DefaultAuthenticationContext::new();
148        let username = CheetahString::from("test_user");
149        let content = vec![1, 2, 3];
150        let signature = CheetahString::from("test_signature");
151        let request_timestamp = CheetahString::from("20231227T194619Z");
152
153        context.set_username(username.clone());
154        context.set_content(content.clone());
155        context.set_signature(signature.clone());
156        context.set_request_timestamp(request_timestamp.clone());
157        context.set_request_timestamp_millis(1_703_706_379_000);
158        context.set_verified_transport_identity(vec![7, 8, 9]);
159
160        assert_eq!(context.username(), Some(&username));
161        assert_eq!(context.content(), Some(content.as_slice()));
162        assert_eq!(context.signature(), Some(&signature));
163        assert_eq!(context.request_timestamp(), Some(&request_timestamp));
164        assert_eq!(context.request_timestamp_millis(), Some(1_703_706_379_000));
165        assert_eq!(context.verified_transport_identity(), Some([7, 8, 9].as_slice()));
166    }
167
168    #[test]
169    fn test_default_authentication_context_as_any() {
170        let context = DefaultAuthenticationContext::new();
171        let any = context.as_any();
172        assert!(any.is::<DefaultAuthenticationContext>());
173
174        let mut context_mut = DefaultAuthenticationContext::new();
175        let any_mut = context_mut.as_any_mut();
176        assert!(any_mut.is::<DefaultAuthenticationContext>());
177    }
178
179    #[test]
180    fn default_authentication_context_debug_redacts_signature() {
181        let mut context = DefaultAuthenticationContext::new();
182        context.set_username(CheetahString::from("alice"));
183        context.set_content(vec![1, 2, 3, 4]);
184        context.set_signature(CheetahString::from("signature-secret"));
185
186        let debug = format!("{context:?}");
187
188        assert!(debug.contains("alice"));
189        assert!(debug.contains("content_len"));
190        assert!(debug.contains(REDACTED));
191        assert!(!debug.contains("signature-secret"));
192    }
193}