You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@opendal.apache.org by xu...@apache.org on 2026/08/24 07:59:47 UTC
(opendal-reqsign) branch xuanwo/s3-express-session-provider-mode created (now daf1207)
This is an automated email from the ASF dual-hosted git repository.
Xuanwo pushed a change to branch xuanwo/s3-express-session-provider-mode
in repository https://gitbox.apache.org/repos/asf/opendal-reqsign.git
at daf1207 fix(aws): configure S3 Express session provider grants
This branch includes the following new commits:
new daf1207 fix(aws): configure S3 Express session provider grants
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
(opendal-reqsign) 01/01: fix(aws): configure S3 Express session provider grants
Posted by xu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
Xuanwo pushed a commit to branch xuanwo/s3-express-session-provider-mode
in repository https://gitbox.apache.org/repos/asf/opendal-reqsign.git
commit daf120784eded0a550fe119d5f5295772b87c1c3
Author: Xuanwo <gi...@xuanwo.io>
AuthorDate: Mon Aug 24 15:59:36 2026 +0800
fix(aws): configure S3 Express session provider grants
---
.../src/provide_credential/s3_express_session.rs | 96 +++++++++++++++++++---
1 file changed, 86 insertions(+), 10 deletions(-)
diff --git a/services/aws-v4/src/provide_credential/s3_express_session.rs b/services/aws-v4/src/provide_credential/s3_express_session.rs
index 06d8a8a..96d7ad0 100644
--- a/services/aws-v4/src/provide_credential/s3_express_session.rs
+++ b/services/aws-v4/src/provide_credential/s3_express_session.rs
@@ -694,15 +694,15 @@ impl GrantCredential for S3ExpressSessionGranter {
}
}
-/// S3 Express fixed-flow credential provider.
+/// S3 Express session credential provider.
///
-/// This compatibility API loads its source through [`ProvideCredential`] and
-/// creates a `ReadWrite` session on every call. New explicit credential-vending
-/// flows should use [`S3ExpressSessionGranter`] through
-/// [`reqsign_core::Granter`].
+/// This API loads its source through [`ProvideCredential`] and creates a session
+/// on every call. It defaults to an explicit `ReadWrite` session for compatibility;
+/// use [`Self::with_grant`] to select another mode.
pub struct S3ExpressSessionProvider {
bucket: String,
region: Option<String>,
+ grant: S3ExpressSessionGrantSelection,
base_provider: Box<dyn ProvideCredentialDyn<Credential = Credential>>,
}
@@ -714,7 +714,7 @@ impl Debug for S3ExpressSessionProvider {
}
impl S3ExpressSessionProvider {
- /// Create a fixed `ReadWrite` session provider for a directory bucket.
+ /// Create a session provider that defaults to `ReadWrite` for a directory bucket.
///
/// The legacy constructor infers the Region from well-known AWS Zone ID
/// prefixes. Use [`S3ExpressSessionProvider::with_region`] when the Zone is
@@ -727,6 +727,7 @@ impl S3ExpressSessionProvider {
Self {
bucket: bucket.into(),
region: None,
+ grant: S3ExpressSessionGrant::new(S3ExpressSessionMode::ReadWrite).into(),
base_provider: Box::new(provider),
}
}
@@ -737,6 +738,12 @@ impl S3ExpressSessionProvider {
self
}
+ /// Select how S3 Express determines the `CreateSession` permission mode.
+ pub fn with_grant(mut self, grant: impl Into<S3ExpressSessionGrantSelection>) -> Self {
+ self.grant = grant.into();
+ self
+ }
+
fn operation(&self) -> Result<S3ExpressSessionGranter> {
let zone_id = zone_id_from_bucket(&self.bucket)?;
let region = match &self.region {
@@ -748,10 +755,7 @@ impl S3ExpressSessionProvider {
})?,
};
let config = S3ExpressSessionConfig::from_bucket(&self.bucket, region)?;
- Ok(S3ExpressSessionGranter::new(
- config,
- S3ExpressSessionGrant::new(S3ExpressSessionMode::ReadWrite),
- ))
+ Ok(S3ExpressSessionGranter::new(config, self.grant.clone()))
}
}
@@ -2298,6 +2302,78 @@ mod tests {
);
}
+ #[tokio::test]
+ async fn configurable_provider_refreshes_maximum_allowed_sessions_for_signer() {
+ let first_expiration = (Timestamp::now() + Duration::from_secs(110)).format_rfc3339_zulu();
+ let second_expiration = (Timestamp::now() + Duration::from_secs(300)).format_rfc3339_zulu();
+ let http = MockHttpSend::new([
+ success_response(
+ "first-session-access-key",
+ "first-session-secret-key",
+ "first-session-token",
+ &first_expiration,
+ ),
+ success_response(
+ "second-session-access-key",
+ "second-session-secret-key",
+ "second-session-token",
+ &second_expiration,
+ ),
+ ]);
+ let ctx = Context::new().with_http_send(http.clone());
+ let (source_provider, source_calls) = FixedCredentialProvider::new(source_credential());
+ let provider = S3ExpressSessionProvider::new("example--usw2-az1--x-s3", source_provider)
+ .with_grant(S3ExpressSessionGrant::maximum_allowed());
+ let signer = Signer::new(
+ ctx,
+ provider,
+ crate::RequestSigner::new("s3express", "us-west-2"),
+ );
+
+ let mut first = Request::get(
+ "https://example--usw2-az1--x-s3.s3express-usw2-az1.us-west-2.amazonaws.com/first",
+ )
+ .body(())
+ .expect("first request must build")
+ .into_parts()
+ .0;
+ signer
+ .sign(&mut first, None)
+ .await
+ .expect("first request must use a maximum-allowed session");
+ assert_eq!(
+ first.headers["x-amz-s3session-token"],
+ "first-session-token"
+ );
+
+ let mut second = Request::get(
+ "https://example--usw2-az1--x-s3.s3express-usw2-az1.us-west-2.amazonaws.com/second",
+ )
+ .body(())
+ .expect("second request must build")
+ .into_parts()
+ .0;
+ signer
+ .sign(&mut second, None)
+ .await
+ .expect("second request must refresh the maximum-allowed session");
+ assert_eq!(
+ second.headers["x-amz-s3session-token"],
+ "second-session-token"
+ );
+
+ assert_eq!(source_calls.load(Ordering::SeqCst), 2);
+ assert_eq!(http.calls.load(Ordering::SeqCst), 2);
+ for index in 0..2 {
+ assert!(
+ !http
+ .request(index)
+ .headers
+ .contains_key("x-amz-create-session-mode")
+ );
+ }
+ }
+
#[tokio::test]
async fn compatibility_provider_uses_explicit_region_for_new_zone_prefix() {
let response = success_response(