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]