mountpoint_s3_crt/auth/
credentials.rs

1//! AWS credentials providers
2
3use std::fmt::Debug;
4use std::ptr::NonNull;
5
6use mountpoint_s3_crt_sys::{
7    aws_credentials_provider, aws_credentials_provider_acquire, aws_credentials_provider_chain_default_options,
8    aws_credentials_provider_new_anonymous, aws_credentials_provider_new_chain_default,
9    aws_credentials_provider_new_profile, aws_credentials_provider_new_static,
10    aws_credentials_provider_profile_options, aws_credentials_provider_release,
11    aws_credentials_provider_static_options,
12};
13
14use crate::auth::auth_library_init;
15use crate::common::allocator::Allocator;
16use crate::common::error::Error;
17use crate::io::channel_bootstrap::ClientBootstrap;
18use crate::{CrtError as _, ToAwsByteCursor as _};
19
20/// Options for creating a default credentials provider
21#[derive(Debug)]
22pub struct CredentialsProviderChainDefaultOptions<'a> {
23    /// The client bootstrap this credentials provider should use to setup channels
24    pub bootstrap: &'a mut ClientBootstrap,
25}
26
27/// Options for creating a profile credentials provider
28#[derive(Debug)]
29pub struct CredentialsProviderProfileOptions<'a> {
30    /// The client bootstrap this credentials provider should use to setup channels
31    pub bootstrap: &'a mut ClientBootstrap,
32    /// The name of profile to use.
33    pub profile_name_override: &'a str,
34}
35
36/// Options for creating a static credentials provider
37pub struct CredentialsProviderStaticOptions<'a> {
38    /// AWS access key ID
39    pub access_key_id: &'a str,
40    /// AWS secret access key
41    pub secret_access_key: &'a str,
42    /// AWS session token (only required for some credentials sources, e.g. STS)
43    pub session_token: Option<&'a str>,
44}
45
46impl Debug for CredentialsProviderStaticOptions<'_> {
47    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
48        f.debug_struct("CredentialsProviderStaticOptions")
49            .field("access_key_id", &"** redacted **")
50            .field("secret_access_key", &"** redacted **")
51            .field("session_token", &self.session_token.map(|_| "** redacted **"))
52            .finish()
53    }
54}
55
56/// A credentials provider is an object that has an asynchronous query function for retrieving AWS
57/// credentials
58#[derive(Debug)]
59pub struct CredentialsProvider {
60    pub(crate) inner: NonNull<aws_credentials_provider>,
61}
62
63// SAFETY: aws_credentials_provider is thread-safe.
64unsafe impl Send for CredentialsProvider {}
65// SAFETY: aws_credentials_provider is thread-safe.
66unsafe impl Sync for CredentialsProvider {}
67
68impl CredentialsProvider {
69    /// Creates the default credential provider chain as used by most AWS SDKs
70    pub fn new_chain_default(
71        allocator: &Allocator,
72        options: CredentialsProviderChainDefaultOptions,
73    ) -> Result<Self, Error> {
74        auth_library_init(allocator);
75
76        let inner_options = aws_credentials_provider_chain_default_options {
77            bootstrap: options.bootstrap.inner.as_ptr(),
78            ..Default::default()
79        };
80
81        // SAFETY: aws_credentials_provider_new_chain_default makes a copy of the bootstrap options.
82        let inner = unsafe {
83            aws_credentials_provider_new_chain_default(allocator.inner.as_ptr(), &inner_options).ok_or_last_error()?
84        };
85
86        Ok(Self { inner })
87    }
88
89    /// Creates the anonymous credential provider.
90    /// Anonynous credentials provider gives you anonymous credentials which can be used to skip the signing process.
91    pub fn new_anonymous(allocator: &Allocator) -> Result<Self, Error> {
92        auth_library_init(allocator);
93
94        // SAFETY: allocator is a valid aws_allocator and shutdown_options is optional
95        let inner = unsafe {
96            aws_credentials_provider_new_anonymous(allocator.inner.as_ptr(), std::ptr::null_mut()).ok_or_last_error()?
97        };
98
99        Ok(Self { inner })
100    }
101
102    /// Creates the profile credential provider.
103    pub fn new_profile(allocator: &Allocator, options: CredentialsProviderProfileOptions) -> Result<Self, Error> {
104        auth_library_init(allocator);
105
106        // SAFETY: aws_credentials_provider_new_profile makes a copy of bootstrap
107        // and contents of profile_name_override.
108        let inner = unsafe {
109            let inner_options = aws_credentials_provider_profile_options {
110                bootstrap: options.bootstrap.inner.as_ptr(),
111                profile_name_override: options.profile_name_override.as_aws_byte_cursor(),
112                ..Default::default()
113            };
114
115            aws_credentials_provider_new_profile(allocator.inner.as_ptr(), &inner_options).ok_or_last_error()?
116        };
117
118        Ok(Self { inner })
119    }
120
121    /// Creates a static credential provider that always returns the given credentials
122    pub fn new_static(allocator: &Allocator, options: CredentialsProviderStaticOptions) -> Result<Self, Error> {
123        auth_library_init(allocator);
124
125        // SAFETY: aws_credentials_provider_new_static makes a copy of the strings
126        let inner = unsafe {
127            let inner_options = aws_credentials_provider_static_options {
128                access_key_id: options.access_key_id.as_aws_byte_cursor(),
129                secret_access_key: options.secret_access_key.as_aws_byte_cursor(),
130                session_token: options
131                    .session_token
132                    .map(|t| t.as_aws_byte_cursor())
133                    .unwrap_or_default(),
134                ..Default::default()
135            };
136
137            aws_credentials_provider_new_static(allocator.inner.as_ptr(), &inner_options).ok_or_last_error()?
138        };
139
140        Ok(Self { inner })
141    }
142}
143
144impl Clone for CredentialsProvider {
145    fn clone(&self) -> Self {
146        // SAFETY: `self.inner` is a valid `aws_credentials_provider` for as long as `self` exists
147        unsafe {
148            aws_credentials_provider_acquire(self.inner.as_ptr());
149        }
150
151        Self { inner: self.inner }
152    }
153}
154
155impl Drop for CredentialsProvider {
156    fn drop(&mut self) {
157        // SAFETY: `self.inner` is a valid `aws_credentials_provider` and we're in drop so it's safe
158        // to decrement the reference count.
159        unsafe {
160            aws_credentials_provider_release(self.inner.as_ptr());
161        }
162    }
163}