1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
//! Access control and authorization
//!
//! This module provides the [`S3Access`] trait for implementing fine-grained access control
//! over S3 operations based on authenticated credentials.
//!
//! # Overview
//!
//! The access control system allows you to authorize or deny S3 operations. The generated
//! [`S3Access`] trait provides:
//!
//! - A general `check` method that, when authentication is configured, is called before
//! deserializing operation input; note that per-request credentials may be absent
//! (for example, for unsigned or otherwise unauthenticated requests)
//! - Per-operation methods for fine-grained control (e.g., `get_object`, `put_object`)
//!
//! > **Security note**
//! >
//! > `S3Access::check` (and per-operation access methods) are only invoked when an auth
//! > provider is configured. If no auth provider is configured (i.e., the internal
//! > `CallContext.auth` is `None`), S3 operations skip access checks entirely. In other
//! > words, calling [`S3ServiceBuilder::set_access`](crate::service::S3ServiceBuilder::set_access)
//! > alone does *not* enforce authentication or authorization.
//! >
//! > When an auth provider is configured, access checks run for every request, even if
//! > the request is not successfully authenticated (for example, unsigned requests or
//! > requests with invalid credentials). In those cases,
//! > [`S3AccessContext::credentials`](crate::access::S3AccessContext::credentials) may
//! > return `None`, and your `S3Access` implementation is responsible for deciding
//! > whether to allow or deny the operation.
//!
//! # Example
//!
//! ```
//! use s3s::access::{S3Access, S3AccessContext};
//! use s3s::S3Result;
//!
//! struct MyAccessControl;
//!
//! #[async_trait::async_trait]
//! impl S3Access for MyAccessControl {
//! async fn check(&self, cx: &mut S3AccessContext<'_>) -> S3Result<()> {
//! // Check if request has valid credentials
//! match cx.credentials() {
//! Some(creds) => {
//! // You can check the operation, bucket, key, etc.
//! let op_name = cx.s3_op().name();
//! let path = cx.s3_path();
//!
//! // Implement your access control logic here
//! tracing::info!("User {} accessing {} on {:?}",
//! creds.access_key, op_name, path);
//! Ok(())
//! }
//! None => Err(s3s::s3_error!(AccessDenied, "Authentication required")),
//! }
//! }
//! }
//! ```
//!
//! # Integration with `S3Service`
//!
//! ```
//! use s3s::service::S3ServiceBuilder;
//! use s3s::access::{S3Access, S3AccessContext};
//! use s3s::auth::SimpleAuth;
//! use s3s::{S3, S3Request, S3Response, S3Result};
//! use s3s::dto::{GetObjectInput, GetObjectOutput};
//!
//! #[derive(Clone)]
//! struct MyS3;
//!
//! #[async_trait::async_trait]
//! impl S3 for MyS3 {
//! # async fn get_object(&self, _req: S3Request<GetObjectInput>) -> S3Result<S3Response<GetObjectOutput>> {
//! # Err(s3s::s3_error!(NotImplemented))
//! # }
//! // Implement S3 operations
//! }
//!
//! struct MyAccessControl;
//!
//! #[async_trait::async_trait]
//! impl S3Access for MyAccessControl {
//! async fn check(&self, _cx: &mut S3AccessContext<'_>) -> S3Result<()> {
//! Ok(())
//! }
//! }
//!
//! let mut builder = S3ServiceBuilder::new(MyS3);
//! // Configure both auth and access control for authorization to be enforced
//! builder.set_auth(SimpleAuth::from_single("ACCESS_KEY", "SECRET_KEY"));
//! builder.set_access(MyAccessControl);
//! let service = builder.build();
//! ```
cfg_if!
pub use S3Access;
pub use S3AccessContext;
use crateS3Result;
pub