Skip to main content

rustack_s3_core/
auth.rs

1//! S3 authentication via the `CredentialProvider` trait.
2//!
3//! [`RustackAuth`] implements the [`rustack_auth::credentials::CredentialProvider`]
4//! trait to provide authentication for the Rustack S3 service. When signature
5//! validation is skipped (the default for local development), any access key maps
6//! to an empty secret key, effectively disabling signature verification.
7//!
8//! When validation is enabled, all access keys map to the secret key `"test"`,
9//! matching LocalStack's default behavior.
10
11use rustack_auth::{credentials::CredentialProvider, error::AuthError};
12use tracing::debug;
13
14/// Rustack authentication provider.
15///
16/// # Examples
17///
18/// ```
19/// use rustack_s3_core::auth::RustackAuth;
20///
21/// let auth = RustackAuth::new(true);
22/// assert!(auth.skip_validation());
23/// ```
24#[derive(Debug, Clone)]
25pub struct RustackAuth {
26    skip_validation: bool,
27}
28
29impl RustackAuth {
30    /// Create a new authentication provider.
31    ///
32    /// When `skip_validation` is `true`, all signature checks are effectively
33    /// bypassed by returning an empty secret key for any access key.
34    #[must_use]
35    pub fn new(skip_validation: bool) -> Self {
36        Self { skip_validation }
37    }
38
39    /// Whether signature validation is skipped.
40    #[must_use]
41    pub fn skip_validation(&self) -> bool {
42        self.skip_validation
43    }
44}
45
46impl CredentialProvider for RustackAuth {
47    fn get_secret_key(&self, access_key_id: &str) -> Result<String, AuthError> {
48        if self.skip_validation {
49            debug!(access_key_id, "Skipping signature validation");
50            return Ok(String::new());
51        }
52
53        debug!(access_key_id, "Returning default secret key for access key");
54        Ok("test".to_owned())
55    }
56}
57
58#[cfg(test)]
59mod tests {
60    use super::*;
61
62    #[test]
63    fn test_should_create_auth_with_skip_validation() {
64        let auth = RustackAuth::new(true);
65        assert!(auth.skip_validation());
66    }
67
68    #[test]
69    fn test_should_create_auth_with_validation() {
70        let auth = RustackAuth::new(false);
71        assert!(!auth.skip_validation());
72    }
73
74    #[test]
75    fn test_should_return_empty_key_when_skipping_validation() {
76        let auth = RustackAuth::new(true);
77        let key = auth.get_secret_key("any-key").expect("test get_secret_key");
78        assert_eq!(key, "");
79    }
80
81    #[test]
82    fn test_should_return_test_key_when_validating() {
83        let auth = RustackAuth::new(false);
84        let key = auth
85            .get_secret_key("AKIAIOSFODNN7EXAMPLE")
86            .expect("test get_secret_key");
87        assert_eq!(key, "test");
88    }
89}