This is an automated email from the ASF dual-hosted git repository.

ChenSammi pushed a commit to branch HDDS-13323-sts
in repository https://gitbox.apache.org/repos/asf/ozone.git


The following commit(s) were added to refs/heads/HDDS-13323-sts by this push:
     new 79b82272595 HDDS-15861. [STS] Actions must not be sent in 
RequestContext to Authorizer if feature flag is off (#10771)
79b82272595 is described below

commit 79b822725956f090427ae877046ff96b0e16e6f0
Author: fmorg-git <[email protected]>
AuthorDate: Thu Jul 16 07:35:28 2026 -0700

    HDDS-15861. [STS] Actions must not be sent in RequestContext to Authorizer 
if feature flag is off (#10771)
---
 .../ozone/om/helpers/AssumeRoleResponseInfo.java   |  5 ++--
 .../om/helpers/TestAssumeRoleResponseInfo.java     |  4 +--
 .../apache/hadoop/ozone/om/OmMetadataReader.java   |  9 +++++-
 .../hadoop/ozone/om/TestOMMetadataReader.java      | 24 ++++++++++++++++
 .../hadoop/ozone/s3/endpoint/EndpointBase.java     | 11 ++++++--
 .../TestS3ActionOverrideForOwnerVerification.java  | 33 ++++++++++++++++++++--
 6 files changed, 76 insertions(+), 10 deletions(-)

diff --git 
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/AssumeRoleResponseInfo.java
 
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/AssumeRoleResponseInfo.java
index 5f21abb3cbd..ae674bfcfb2 100644
--- 
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/AssumeRoleResponseInfo.java
+++ 
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/AssumeRoleResponseInfo.java
@@ -80,8 +80,9 @@ public AssumeRoleResponse getProtobuf() {
 
   @Override
   public String toString() {
-    return "AssumeRoleResponseInfo{" + "accessKeyId='" + accessKeyId + "', 
secretAccessKey='" + secretAccessKey +
-        "', sessionToken='" + sessionToken + "', expirationEpochSeconds=" + 
expirationEpochSeconds +
+    // Intentionally left off secretAccessKey
+    return "AssumeRoleResponseInfo{" + "accessKeyId='" + accessKeyId + "'" +
+        ", sessionToken='" + sessionToken + "', expirationEpochSeconds=" + 
expirationEpochSeconds +
         ", assumedRoleId='" + assumedRoleId + "'}";
   }
 
diff --git 
a/hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/om/helpers/TestAssumeRoleResponseInfo.java
 
b/hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/om/helpers/TestAssumeRoleResponseInfo.java
index 38c74dc1f26..ce42b815470 100644
--- 
a/hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/om/helpers/TestAssumeRoleResponseInfo.java
+++ 
b/hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/om/helpers/TestAssumeRoleResponseInfo.java
@@ -187,8 +187,8 @@ public void testToString() {
 
     final String toString = response.toString();
     final String expectedString = "AssumeRoleResponseInfo{" + "accessKeyId='" 
+ ACCESS_KEY_ID  +
-        "', secretAccessKey='" + SECRET_ACCESS_KEY + "', sessionToken='" + 
SESSION_TOKEN +
-        "', expirationEpochSeconds=" + EXPIRATION_EPOCH_SECONDS + ", 
assumedRoleId='" + ASSUMED_ROLE_ID + "'}";
+        "', sessionToken='" + SESSION_TOKEN + "', expirationEpochSeconds=" + 
EXPIRATION_EPOCH_SECONDS +
+        ", assumedRoleId='" + ASSUMED_ROLE_ID + "'}";
 
     assertNotNull(toString);
     assertEquals(expectedString, toString);
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmMetadataReader.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmMetadataReader.java
index 40caed20554..7fbdf798b8e 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmMetadataReader.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmMetadataReader.java
@@ -673,9 +673,16 @@ public boolean checkAcls(OzoneObj obj, 
RequestContext.Builder contextBuilder,
    * thread locals: the session policy from {@link STSTokenIdentifier} (set on 
STS requests) and the
    * S3 action from {@link S3Authentication} (set on S3 requests). Either or 
both may be absent, in
    * which case the corresponding field is left untouched on the builder.
+   * <p>
+   * The S3 action is only propagated when the S3 STS feature flag is enabled, 
since it is only used
+   * for fine-grained STS authorization.
    * @param contextBuilder the builder to enrich in-place
    */
-  public static void maybeAddToContextFromThreadLocal(RequestContext.Builder 
contextBuilder) {
+  private void maybeAddToContextFromThreadLocal(RequestContext.Builder 
contextBuilder) {
+    if (!ozoneManager.isS3STSEnabled()) {
+      return;
+    }
+
     final STSTokenIdentifier stsTokenIdentifier = 
OzoneManager.getStsTokenIdentifier();
     if (stsTokenIdentifier != null) {
       contextBuilder.setSessionPolicy(stsTokenIdentifier.getSessionPolicy());
diff --git 
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestOMMetadataReader.java
 
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestOMMetadataReader.java
index e35a3952193..cf94366d567 100644
--- 
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestOMMetadataReader.java
+++ 
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestOMMetadataReader.java
@@ -162,6 +162,24 @@ public void testCheckAclsAttachesS3ActionFromThreadLocal() 
throws Exception {
     verifyS3ActionPassedToAuthorizer(accessAuthorizer, obj, "GetObject");
   }
 
+  @Test
+  public void testCheckAclsDoesNotAttachS3ActionWhenStsFeatureDisabled() 
throws Exception {
+    OzoneManager.setS3Auth(S3Authentication.newBuilder()
+        .setAccessId(ACCESS_KEY_ID)
+        .setS3Action("GetObject")
+        .build());
+
+    final IAccessAuthorizer accessAuthorizer = 
createMockIAccessAuthorizerReturningTrue();
+    final OmMetadataReader omMetadataReader = 
createMetadataReader(accessAuthorizer, mock(KeyManager.class), false);
+
+    final RequestContext.Builder contextWithoutS3ActionBuilder = 
createTestRequestContextBuilder();
+    final OzoneObj obj = createTestOzoneObj();
+
+    assertTrue(omMetadataReader.checkAcls(obj, contextWithoutS3ActionBuilder, 
true));
+
+    verifyS3ActionPassedToAuthorizer(accessAuthorizer, obj, null);
+  }
+
   @Test
   public void testCheckAclsLeavesS3ActionUnsetWhenS3AuthThreadLocalNull() 
throws Exception {
     final IAccessAuthorizer accessAuthorizer = 
createMockIAccessAuthorizerReturningTrue();
@@ -417,11 +435,17 @@ private OmMetadataReader 
createMetadataReader(IAccessAuthorizer accessAuthorizer
 
   private OmMetadataReader createMetadataReader(IAccessAuthorizer 
accessAuthorizer, KeyManager keyManager)
       throws IOException {
+    return createMetadataReader(accessAuthorizer, keyManager, true);
+  }
+
+  private OmMetadataReader createMetadataReader(IAccessAuthorizer 
accessAuthorizer, KeyManager keyManager,
+      boolean isS3StsEnabled) throws IOException {
     final OzoneManager ozoneManager = mock(OzoneManager.class);
     
when(ozoneManager.getBucketManager()).thenReturn(mock(BucketManager.class));
     
when(ozoneManager.getVolumeManager()).thenReturn(mock(VolumeManager.class));
     when(ozoneManager.getConfiguration()).thenReturn(new OzoneConfiguration());
     when(ozoneManager.getAclsEnabled()).thenReturn(true);
+    when(ozoneManager.isS3STSEnabled()).thenReturn(isS3StsEnabled);
     final OMPerformanceMetrics perfMetrics = mock(OMPerformanceMetrics.class);
     // OmMetadataReader uses these MutableRate metrics via 
MetricUtil.captureLatencyNs(...).
     
when(perfMetrics.getListKeysResolveBucketLatencyNs()).thenReturn(mock(MutableRate.class));
diff --git 
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/EndpointBase.java
 
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/EndpointBase.java
index fd6ef9c3c0b..1ab1ba0d9ff 100644
--- 
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/EndpointBase.java
+++ 
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/EndpointBase.java
@@ -24,6 +24,8 @@
 import static 
org.apache.hadoop.ozone.OzoneConfigKeys.HDDS_CONTAINER_RATIS_DATASTREAM_ENABLED_DEFAULT;
 import static 
org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_FS_DATASTREAM_AUTO_THRESHOLD;
 import static 
org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_FS_DATASTREAM_AUTO_THRESHOLD_DEFAULT;
+import static 
org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_S3G_STS_HTTP_ENABLED_DEFAULT;
+import static 
org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_S3G_STS_HTTP_ENABLED_KEY;
 import static org.apache.hadoop.ozone.OzoneConsts.ETAG;
 import static org.apache.hadoop.ozone.OzoneConsts.KB;
 import static 
org.apache.hadoop.ozone.s3.S3GatewayConfigKeys.OZONE_S3G_CLIENT_BUFFER_SIZE_DEFAULT;
@@ -157,6 +159,7 @@ public abstract class EndpointBase {
   private int chunkSize;
   private boolean datastreamEnabled;
   private long datastreamMinLength;
+  private boolean s3StsEnabled;
 
   @Context
   private ContainerRequestContext context;
@@ -221,6 +224,10 @@ public void initialization() {
         OZONE_FS_DATASTREAM_AUTO_THRESHOLD,
         OZONE_FS_DATASTREAM_AUTO_THRESHOLD_DEFAULT, StorageUnit.BYTES);
 
+    s3StsEnabled = getOzoneConfiguration().getBoolean(
+        OZONE_S3G_STS_HTTP_ENABLED_KEY,
+        OZONE_S3G_STS_HTTP_ENABLED_DEFAULT);
+
     init();
   }
 
@@ -233,7 +240,7 @@ protected void init() {
    * Called when the handler resolves the {@link S3GAction}.
    */
   protected void applyS3Action(S3GAction action) {
-    if (s3Auth != null) {
+    if (s3Auth != null && s3StsEnabled) {
       s3Auth.setS3Action(S3GActionIamMapper.toS3ActionString(action));
     }
   }
@@ -249,7 +256,7 @@ protected void applyS3Action(S3GAction action) {
    */
   protected <T, E extends Exception> T runWithS3ActionString(String s3Action, 
CheckedSupplier<T, E> checkedSupplier)
       throws E {
-    if (s3Auth == null) {
+    if (s3Auth == null || !s3StsEnabled) {
       return checkedSupplier.get();
     }
     final String originalS3Action = s3Auth.getS3Action();
diff --git 
a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestS3ActionOverrideForOwnerVerification.java
 
b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestS3ActionOverrideForOwnerVerification.java
index 0cb57755670..01dcc0acb27 100644
--- 
a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestS3ActionOverrideForOwnerVerification.java
+++ 
b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestS3ActionOverrideForOwnerVerification.java
@@ -26,6 +26,7 @@
 import static org.apache.hadoop.ozone.s3.util.S3Consts.X_AMZ_CONTENT_SHA256;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyString;
@@ -38,6 +39,7 @@
 import java.util.concurrent.atomic.AtomicReference;
 import javax.ws.rs.core.HttpHeaders;
 import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+import org.apache.hadoop.ozone.OzoneConfigKeys;
 import org.apache.hadoop.ozone.client.ObjectStore;
 import org.apache.hadoop.ozone.client.OzoneBucket;
 import org.apache.hadoop.ozone.client.OzoneClient;
@@ -65,7 +67,7 @@ public class TestS3ActionOverrideForOwnerVerification {
   @Test
   public void 
testUploadPartCopyUsesGetObjectActionForSourceBucketOwnerLookup() throws 
Exception {
     final AtomicReference<String> actionAtSourceBucketOwnerLookup = new 
AtomicReference<>();
-    final ObjectEndpoint endpoint = 
newEndpoint(actionAtSourceBucketOwnerLookup);
+    final ObjectEndpoint endpoint = 
newEndpoint(actionAtSourceBucketOwnerLookup, true);
 
     // Trigger UploadPartCopy (MPU part upload with copy header).
     final String uploadId = "upload-id";
@@ -77,7 +79,7 @@ public void 
testUploadPartCopyUsesGetObjectActionForSourceBucketOwnerLookup() th
   @Test
   public void testCopyObjectUsesGetObjectActionForSourceBucketOwnerLookup() 
throws Exception {
     final AtomicReference<String> actionAtSourceBucketOwnerLookup = new 
AtomicReference<>();
-    final ObjectEndpoint endpoint = 
newEndpoint(actionAtSourceBucketOwnerLookup);
+    final ObjectEndpoint endpoint = 
newEndpoint(actionAtSourceBucketOwnerLookup, true);
 
     // Trigger CopyObject (PUT with copy header, no upload ID).
     assertThrows(Exception.class, () -> put(endpoint, DEST_BUCKET, DEST_KEY, 
""));
@@ -85,7 +87,31 @@ public void 
testCopyObjectUsesGetObjectActionForSourceBucketOwnerLookup() throws
     assertEquals("GetObject", actionAtSourceBucketOwnerLookup.get());
   }
 
-  private static ObjectEndpoint newEndpoint(AtomicReference<String> 
actionAtSourceBucketOwnerLookup) throws Exception {
+  @Test
+  public void testUploadPartCopyDoesNotSetActionWhenStsDisabled() throws 
Exception {
+    final AtomicReference<String> actionAtSourceBucketOwnerLookup = new 
AtomicReference<>();
+    final ObjectEndpoint endpoint = 
newEndpoint(actionAtSourceBucketOwnerLookup, false);
+
+    // Trigger UploadPartCopy (MPU part upload with copy header).
+    final String uploadId = "upload-id";
+    assertThrows(Exception.class, () -> put(endpoint, DEST_BUCKET, DEST_KEY, 
1, uploadId, ""));
+
+    assertNull(actionAtSourceBucketOwnerLookup.get());
+  }
+
+  @Test
+  public void testCopyObjectDoesNotSetActionWhenStsDisabled() throws Exception 
{
+    final AtomicReference<String> actionAtSourceBucketOwnerLookup = new 
AtomicReference<>();
+    final ObjectEndpoint endpoint = 
newEndpoint(actionAtSourceBucketOwnerLookup, false);
+
+    // Trigger CopyObject (PUT with copy header, no upload ID).
+    assertThrows(Exception.class, () -> put(endpoint, DEST_BUCKET, DEST_KEY, 
""));
+
+    assertNull(actionAtSourceBucketOwnerLookup.get());
+  }
+
+  private static ObjectEndpoint newEndpoint(AtomicReference<String> 
actionAtSourceBucketOwnerLookup,
+      boolean isStsEnabled) throws Exception {
     final HttpHeaders headers = mock(HttpHeaders.class);
     
when(headers.getHeaderString(X_AMZ_CONTENT_SHA256)).thenReturn(UNSIGNED_PAYLOAD);
     when(headers.getHeaderString(STORAGE_CLASS_HEADER)).thenReturn("STANDARD");
@@ -138,6 +164,7 @@ private static ObjectEndpoint 
newEndpoint(AtomicReference<String> actionAtSource
         .thenThrow(new OMException("stop-after-owner-check", 
ResultCodes.KEY_NOT_FOUND));
 
     final OzoneConfiguration conf = new OzoneConfiguration();
+    conf.setBoolean(OzoneConfigKeys.OZONE_S3G_STS_HTTP_ENABLED_KEY, 
isStsEnabled);
     return EndpointBuilder.newObjectEndpointBuilder()
         .setClient(client)
         .setConfig(conf)


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to