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 56654627b20 HDDS-14935. [STS] Handle Latent Inconsistencies in S3 API 
Acl Checks (#10009)
56654627b20 is described below

commit 56654627b2042536695bccdc5c12e738bf697615
Author: fmorg-git <[email protected]>
AuthorDate: Wed May 27 06:51:04 2026 -0700

    HDDS-14935. [STS] Handle Latent Inconsistencies in S3 API Acl Checks 
(#10009)
---
 hadoop-hdds/dev-support/checkstyle/checkstyle.xml  |   6 +
 .../src/main/proto/OmClientProtocol.proto          |   8 ++
 .../ozone/om/ratis/OzoneManagerStateMachine.java   |  28 +++++
 .../hadoop/ozone/om/request/OMClientRequest.java   |  66 ++++++++++-
 .../om/request/bucket/OMBucketSetOwnerRequest.java |   7 +-
 .../request/bucket/OMBucketSetPropertyRequest.java |   9 +-
 .../request/bucket/acl/OMBucketAddAclRequest.java  |  11 +-
 .../bucket/acl/OMBucketRemoveAclRequest.java       |  11 +-
 .../request/bucket/acl/OMBucketSetAclRequest.java  |   9 +-
 .../ozone/om/request/file/OMFileCreateRequest.java |   2 +-
 .../om/request/file/OMRecoverLeaseRequest.java     |   2 +-
 .../ozone/om/request/key/OMKeyCommitRequest.java   |   2 +-
 .../ozone/om/request/key/OMKeyCreateRequest.java   |   2 +-
 .../ozone/om/request/key/OMKeyDeleteRequest.java   |   2 +-
 .../ozone/om/request/key/OMKeyRenameRequest.java   |   2 +-
 .../ozone/om/request/key/OMKeySetTimesRequest.java |   2 +-
 .../om/request/key/acl/OMKeyAddAclRequest.java     |  11 +-
 .../om/request/key/acl/OMKeyRemoveAclRequest.java  |  11 +-
 .../om/request/key/acl/OMKeySetAclRequest.java     |  11 +-
 .../multipart/S3MultipartUploadAbortRequest.java   |   2 +-
 .../om/request/s3/security/OMSetSecretRequest.java |   6 +-
 .../request/s3/security/S3AssumeRoleRequest.java   |  23 +---
 .../security/S3DeleteRevokedSTSTokensRequest.java  |   4 +-
 .../om/request/s3/security/S3GetSecretRequest.java |  21 ++--
 .../s3/security/S3RevokeSTSTokenRequest.java       |  16 +--
 .../request/s3/security/S3RevokeSecretRequest.java |  14 +--
 .../security/OMCancelDelegationTokenRequest.java   |   2 +-
 .../security/OMGetDelegationTokenRequest.java      |   2 +-
 .../security/OMRenewDelegationTokenRequest.java    |   2 +-
 .../snapshot/OMSnapshotMoveTableKeysRequest.java   |   7 +-
 .../om/request/volume/OMVolumeSetOwnerRequest.java |   6 +-
 .../om/request/volume/OMVolumeSetQuotaRequest.java |   8 +-
 .../request/volume/acl/OMVolumeAddAclRequest.java  |  11 +-
 .../volume/acl/OMVolumeRemoveAclRequest.java       |  11 +-
 .../request/volume/acl/OMVolumeSetAclRequest.java  |  11 +-
 .../hadoop/ozone/security/STSSecurityUtil.java     |  41 +++++++
 .../om/ratis/TestOzoneManagerStateMachine.java     |  74 +++++++++++++
 .../request/TestOMClientRequestWithUserInfo.java   | 123 +++++++++++++++++++++
 .../s3/security/TestS3GetSecretRequest.java        |   4 +
 .../hadoop/ozone/security/TestSTSSecurityUtil.java |  75 +++++++++++++
 40 files changed, 527 insertions(+), 138 deletions(-)

diff --git a/hadoop-hdds/dev-support/checkstyle/checkstyle.xml 
b/hadoop-hdds/dev-support/checkstyle/checkstyle.xml
index 1109bd9983b..307d99261ff 100644
--- a/hadoop-hdds/dev-support/checkstyle/checkstyle.xml
+++ b/hadoop-hdds/dev-support/checkstyle/checkstyle.xml
@@ -83,6 +83,12 @@
         <property name="matchAcrossLines" value="true"/>
         <property name="message" value="Use Objects.requireNonNull instead of 
Preconditions.checkNotNull"/>
     </module>
+    <module name="RegexpMultiline">
+        <property name="format"
+                  
value="@Override\s+public\s+(?:(?:final|synchronized)\s+)*OMRequest\s+preExecute\s*\([^\)]*\)\s*(?:throws\s+[^{]+)?\s*\{(?!(?:(?!\/\*|\*\/)[\s\S]|\/\*(?:(?!\*\/)[\s\S])*\*\/){0,400}?(?:^|\r?\n|(?&lt;=\{))[
 \t]*(?!\*|\/)(?:return\s+|final\s+(?:[a-zA-Z0-9_]+\s+)*[a-zA-Z0-9_]+[ \t]*=[ 
\t]*)?(?:\([a-zA-Z0-9_]+\)\s*)?super\s*\.\s*preExecute\s*\()"/>
+        <property name="matchAcrossLines" value="true"/>
+        <property name="message" value="preExecute() overrides must call 
super.preExecute(ozoneManager) and its result must be final or returned"/>
+    </module>
     <module name="TreeWalker">
         <module name="SuppressWarningsHolder"/>
         <module name="SuppressionCommentFilter"/>
diff --git 
a/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto 
b/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
index dde32437db5..5cf503275a2 100644
--- a/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
+++ b/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
@@ -2338,6 +2338,14 @@ message S3Authentication {
     // If present, indicates this request uses STS temporary credentials
     // and carries the base64-encoded session token for validation.
     optional string sessionToken = 4;
+    // The following fields are resolved from the STS session token by OM.
+    // They are used to enforce STS session policies during Ratis apply.
+    // They must be written or cleared by the OM leader when the token is 
validated.
+    optional string resolvedStsSessionPolicy = 5;
+    optional string resolvedStsRoleArn = 6;
+    optional string resolvedStsOriginalAccessKeyId = 7;
+    optional string resolvedStsTempAccessKeyId = 8;
+    optional string resolvedStsSecretKeyId = 9;
 }
 
 message RecoverLeaseRequest {
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis/OzoneManagerStateMachine.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis/OzoneManagerStateMachine.java
index 2abaf9ae571..34c5a485d61 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis/OzoneManagerStateMachine.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis/OzoneManagerStateMachine.java
@@ -57,6 +57,8 @@
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMResponse;
 import org.apache.hadoop.ozone.protocolPB.OzoneManagerRequestHandler;
 import org.apache.hadoop.ozone.protocolPB.RequestHandler;
+import org.apache.hadoop.ozone.security.STSSecurityUtil;
+import org.apache.hadoop.ozone.security.STSTokenIdentifier;
 import org.apache.hadoop.security.UserGroupInformation;
 import org.apache.hadoop.util.Time;
 import org.apache.hadoop.util.concurrent.HadoopExecutors;
@@ -662,7 +664,29 @@ public void close() {
    */
   @VisibleForTesting
   OMResponse runCommand(OMRequest request, TermIndex termIndex) {
+    boolean isStsThreadLocalSet = false;
     try {
+      if (ozoneManager.isSecurityEnabled() && request.hasS3Authentication()) {
+        // STS token verification runs on the leader RPC path so we don't need 
to recheck here on the apply
+        // after the log is committed
+        STSSecurityUtil.ensureResolvedStsFieldsInvariants(request);
+
+        final OzoneManagerProtocolProtos.S3Authentication s3Auth = 
request.getS3Authentication();
+        if (s3Auth.hasSessionToken() && !s3Auth.getSessionToken().isEmpty()) {
+          // ThreadLocal carries session policy for OmMetadataReader
+          final STSTokenIdentifier rehydratedTokenIdentifier = new 
STSTokenIdentifier(
+                  s3Auth.hasResolvedStsTempAccessKeyId() ? 
s3Auth.getResolvedStsTempAccessKeyId() : "",
+                  s3Auth.hasResolvedStsOriginalAccessKeyId() ? 
s3Auth.getResolvedStsOriginalAccessKeyId() : "",
+                  s3Auth.hasResolvedStsRoleArn() ? 
s3Auth.getResolvedStsRoleArn() : "",
+                  java.time.Instant.MAX, // ensure it deterministically is not 
expired
+                  "", // no secretAccessKey needed
+                  s3Auth.hasResolvedStsSessionPolicy() ? 
s3Auth.getResolvedStsSessionPolicy() : "",
+                  null // no encryption key needed
+              );
+          OzoneManager.setStsTokenIdentifier(rehydratedTokenIdentifier);
+          isStsThreadLocalSet = true;
+        }
+      }
       ExecutionContext context = ExecutionContext.of(termIndex.getIndex(), 
termIndex);
       final OMClientResponse omClientResponse = handler.handleWriteRequest(
           request, context, ozoneManagerDoubleBuffer);
@@ -681,6 +705,10 @@ OMResponse runCommand(OMRequest request, TermIndex 
termIndex) {
       // For any Runtime exceptions, terminate OM.
       String errorMessage = "Request " + request + " failed with exception";
       ExitUtils.terminate(1, errorMessage, e, LOG);
+    } finally {
+      if (isStsThreadLocalSet) {
+        OzoneManager.setStsTokenIdentifier(null);
+      }
     }
     return null;
   }
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/OMClientRequest.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/OMClientRequest.java
index 0420eef2fd5..81d6925442b 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/OMClientRequest.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/OMClientRequest.java
@@ -27,6 +27,7 @@
 import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Objects;
+import java.util.UUID;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.hadoop.hdds.utils.TransactionInfo;
 import org.apache.hadoop.ipc_.ProtobufRpcEngine;
@@ -50,10 +51,12 @@
 import org.apache.hadoop.ozone.om.ratis.utils.OzoneManagerRatisUtils;
 import org.apache.hadoop.ozone.om.request.s3.security.S3AssumeRoleRequest;
 import org.apache.hadoop.ozone.om.response.OMClientResponse;
+import org.apache.hadoop.ozone.om.upgrade.OMLayoutVersionManager;
 import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos;
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.LayoutVersion;
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRequest;
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMResponse;
+import org.apache.hadoop.ozone.security.STSTokenIdentifier;
 import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer;
 import org.apache.hadoop.ozone.security.acl.OzoneObj;
 import org.apache.hadoop.ozone.security.acl.OzoneObjInfo;
@@ -112,15 +115,66 @@ public OMClientRequest(OMRequest omRequest) {
    */
   public OMRequest preExecute(OzoneManager ozoneManager)
       throws IOException {
-    LayoutVersion layoutVersion = LayoutVersion.newBuilder()
-        
.setVersion(ozoneManager.getVersionManager().getMetadataLayoutVersion())
-        .build();
-    omRequest = getOmRequest().toBuilder()
-        .setUserInfo(getUserIfNotExists(ozoneManager))
-        .setLayoutVersion(layoutVersion).build();
+    final OMRequest.Builder requestBuilder = getOmRequest().toBuilder()
+        .setUserInfo(getUserIfNotExists(ozoneManager));
+
+    // VersionManager is always expected in production OzoneManager instances.
+    // Some unit tests use a minimal mocked OzoneManager, so perform null 
check here.
+    final OMLayoutVersionManager versionManager = 
ozoneManager.getVersionManager();
+    if (versionManager != null) {
+      final LayoutVersion layoutVersion = LayoutVersion.newBuilder()
+          .setVersion(versionManager.getMetadataLayoutVersion())
+          .build();
+      requestBuilder.setLayoutVersion(layoutVersion);
+    }
+
+    if (requestBuilder.hasS3Authentication()) {
+      final OzoneManagerProtocolProtos.S3Authentication s3Auth = 
requestBuilder.getS3Authentication();
+      final boolean hasSessionToken = s3Auth.hasSessionToken() && 
!s3Auth.getSessionToken().isEmpty();
+      final STSTokenIdentifier stsTokenIdentifier = 
OzoneManager.getStsTokenIdentifier();
+
+      // This should not happen, so explicitly throw an error.  An existing 
sessionToken
+      // implies prior STS validation must have populated the ThreadLocal.
+      if (ozoneManager.isSecurityEnabled() && hasSessionToken && 
stsTokenIdentifier == null) {
+        throw new OMException(
+            "S3Authentication has session token but no STS token identifier in 
OzoneManager ThreadLocal",
+            OMException.ResultCodes.INVALID_REQUEST);
+      }
+
+      requestBuilder.setS3Authentication(resolveS3Authentication(s3Auth, 
stsTokenIdentifier));
+    }
+
+    omRequest = requestBuilder.build();
     return omRequest;
   }
 
+  private static OzoneManagerProtocolProtos.S3Authentication 
resolveS3Authentication(
+      OzoneManagerProtocolProtos.S3Authentication s3Auth, STSTokenIdentifier 
stsTokenIdentifier) {
+    final OzoneManagerProtocolProtos.S3Authentication.Builder s3AuthBuilder = 
s3Auth.toBuilder();
+
+    if (s3Auth.hasSessionToken() && !s3Auth.getSessionToken().isEmpty() && 
stsTokenIdentifier != null) {
+      s3AuthBuilder.setResolvedStsSessionPolicy(
+          StringUtils.defaultString(stsTokenIdentifier.getSessionPolicy()));
+      s3AuthBuilder.setResolvedStsRoleArn(
+          StringUtils.defaultString(stsTokenIdentifier.getRoleArn()));
+      s3AuthBuilder.setResolvedStsOriginalAccessKeyId(
+          
StringUtils.defaultString(stsTokenIdentifier.getOriginalAccessKeyId()));
+      s3AuthBuilder.setResolvedStsTempAccessKeyId(
+          StringUtils.defaultString(stsTokenIdentifier.getTempAccessKeyId()));
+      final UUID secretKeyId = stsTokenIdentifier.getSecretKeyId();
+      s3AuthBuilder.setResolvedStsSecretKeyId(
+          secretKeyId != null ? secretKeyId.toString() : "");
+    } else {
+      s3AuthBuilder.clearResolvedStsSessionPolicy();
+      s3AuthBuilder.clearResolvedStsRoleArn();
+      s3AuthBuilder.clearResolvedStsOriginalAccessKeyId();
+      s3AuthBuilder.clearResolvedStsTempAccessKeyId();
+      s3AuthBuilder.clearResolvedStsSecretKeyId();
+    }
+
+    return s3AuthBuilder.build();
+  }
+
   /**
    * Performs any request specific failure handling during request
    * submission. An example of this would be an undo of any steps
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/bucket/OMBucketSetOwnerRequest.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/bucket/OMBucketSetOwnerRequest.java
index 6d0c90cdca2..888e8b48dfb 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/bucket/OMBucketSetOwnerRequest.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/bucket/OMBucketSetOwnerRequest.java
@@ -63,15 +63,16 @@ public OMBucketSetOwnerRequest(OMRequest omRequest) {
   @Override
   public OMRequest preExecute(OzoneManager ozoneManager)
       throws IOException {
+    final OMRequest omRequest = super.preExecute(ozoneManager);
+
     long modificationTime = Time.now();
     OzoneManagerProtocolProtos.SetBucketPropertyRequest.Builder
-        setBucketPropertyRequestBuilder = getOmRequest()
+        setBucketPropertyRequestBuilder = omRequest
         .getSetBucketPropertyRequest().toBuilder()
         .setModificationTime(modificationTime);
 
-    return getOmRequest().toBuilder()
+    return omRequest.toBuilder()
         .setSetBucketPropertyRequest(setBucketPropertyRequestBuilder)
-        .setUserInfo(getUserInfo())
         .build();
   }
 
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/bucket/OMBucketSetPropertyRequest.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/bucket/OMBucketSetPropertyRequest.java
index a88e5fb7333..7563ba9e4b8 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/bucket/OMBucketSetPropertyRequest.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/bucket/OMBucketSetPropertyRequest.java
@@ -79,14 +79,16 @@ public OMBucketSetPropertyRequest(OMRequest omRequest) {
   @Override
   public OMRequest preExecute(OzoneManager ozoneManager)
       throws IOException {
+    final OMRequest omRequest = super.preExecute(ozoneManager);
+
     long modificationTime = Time.now();
     OzoneManagerProtocolProtos.SetBucketPropertyRequest.Builder
-        setBucketPropertyRequestBuilder = getOmRequest()
+        setBucketPropertyRequestBuilder = omRequest
         .getSetBucketPropertyRequest().toBuilder()
         .setModificationTime(modificationTime);
 
     BucketArgs bucketArgs =
-        getOmRequest().getSetBucketPropertyRequest().getBucketArgs();
+        omRequest.getSetBucketPropertyRequest().getBucketArgs();
 
     if (bucketArgs.hasBekInfo()) {
       KeyProviderCryptoExtension kmsProvider = ozoneManager.getKmsProvider();
@@ -97,9 +99,8 @@ public OMRequest preExecute(OzoneManager ozoneManager)
       setBucketPropertyRequestBuilder.setBucketArgs(bucketArgsBuilder.build());
     }
 
-    return getOmRequest().toBuilder()
+    return omRequest.toBuilder()
         .setSetBucketPropertyRequest(setBucketPropertyRequestBuilder)
-        .setUserInfo(getUserInfo())
         .build();
   }
 
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/bucket/acl/OMBucketAddAclRequest.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/bucket/acl/OMBucketAddAclRequest.java
index 1b3ce4e3f84..843e95865c2 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/bucket/acl/OMBucketAddAclRequest.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/bucket/acl/OMBucketAddAclRequest.java
@@ -56,14 +56,15 @@ public class OMBucketAddAclRequest extends 
OMBucketAclRequest {
 
   @Override
   public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
-    long modificationTime = Time.now();
-    OzoneManagerProtocolProtos.AddAclRequest.Builder addAclRequestBuilder =
-        getOmRequest().getAddAclRequest().toBuilder()
+    final OMRequest omRequest = super.preExecute(ozoneManager);
+
+    final long modificationTime = Time.now();
+    final OzoneManagerProtocolProtos.AddAclRequest.Builder 
addAclRequestBuilder =
+        omRequest.getAddAclRequest().toBuilder()
             .setModificationTime(modificationTime);
 
-    return getOmRequest().toBuilder()
+    return omRequest.toBuilder()
         .setAddAclRequest(addAclRequestBuilder)
-        .setUserInfo(getUserInfo())
         .build();
   }
 
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/bucket/acl/OMBucketRemoveAclRequest.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/bucket/acl/OMBucketRemoveAclRequest.java
index 13839ddb58a..4ac27878eb8 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/bucket/acl/OMBucketRemoveAclRequest.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/bucket/acl/OMBucketRemoveAclRequest.java
@@ -55,14 +55,15 @@ public class OMBucketRemoveAclRequest extends 
OMBucketAclRequest {
 
   @Override
   public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
-    long modificationTime = Time.now();
-    OzoneManagerProtocolProtos.RemoveAclRequest.Builder removeAclRequestBuilder
-        = getOmRequest().getRemoveAclRequest().toBuilder()
+    final OMRequest omRequest = super.preExecute(ozoneManager);
+
+    final long modificationTime = Time.now();
+    final OzoneManagerProtocolProtos.RemoveAclRequest.Builder 
removeAclRequestBuilder =
+        omRequest.getRemoveAclRequest().toBuilder()
             .setModificationTime(modificationTime);
 
-    return getOmRequest().toBuilder()
+    return omRequest.toBuilder()
         .setRemoveAclRequest(removeAclRequestBuilder)
-        .setUserInfo(getUserInfo())
         .build();
   }
 
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/bucket/acl/OMBucketSetAclRequest.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/bucket/acl/OMBucketSetAclRequest.java
index 97dca83c197..678c4ba0dc8 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/bucket/acl/OMBucketSetAclRequest.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/bucket/acl/OMBucketSetAclRequest.java
@@ -54,14 +54,15 @@ public class OMBucketSetAclRequest extends 
OMBucketAclRequest {
 
   @Override
   public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
-    long modificationTime = Time.now();
-    OzoneManagerProtocolProtos.SetAclRequest.Builder setAclRequestBuilder =
+    final long modificationTime = Time.now();
+    final OzoneManagerProtocolProtos.SetAclRequest.Builder 
setAclRequestBuilder =
         getOmRequest().getSetAclRequest().toBuilder()
             .setModificationTime(modificationTime);
 
-    return getOmRequest().toBuilder()
+    // super.preExecute resolves S3Authentication (STS) for Ratis apply.  
Merge SetAclRequest changes on top.
+    final OMRequest request = super.preExecute(ozoneManager);
+    return request.toBuilder()
         .setSetAclRequest(setAclRequestBuilder)
-        .setUserInfo(getUserInfo())
         .build();
   }
 
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/file/OMFileCreateRequest.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/file/OMFileCreateRequest.java
index 9788cfbafe1..71651506f1d 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/file/OMFileCreateRequest.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/file/OMFileCreateRequest.java
@@ -82,7 +82,7 @@ public OMFileCreateRequest(OMRequest omRequest, BucketLayout 
bucketLayout) {
 
   @Override
   public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
-    CreateFileRequest createFileRequest = super.preExecute(ozoneManager)
+    final CreateFileRequest createFileRequest = super.preExecute(ozoneManager)
         .getCreateFileRequest();
     Objects.requireNonNull(createFileRequest, "createFileRequest == null");
 
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/file/OMRecoverLeaseRequest.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/file/OMRecoverLeaseRequest.java
index ca1ea07ad6e..b01c69c6406 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/file/OMRecoverLeaseRequest.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/file/OMRecoverLeaseRequest.java
@@ -96,7 +96,7 @@ public OMRecoverLeaseRequest(OMRequest omRequest) {
   @Override
   @DisallowedUntilLayoutVersion(HBASE_SUPPORT)
   public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
-    OMRequest request = super.preExecute(ozoneManager);
+    final OMRequest request = super.preExecute(ozoneManager);
     RecoverLeaseRequest recoverLeaseRequest = request.getRecoverLeaseRequest();
 
     String keyPath = recoverLeaseRequest.getKeyName();
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyCommitRequest.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyCommitRequest.java
index 4e1d3603d73..3d8bf932e09 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyCommitRequest.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyCommitRequest.java
@@ -87,7 +87,7 @@ public OMKeyCommitRequest(OMRequest omRequest, BucketLayout 
bucketLayout) {
 
   @Override
   public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
-    OMRequest request = super.preExecute(ozoneManager);
+    final OMRequest request = super.preExecute(ozoneManager);
     CommitKeyRequest commitKeyRequest = request.getCommitKeyRequest();
     Objects.requireNonNull(commitKeyRequest, "commitKeyRequest == null");
 
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyCreateRequest.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyCreateRequest.java
index d7b14455369..d2de7e391e6 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyCreateRequest.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyCreateRequest.java
@@ -87,7 +87,7 @@ public OMKeyCreateRequest(OMRequest omRequest, BucketLayout 
bucketLayout) {
 
   @Override
   public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
-    CreateKeyRequest createKeyRequest = super.preExecute(ozoneManager)
+    final CreateKeyRequest createKeyRequest = super.preExecute(ozoneManager)
         .getCreateKeyRequest();
     Objects.requireNonNull(createKeyRequest, "createKeyRequest == null");
 
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyDeleteRequest.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyDeleteRequest.java
index 4726d4af2d5..24babd76b85 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyDeleteRequest.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyDeleteRequest.java
@@ -75,7 +75,7 @@ public OMKeyDeleteRequest(OMRequest omRequest, BucketLayout 
bucketLayout) {
 
   @Override
   public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
-    DeleteKeyRequest deleteKeyRequest = super.preExecute(ozoneManager)
+    final DeleteKeyRequest deleteKeyRequest = super.preExecute(ozoneManager)
         .getDeleteKeyRequest();
     Objects.requireNonNull(deleteKeyRequest, "deleteKeyRequest == null");
 
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyRenameRequest.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyRenameRequest.java
index 850f111a913..9c46eba8f46 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyRenameRequest.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyRenameRequest.java
@@ -72,7 +72,7 @@ public OMKeyRenameRequest(OMRequest omRequest, BucketLayout 
bucketLayout) {
 
   @Override
   public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
-    RenameKeyRequest renameKeyRequest = super.preExecute(ozoneManager)
+    final RenameKeyRequest renameKeyRequest = super.preExecute(ozoneManager)
         .getRenameKeyRequest();
     Objects.requireNonNull(renameKeyRequest, "renameKeyRequest == null");
 
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeySetTimesRequest.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeySetTimesRequest.java
index eef06ef2b41..fc46fbe3409 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeySetTimesRequest.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeySetTimesRequest.java
@@ -62,7 +62,7 @@ public class OMKeySetTimesRequest extends OMKeyRequest {
 
   @Override
   public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
-    OMRequest request = super.preExecute(ozoneManager);
+    final OMRequest request = super.preExecute(ozoneManager);
     SetTimesRequest setTimesRequest = request.getSetTimesRequest();
     String keyPath = setTimesRequest.getKeyArgs().getKeyName();
     String normalizedKeyPath =
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/acl/OMKeyAddAclRequest.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/acl/OMKeyAddAclRequest.java
index 367e3c87db6..777ff972453 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/acl/OMKeyAddAclRequest.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/acl/OMKeyAddAclRequest.java
@@ -63,14 +63,15 @@ public class OMKeyAddAclRequest extends OMKeyAclRequest {
 
   @Override
   public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
-    long modificationTime = Time.now();
-    OzoneManagerProtocolProtos.AddAclRequest.Builder addAclRequestBuilder =
-        getOmRequest().getAddAclRequest().toBuilder()
+    final OMRequest omRequest = super.preExecute(ozoneManager);
+
+    final long modificationTime = Time.now();
+    final OzoneManagerProtocolProtos.AddAclRequest.Builder 
addAclRequestBuilder =
+        omRequest.getAddAclRequest().toBuilder()
             .setModificationTime(modificationTime);
 
-    return getOmRequest().toBuilder()
+    return omRequest.toBuilder()
         .setAddAclRequest(addAclRequestBuilder)
-        .setUserInfo(getUserInfo())
         .build();
   }
 
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/acl/OMKeyRemoveAclRequest.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/acl/OMKeyRemoveAclRequest.java
index 0de996fd28a..8761b7db359 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/acl/OMKeyRemoveAclRequest.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/acl/OMKeyRemoveAclRequest.java
@@ -63,14 +63,15 @@ public class OMKeyRemoveAclRequest extends OMKeyAclRequest {
 
   @Override
   public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
-    long modificationTime = Time.now();
-    OzoneManagerProtocolProtos.RemoveAclRequest.Builder removeAclRequestBuilder
-        = getOmRequest().getRemoveAclRequest().toBuilder()
+    final OMRequest omRequest = super.preExecute(ozoneManager);
+
+    final long modificationTime = Time.now();
+    final OzoneManagerProtocolProtos.RemoveAclRequest.Builder 
removeAclRequestBuilder =
+        omRequest.getRemoveAclRequest().toBuilder()
             .setModificationTime(modificationTime);
 
-    return getOmRequest().toBuilder()
+    return omRequest.toBuilder()
         .setRemoveAclRequest(removeAclRequestBuilder)
-        .setUserInfo(getUserInfo())
         .build();
   }
 
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/acl/OMKeySetAclRequest.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/acl/OMKeySetAclRequest.java
index b0bd2f8fe52..bd9b7f677b4 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/acl/OMKeySetAclRequest.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/acl/OMKeySetAclRequest.java
@@ -64,14 +64,15 @@ public class OMKeySetAclRequest extends OMKeyAclRequest {
 
   @Override
   public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
-    long modificationTime = Time.now();
-    OzoneManagerProtocolProtos.SetAclRequest.Builder setAclRequestBuilder =
-        getOmRequest().getSetAclRequest().toBuilder()
+    final OMRequest omRequest = super.preExecute(ozoneManager);
+
+    final long modificationTime = Time.now();
+    final OzoneManagerProtocolProtos.SetAclRequest.Builder 
setAclRequestBuilder =
+        omRequest.getSetAclRequest().toBuilder()
             .setModificationTime(modificationTime);
 
-    return getOmRequest().toBuilder()
+    return omRequest.toBuilder()
         .setSetAclRequest(setAclRequestBuilder)
-        .setUserInfo(getUserInfo())
         .build();
   }
 
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/multipart/S3MultipartUploadAbortRequest.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/multipart/S3MultipartUploadAbortRequest.java
index a9aeff0ac5d..905288e6f68 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/multipart/S3MultipartUploadAbortRequest.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/multipart/S3MultipartUploadAbortRequest.java
@@ -77,7 +77,7 @@ public S3MultipartUploadAbortRequest(OMRequest omRequest,
 
   @Override
   public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
-    KeyArgs keyArgs = super.preExecute(ozoneManager)
+    final KeyArgs keyArgs = super.preExecute(ozoneManager)
         .getAbortMultiPartUploadRequest().getKeyArgs();
     String keyPath = keyArgs.getKeyName();
     keyPath = validateAndNormalizeKey(ozoneManager.getEnableFileSystemPaths(),
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/security/OMSetSecretRequest.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/security/OMSetSecretRequest.java
index 4b0fceb821a..9f8d6ca1ee2 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/security/OMSetSecretRequest.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/security/OMSetSecretRequest.java
@@ -55,11 +55,11 @@ public OMSetSecretRequest(OMRequest omRequest) {
 
   @Override
   public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
+    final OMRequest omRequest = super.preExecute(ozoneManager);
     final OMMetadataManager omMetadataManager =
         ozoneManager.getMetadataManager();
 
-    final SetS3SecretRequest request =
-        getOmRequest().getSetS3SecretRequest();
+    final SetS3SecretRequest request = omRequest.getSetS3SecretRequest();
 
     final String accessId = request.getAccessId();
 
@@ -94,7 +94,7 @@ public OMRequest preExecute(OzoneManager ozoneManager) throws 
IOException {
     S3SecretRequestHelper.checkAccessIdSecretOpPermission(
         ozoneManager, ugi, accessId);
 
-    return getOmRequest();
+    return omRequest;
   }
 
   @Override
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/security/S3AssumeRoleRequest.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/security/S3AssumeRoleRequest.java
index a87f2de54dd..4efd18b4b32 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/security/S3AssumeRoleRequest.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/security/S3AssumeRoleRequest.java
@@ -90,7 +90,8 @@ public S3AssumeRoleRequest(OMRequest omRequest, Clock clock) {
 
   @Override
   public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
-    final AssumeRoleRequest assumeRoleRequest = 
getOmRequest().getAssumeRoleRequest();
+    final OMRequest omRequest = super.preExecute(ozoneManager);
+    final AssumeRoleRequest assumeRoleRequest = 
omRequest.getAssumeRoleRequest();
 
     // Brief overview of flow:
     // The STS Endpoint makes the AssumeRole call, which when received by OM 
leader (via this method),
@@ -123,23 +124,9 @@ public OMRequest preExecute(OzoneManager ozoneManager) 
throws IOException {
       
updateAssumeRoleRequestBuilder.setAwsIamSessionPolicy(assumeRoleRequest.getAwsIamSessionPolicy());
     }
 
-    // Build new OMRequest with both original and update requests
-    final OMRequest.Builder omRequest = OMRequest.newBuilder()
-        .setUserInfo(getUserInfo())
-        .setCmdType(getOmRequest().getCmdType())
-        .setClientId(getOmRequest().getClientId())
-        .setAssumeRoleRequest(assumeRoleRequest)
-        .setUpdateAssumeRoleRequest(updateAssumeRoleRequestBuilder.build());
-
-    if (getOmRequest().hasS3Authentication()) {
-      omRequest.setS3Authentication(getOmRequest().getS3Authentication());
-    }
-
-    if (getOmRequest().hasTraceID()) {
-      omRequest.setTraceID(getOmRequest().getTraceID());
-    }
-
-    return omRequest.build();
+    return omRequest.toBuilder()
+        .setUpdateAssumeRoleRequest(updateAssumeRoleRequestBuilder.build())
+        .build();
   }
 
   @Override
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/security/S3DeleteRevokedSTSTokensRequest.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/security/S3DeleteRevokedSTSTokensRequest.java
index ee2a8656445..f41b20353a8 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/security/S3DeleteRevokedSTSTokensRequest.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/security/S3DeleteRevokedSTSTokensRequest.java
@@ -54,9 +54,7 @@ public OMRequest preExecute(OzoneManager ozoneManager) throws 
IOException {
       throw new OMException("Only admins can delete revoked STS tokens", 
OMException.ResultCodes.PERMISSION_DENIED);
     }
 
-    return getOmRequest().toBuilder()
-        .setUserInfo(getUserInfo())
-        .build();
+    return super.preExecute(ozoneManager);
   }
 
   @Override
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/security/S3GetSecretRequest.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/security/S3GetSecretRequest.java
index 2c698abefe0..c0609d7a52e 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/security/S3GetSecretRequest.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/security/S3GetSecretRequest.java
@@ -59,9 +59,9 @@ public S3GetSecretRequest(OMRequest omRequest) {
 
   @Override
   public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
+    final OMRequest omRequest = super.preExecute(ozoneManager);
 
-    final GetS3SecretRequest s3GetSecretRequest =
-        getOmRequest().getGetS3SecretRequest();
+    final GetS3SecretRequest s3GetSecretRequest = 
omRequest.getGetS3SecretRequest();
 
     // The proto field kerberosID is effectively accessId w/ Multi-Tenancy
     //
@@ -83,10 +83,7 @@ public OMRequest preExecute(OzoneManager ozoneManager) 
throws IOException {
     // way S3Secret created by leader, will be replicated across all
     // OMs. With this approach, original GetS3Secret request from
     // client does not need any proto changes.
-    OMRequest.Builder omRequest = OMRequest.newBuilder()
-        .setUserInfo(getUserInfo())
-        .setCmdType(getOmRequest().getCmdType())
-        .setClientId(getOmRequest().getClientId());
+    final OMRequest.Builder omRequestBuilder = omRequest.toBuilder();
 
     // createIfNotExist defaults to true if not specified.
     boolean createIfNotExist = !s3GetSecretRequest.hasCreateIfNotExist()
@@ -98,7 +95,7 @@ public OMRequest preExecute(OzoneManager ozoneManager) throws 
IOException {
                     .setKerberosID(accessId)  // See Note 1 above
                     .setCreateIfNotExist(createIfNotExist)
                     .build();
-    omRequest.setGetS3SecretRequest(newGetS3SecretRequest);
+    omRequestBuilder.setGetS3SecretRequest(newGetS3SecretRequest);
 
     // When createIfNotExist is true, pass UpdateGetS3SecretRequest message;
     // otherwise, just use GetS3SecretRequest message.
@@ -113,14 +110,12 @@ public OMRequest preExecute(OzoneManager ozoneManager) 
throws IOException {
                       .setAwsSecret(s3Secret)
                       .build();
 
-      omRequest.setUpdateGetS3SecretRequest(updateGetS3SecretRequest);
-    }
-
-    if (getOmRequest().hasTraceID()) {
-      omRequest.setTraceID(getOmRequest().getTraceID());
+      omRequestBuilder.setUpdateGetS3SecretRequest(updateGetS3SecretRequest);
+    } else {
+      omRequestBuilder.clearUpdateGetS3SecretRequest();
     }
 
-    return omRequest.build();
+    return omRequestBuilder.build();
   }
 
   @Override
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/security/S3RevokeSTSTokenRequest.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/security/S3RevokeSTSTokenRequest.java
index 94c2f8d5083..52a92d8a556 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/security/S3RevokeSTSTokenRequest.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/security/S3RevokeSTSTokenRequest.java
@@ -60,8 +60,9 @@ public S3RevokeSTSTokenRequest(OMRequest omRequest) {
 
   @Override
   public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
+    final OMRequest omRequest = super.preExecute(ozoneManager);
     final OzoneManagerProtocolProtos.RevokeSTSTokenRequest revokeReq =
-        getOmRequest().getRevokeSTSTokenRequest();
+        omRequest.getRevokeSTSTokenRequest();
 
     // Get the original (long-lived) access key id from the session token
     // and enforce the same permission model that is used for S3 secret
@@ -73,21 +74,10 @@ public OMRequest preExecute(OzoneManager ozoneManager) 
throws IOException {
         sessionToken, ozoneManager.getSecretKeyClient(), CLOCK);
     final String originalAccessKeyId = 
stsTokenIdentifier.getOriginalAccessKeyId();
 
-    final OzoneManagerProtocolProtos.UserInfo userInfo = getUserInfo();
     final UserGroupInformation ugi = 
S3SecretRequestHelper.getOrCreateUgi(originalAccessKeyId);
     S3SecretRequestHelper.checkAccessIdSecretOpPermission(ozoneManager, ugi, 
originalAccessKeyId);
 
-    final OMRequest.Builder omRequest = OMRequest.newBuilder()
-        .setRevokeSTSTokenRequest(revokeReq)
-        .setCmdType(getOmRequest().getCmdType())
-        .setClientId(getOmRequest().getClientId())
-        .setUserInfo(userInfo);
-
-    if (getOmRequest().hasTraceID()) {
-      omRequest.setTraceID(getOmRequest().getTraceID());
-    }
-
-    return omRequest.build();
+    return omRequest;
   }
 
   @Override
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/security/S3RevokeSecretRequest.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/security/S3RevokeSecretRequest.java
index 24e9b1a3b46..f74d5a57977 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/security/S3RevokeSecretRequest.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/security/S3RevokeSecretRequest.java
@@ -50,8 +50,9 @@ public S3RevokeSecretRequest(OMRequest omRequest) {
 
   @Override
   public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
+    final OMRequest omRequest = super.preExecute(ozoneManager);
     final RevokeS3SecretRequest s3RevokeSecretRequest =
-        getOmRequest().getRevokeS3SecretRequest();
+        omRequest.getRevokeS3SecretRequest();
     final String accessId = s3RevokeSecretRequest.getKerberosID();
     final UserGroupInformation ugi =
         S3SecretRequestHelper.getOrCreateUgi(accessId);
@@ -63,16 +64,9 @@ public OMRequest preExecute(OzoneManager ozoneManager) 
throws IOException {
             RevokeS3SecretRequest.newBuilder()
                     .setKerberosID(accessId).build();
 
-    OMRequest.Builder omRequest = OMRequest.newBuilder()
+    return omRequest.toBuilder()
         .setRevokeS3SecretRequest(revokeS3SecretRequest)
-        .setCmdType(getOmRequest().getCmdType())
-        .setClientId(getOmRequest().getClientId());
-
-    if (getOmRequest().hasTraceID()) {
-      omRequest.setTraceID(getOmRequest().getTraceID());
-    }
-
-    return omRequest.build();
+        .build();
   }
 
   @Override
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/security/OMCancelDelegationTokenRequest.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/security/OMCancelDelegationTokenRequest.java
index ab3cc4fc0ab..0b6ba013860 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/security/OMCancelDelegationTokenRequest.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/security/OMCancelDelegationTokenRequest.java
@@ -59,7 +59,7 @@ public OMCancelDelegationTokenRequest(OMRequest omRequest) {
   @Override
   public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
     // We need to populate user info in our request object.
-    OMRequest request =  super.preExecute(ozoneManager);
+    final OMRequest request = super.preExecute(ozoneManager);
 
     AuditLogger auditLogger = ozoneManager.getAuditLogger();
     Map<String, String> auditMap = null;
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/security/OMGetDelegationTokenRequest.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/security/OMGetDelegationTokenRequest.java
index 109d39ddab9..8106c6331cb 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/security/OMGetDelegationTokenRequest.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/security/OMGetDelegationTokenRequest.java
@@ -63,7 +63,7 @@ public OMGetDelegationTokenRequest(OMRequest omRequest) {
   @Override
   public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
     // We need to populate user info in our request object.
-    OMRequest request = super.preExecute(ozoneManager);
+    final OMRequest request = super.preExecute(ozoneManager);
 
     GetDelegationTokenRequestProto getDelegationTokenRequest =
         request.getGetDelegationTokenRequest();
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/security/OMRenewDelegationTokenRequest.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/security/OMRenewDelegationTokenRequest.java
index fbac8d4b14c..38e86c3ce6f 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/security/OMRenewDelegationTokenRequest.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/security/OMRenewDelegationTokenRequest.java
@@ -60,7 +60,7 @@ public OMRenewDelegationTokenRequest(OMRequest omRequest) {
   @Override
   public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
     // We need to populate user info in our request object.
-    OMRequest request = super.preExecute(ozoneManager);
+    final OMRequest request = super.preExecute(ozoneManager);
 
     RenewDelegationTokenRequestProto renewDelegationTokenRequest =
         request.getRenewDelegationTokenRequest();
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/snapshot/OMSnapshotMoveTableKeysRequest.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/snapshot/OMSnapshotMoveTableKeysRequest.java
index fef5dc76c4d..440e2aed772 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/snapshot/OMSnapshotMoveTableKeysRequest.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/snapshot/OMSnapshotMoveTableKeysRequest.java
@@ -74,9 +74,10 @@ public OMSnapshotMoveTableKeysRequest(OMRequest omRequest) {
 
   @Override
   public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
-    OmMetadataManagerImpl omMetadataManager = (OmMetadataManagerImpl) 
ozoneManager.getMetadataManager();
+    final OMRequest omRequest = super.preExecute(ozoneManager);
+    final OmMetadataManagerImpl omMetadataManager = (OmMetadataManagerImpl) 
ozoneManager.getMetadataManager();
     SnapshotChainManager snapshotChainManager = 
omMetadataManager.getSnapshotChainManager();
-    SnapshotMoveTableKeysRequest moveTableKeysRequest = 
getOmRequest().getSnapshotMoveTableKeysRequest();
+    SnapshotMoveTableKeysRequest moveTableKeysRequest = 
omRequest.getSnapshotMoveTableKeysRequest();
     UUID fromSnapshotID = 
fromProtobuf(moveTableKeysRequest.getFromSnapshotID());
     SnapshotInfo fromSnapshot = SnapshotUtils.getSnapshotInfo(ozoneManager,
         snapshotChainManager, fromSnapshotID);
@@ -179,7 +180,7 @@ public OMRequest preExecute(OzoneManager ozoneManager) 
throws IOException {
         }
       }
     }
-    return getOmRequest().toBuilder().setSnapshotMoveTableKeysRequest(
+    return omRequest.toBuilder().setSnapshotMoveTableKeysRequest(
         
moveTableKeysRequest.toBuilder().clearDeletedDirs().clearDeletedKeys().clearRenamedKeys()
             .addAllDeletedKeys(deletedKeys).addAllDeletedDirs(deletedDirs)
             .addAllRenamedKeys(renamedKeysList).build()).build();
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/volume/OMVolumeSetOwnerRequest.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/volume/OMVolumeSetOwnerRequest.java
index 02c3b7874e9..f5435b1cfe1 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/volume/OMVolumeSetOwnerRequest.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/volume/OMVolumeSetOwnerRequest.java
@@ -61,15 +61,15 @@ public OMVolumeSetOwnerRequest(OMRequest omRequest) {
 
   @Override
   public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
+    final OMRequest omRequest = super.preExecute(ozoneManager);
 
     long modificationTime = Time.now();
-    SetVolumePropertyRequest.Builder setPropertyRequestBuilder = getOmRequest()
+    SetVolumePropertyRequest.Builder setPropertyRequestBuilder = omRequest
         .getSetVolumePropertyRequest().toBuilder()
         .setModificationTime(modificationTime);
 
-    return getOmRequest().toBuilder()
+    return omRequest.toBuilder()
         .setSetVolumePropertyRequest(setPropertyRequestBuilder)
-        .setUserInfo(getUserInfo())
         .build();
   }
 
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/volume/OMVolumeSetQuotaRequest.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/volume/OMVolumeSetQuotaRequest.java
index c93e8cbeb6c..780f6350516 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/volume/OMVolumeSetQuotaRequest.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/volume/OMVolumeSetQuotaRequest.java
@@ -63,15 +63,15 @@ public OMVolumeSetQuotaRequest(OMRequest omRequest) {
 
   @Override
   public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
+    final OMRequest omRequest = super.preExecute(ozoneManager);
 
     long modificationTime = Time.now();
-    SetVolumePropertyRequest.Builder setPropertyRequestBuilde = getOmRequest()
+    SetVolumePropertyRequest.Builder setPropertyRequestBuilder = omRequest
         .getSetVolumePropertyRequest().toBuilder()
         .setModificationTime(modificationTime);
 
-    return getOmRequest().toBuilder()
-        .setSetVolumePropertyRequest(setPropertyRequestBuilde)
-        .setUserInfo(getUserInfo())
+    return omRequest.toBuilder()
+        .setSetVolumePropertyRequest(setPropertyRequestBuilder)
         .build();
   }
 
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/volume/acl/OMVolumeAddAclRequest.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/volume/acl/OMVolumeAddAclRequest.java
index c0e87043ea3..72c6de925fa 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/volume/acl/OMVolumeAddAclRequest.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/volume/acl/OMVolumeAddAclRequest.java
@@ -58,14 +58,15 @@ public class OMVolumeAddAclRequest extends 
OMVolumeAclRequest {
 
   @Override
   public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
-    long modificationTime = Time.now();
-    OzoneManagerProtocolProtos.AddAclRequest.Builder addAclRequestBuilder =
-        getOmRequest().getAddAclRequest().toBuilder()
+    final OMRequest omRequest = super.preExecute(ozoneManager);
+
+    final long modificationTime = Time.now();
+    final OzoneManagerProtocolProtos.AddAclRequest.Builder 
addAclRequestBuilder =
+        omRequest.getAddAclRequest().toBuilder()
             .setModificationTime(modificationTime);
 
-    return getOmRequest().toBuilder()
+    return omRequest.toBuilder()
         .setAddAclRequest(addAclRequestBuilder)
-        .setUserInfo(getUserInfo())
         .build();
   }
 
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/volume/acl/OMVolumeRemoveAclRequest.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/volume/acl/OMVolumeRemoveAclRequest.java
index 05f338957ee..59267d7849f 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/volume/acl/OMVolumeRemoveAclRequest.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/volume/acl/OMVolumeRemoveAclRequest.java
@@ -58,14 +58,15 @@ public class OMVolumeRemoveAclRequest extends 
OMVolumeAclRequest {
 
   @Override
   public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
-    long modificationTime = Time.now();
-    OzoneManagerProtocolProtos.RemoveAclRequest.Builder removeAclRequestBuilder
-        = getOmRequest().getRemoveAclRequest().toBuilder()
+    final OMRequest omRequest = super.preExecute(ozoneManager);
+
+    final long modificationTime = Time.now();
+    final OzoneManagerProtocolProtos.RemoveAclRequest.Builder 
removeAclRequestBuilder =
+        omRequest.getRemoveAclRequest().toBuilder()
             .setModificationTime(modificationTime);
 
-    return getOmRequest().toBuilder()
+    return omRequest.toBuilder()
         .setRemoveAclRequest(removeAclRequestBuilder)
-        .setUserInfo(getUserInfo())
         .build();
   }
 
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/volume/acl/OMVolumeSetAclRequest.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/volume/acl/OMVolumeSetAclRequest.java
index 6abffc2197f..ce3eba72672 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/volume/acl/OMVolumeSetAclRequest.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/volume/acl/OMVolumeSetAclRequest.java
@@ -57,14 +57,15 @@ public class OMVolumeSetAclRequest extends 
OMVolumeAclRequest {
 
   @Override
   public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
-    long modificationTime = Time.now();
-    OzoneManagerProtocolProtos.SetAclRequest.Builder setAclRequestBuilder =
-        getOmRequest().getSetAclRequest().toBuilder()
+    final OMRequest omRequest = super.preExecute(ozoneManager);
+
+    final long modificationTime = Time.now();
+    final OzoneManagerProtocolProtos.SetAclRequest.Builder 
setAclRequestBuilder =
+        omRequest.getSetAclRequest().toBuilder()
             .setModificationTime(modificationTime);
 
-    return getOmRequest().toBuilder()
+    return omRequest.toBuilder()
         .setSetAclRequest(setAclRequestBuilder)
-        .setUserInfo(getUserInfo())
         .build();
   }
 
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/security/STSSecurityUtil.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/security/STSSecurityUtil.java
index c414708cebe..2212ad6db79 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/security/STSSecurityUtil.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/security/STSSecurityUtil.java
@@ -31,7 +31,9 @@
 import org.apache.hadoop.hdds.security.symmetric.ManagedSecretKey;
 import org.apache.hadoop.hdds.security.symmetric.SecretKeyClient;
 import org.apache.hadoop.ozone.om.exceptions.OMException;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos;
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMTokenProto;
+import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.S3Authentication;
 import org.apache.hadoop.security.token.SecretManager;
 import org.apache.hadoop.security.token.Token;
 
@@ -179,5 +181,44 @@ static void 
ensureEssentialFieldsArePresentInToken(STSTokenIdentifier stsTokenId
       throw new SecretManager.InvalidToken("Invalid STS token - 
secretAccessKey is null/empty");
     }
   }
+
+  /**
+   * Ensures STS-related {@link S3Authentication} fields are structurally 
consistent on the Ratis
+   * apply path. Cryptographic validation (signature, expiry, secret key 
lookup) runs on the leader
+   * RPC path (e.g. {@code S3SecurityUtil.validateS3Credential}).  This method 
performs no crypto and does
+   * not contact {@link SecretKeyClient}, keeping the apply thread 
deterministic and lightweight.
+   *
+   * @param request OM request possibly containing S3 authentication
+   * @throws OMException if resolved fields and session token presence are 
inconsistent
+   */
+  public static void 
ensureResolvedStsFieldsInvariants(OzoneManagerProtocolProtos.OMRequest request)
+      throws OMException {
+    if (!request.hasS3Authentication()) {
+      return;
+    }
+
+    final S3Authentication s3Auth = request.getS3Authentication();
+    final boolean hasSessionToken = s3Auth.hasSessionToken() && 
!s3Auth.getSessionToken().isEmpty();
+
+    if (!hasSessionToken) {
+      // If sessionToken is missing/empty, resolved fields must be empty.
+      if (s3Auth.hasResolvedStsSessionPolicy() || 
s3Auth.hasResolvedStsRoleArn() ||
+          s3Auth.hasResolvedStsOriginalAccessKeyId() || 
s3Auth.hasResolvedStsTempAccessKeyId() ||
+          s3Auth.hasResolvedStsSecretKeyId()) {
+        throw new OMException("Resolved STS fields must be empty when 
sessionToken is not present", INVALID_TOKEN);
+      }
+      return;
+    }
+
+    ensureResolvedFieldsArePresent(s3Auth);
+  }
+
+  private static void ensureResolvedFieldsArePresent(S3Authentication s3Auth) 
throws OMException {
+    if (!s3Auth.hasResolvedStsSessionPolicy() || 
!s3Auth.hasResolvedStsRoleArn() ||
+        !s3Auth.hasResolvedStsOriginalAccessKeyId() || 
!s3Auth.hasResolvedStsTempAccessKeyId() ||
+        !s3Auth.hasResolvedStsSecretKeyId()) {
+      throw new OMException("Resolved STS fields must be present when 
sessionToken is present", INVALID_TOKEN);
+    }
+  }
 }
 
diff --git 
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/ratis/TestOzoneManagerStateMachine.java
 
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/ratis/TestOzoneManagerStateMachine.java
index 111779b9573..1ab49ef67f2 100644
--- 
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/ratis/TestOzoneManagerStateMachine.java
+++ 
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/ratis/TestOzoneManagerStateMachine.java
@@ -125,6 +125,7 @@ public void setup() {
   @AfterEach
   public void tearDown() {
     sm.stop();
+    OzoneManager.setStsTokenIdentifier(null);
   }
 
   // --- startTransaction tests ---
@@ -405,6 +406,79 @@ public void testRunCommandRuntimeExceptionTerminates() 
throws Exception {
         () -> sm.runCommand(request, ti));
   }
 
+  @Test
+  public void testRunCommandSetsAndClearsStsThreadLocal() throws Exception {
+    when(om.isSecurityEnabled()).thenReturn(true);
+
+    final OzoneManagerProtocolProtos.S3Authentication s3Auth =
+        OzoneManagerProtocolProtos.S3Authentication.newBuilder()
+            .setAccessId("accessId")
+            .setSessionToken("sessionToken")
+            .setResolvedStsSessionPolicy("sessionPolicy")
+            .setResolvedStsRoleArn("roleArn")
+            .setResolvedStsOriginalAccessKeyId("originalAccessKeyId")
+            .setResolvedStsTempAccessKeyId("tempAccessKeyId")
+            .setResolvedStsSecretKeyId("secretKeyId")
+            .build();
+
+    final OMRequest request = sampleWriteRequest().toBuilder()
+        .setS3Authentication(s3Auth)
+        .build();
+    final TermIndex ti = TermIndex.valueOf(1, 5);
+
+    final OMResponse expectedResponse = OMResponse.newBuilder()
+        .setCmdType(Type.CreateKey)
+        .setStatus(Status.OK)
+        .setSuccess(true)
+        .build();
+
+    final OMClientResponse clientResponse = mock(OMClientResponse.class);
+    when(clientResponse.getOMResponse()).thenReturn(expectedResponse);
+    when(clientResponse.getOmLockDetails()).thenReturn(null);
+
+    doAnswer(invocation -> {
+      assertNotNull(OzoneManager.getStsTokenIdentifier(),
+          "Expected STS ThreadLocal to be set during 
handler.handleWriteRequest");
+      assertEquals("tempAccessKeyId", 
OzoneManager.getStsTokenIdentifier().getTempAccessKeyId());
+      assertEquals("originalAccessKeyId", 
OzoneManager.getStsTokenIdentifier().getOriginalAccessKeyId());
+      assertEquals("roleArn", 
OzoneManager.getStsTokenIdentifier().getRoleArn());
+      assertEquals("sessionPolicy", 
OzoneManager.getStsTokenIdentifier().getSessionPolicy());
+      return clientResponse;
+    }).when(handler).handleWriteRequest(eq(request), any(), eq(doubleBuffer));
+
+    assertNull(OzoneManager.getStsTokenIdentifier(), "Expected STS ThreadLocal 
to be clear before runCommand");
+
+    OMResponse result = sm.runCommand(request, ti);
+
+    assertNotNull(result);
+    assertTrue(result.getSuccess());
+    assertNull(OzoneManager.getStsTokenIdentifier(), "Expected STS ThreadLocal 
to be cleared after runCommand");
+  }
+
+  @Test
+  public void testRunCommandMissingResolvedStsFieldsReturnsErrorResponse() 
throws Exception {
+    when(om.isSecurityEnabled()).thenReturn(true);
+
+    final OzoneManagerProtocolProtos.S3Authentication s3Auth =
+        OzoneManagerProtocolProtos.S3Authentication.newBuilder()
+            .setAccessId("accessId")
+            .setSessionToken("sessionToken")
+            .build();
+
+    final OMRequest request = sampleWriteRequest().toBuilder()
+        .setS3Authentication(s3Auth)
+        .build();
+    final TermIndex ti = TermIndex.valueOf(1, 5);
+
+    OMResponse result = sm.runCommand(request, ti);
+
+    assertNotNull(result);
+    assertFalse(result.getSuccess());
+    assertEquals(Status.INVALID_TOKEN, result.getStatus());
+    assertNull(OzoneManager.getStsTokenIdentifier(), "Expected STS ThreadLocal 
to be cleared after runCommand");
+    verify(handler, never()).handleWriteRequest(any(), any(), any());
+  }
+
   // --- processResponse tests ---
 
   @Test
diff --git 
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/TestOMClientRequestWithUserInfo.java
 
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/TestOMClientRequestWithUserInfo.java
index fe11baef37e..f97ed727640 100644
--- 
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/TestOMClientRequestWithUserInfo.java
+++ 
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/TestOMClientRequestWithUserInfo.java
@@ -42,9 +42,12 @@
 import org.apache.hadoop.ozone.om.OmConfig;
 import org.apache.hadoop.ozone.om.OmMetadataManagerImpl;
 import org.apache.hadoop.ozone.om.OzoneManager;
+import org.apache.hadoop.ozone.om.exceptions.OMException;
+import org.apache.hadoop.ozone.om.execution.flowcontrol.ExecutionContext;
 import org.apache.hadoop.ozone.om.helpers.BucketLayout;
 import org.apache.hadoop.ozone.om.request.bucket.OMBucketCreateRequest;
 import org.apache.hadoop.ozone.om.request.key.OMKeyCommitRequest;
+import org.apache.hadoop.ozone.om.response.OMClientResponse;
 import org.apache.hadoop.ozone.om.upgrade.OMLayoutVersionManager;
 import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos;
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.BucketInfo;
@@ -210,6 +213,72 @@ public void testUserInfoWithSTSToken() throws IOException {
     }
   }
 
+  @Test
+  public void testPreExecuteOverwritesResolvedStsFields() throws Exception {
+    try (MockedStatic<Server> mockedRpcServer = mockStatic(Server.class)) {
+      
mockedRpcServer.when(Server::getRemoteUser).thenReturn(userGroupInformation);
+      mockedRpcServer.when(Server::getRemoteIp).thenReturn(inetAddress);
+      
mockedRpcServer.when(Server::getRemoteAddress).thenReturn(inetAddress.toString());
+
+      final String accessId = "ASIA12345";
+      final String signature = "Signature";
+      final String stringToSign = "StringToSign";
+      final String sessionToken = "SessionToken";
+      final String originalAccessKeyId = "AKIAORIGINAL";
+      final String roleArn = "arn:aws:iam::123456789012:role/test-role";
+      final String sessionPolicy = "test-session-policy";
+      final UUID secretKeyId = UUID.randomUUID();
+
+      final STSTokenIdentifier stsTokenIdentifier = 
mock(STSTokenIdentifier.class);
+      when(stsTokenIdentifier.getSessionPolicy()).thenReturn(sessionPolicy);
+      when(stsTokenIdentifier.getRoleArn()).thenReturn(roleArn);
+      
when(stsTokenIdentifier.getOriginalAccessKeyId()).thenReturn(originalAccessKeyId);
+      when(stsTokenIdentifier.getTempAccessKeyId()).thenReturn(accessId);
+      when(stsTokenIdentifier.getSecretKeyId()).thenReturn(secretKeyId);
+
+      final S3Authentication s3Authentication = S3Authentication.newBuilder()
+          .setAccessId(accessId)
+          .setSignature(signature)
+          .setStringToSign(stringToSign)
+          .setSessionToken(sessionToken)
+          .setResolvedStsSessionPolicy("client-session-policy")
+          .setResolvedStsRoleArn("client-role")
+          .setResolvedStsOriginalAccessKeyId("client-original-access-key-id")
+          .setResolvedStsTempAccessKeyId("client-temp-access-key-id")
+          .setResolvedStsSecretKeyId("client-secret-key-id")
+          .build();
+
+      OzoneManager.setS3Auth(s3Authentication);
+      OzoneManager.setStsTokenIdentifier(stsTokenIdentifier);
+
+      try {
+        final String bucketName = UUID.randomUUID().toString();
+        final String volumeName = UUID.randomUUID().toString();
+        final BucketInfo.Builder bucketInfo =
+            newBucketInfoBuilder(bucketName, volumeName)
+                .setIsVersionEnabled(true)
+                .setStorageType(StorageTypeProto.DISK);
+
+        final OMRequest omRequest = newCreateBucketRequest(bucketInfo)
+            .setS3Authentication(s3Authentication)
+            .build();
+
+        final OMBucketCreateRequest omBucketCreateRequest = new 
OMBucketCreateRequest(omRequest);
+        final OMRequest modifiedRequest = 
omBucketCreateRequest.preExecute(ozoneManager);
+        final S3Authentication modifiedS3Auth = 
modifiedRequest.getS3Authentication();
+
+        assertEquals(sessionPolicy, 
modifiedS3Auth.getResolvedStsSessionPolicy());
+        assertEquals(roleArn, modifiedS3Auth.getResolvedStsRoleArn());
+        assertEquals(originalAccessKeyId, 
modifiedS3Auth.getResolvedStsOriginalAccessKeyId());
+        assertEquals(accessId, modifiedS3Auth.getResolvedStsTempAccessKeyId());
+        assertEquals(secretKeyId.toString(), 
modifiedS3Auth.getResolvedStsSecretKeyId());
+      } finally {
+        OzoneManager.setStsTokenIdentifier(null);
+        OzoneManager.setS3Auth(null);
+      }
+    }
+  }
+
   @Test
   public void testUserInfoWithSTSAccessKeyMissingSessionToken() {
     final String accessId = "ASIA12345";
@@ -306,4 +375,58 @@ public void 
testUserInfoWithSessionTokenButEmptyOriginalAccessKeyId() {
     }
   }
 
+  @Test
+  public void 
testPreExecuteRejectsSessionTokenWithoutStsTokenIdentifierWhenSecurityEnabled() 
{
+    when(ozoneManager.isSecurityEnabled()).thenReturn(true);
+
+    final String accessId = "ASIA12345";
+    final String signature = "Signature";
+    final String stringToSign = "StringToSign";
+    final String sessionToken = "SessionToken";
+
+    final S3Authentication s3Authentication = S3Authentication.newBuilder()
+        .setAccessId(accessId)
+        .setSignature(signature)
+        .setStringToSign(stringToSign)
+        .setSessionToken(sessionToken)
+        .build();
+
+    final OMRequest omRequest = OMRequest.newBuilder()
+        .setCmdType(OzoneManagerProtocolProtos.Type.CommitKey)
+        .setClientId(UUID.randomUUID().toString())
+        .setS3Authentication(s3Authentication)
+        .build();
+
+    try {
+      OzoneManager.setStsTokenIdentifier(null);
+      final OMClientRequest omClientRequest = new 
DummyOMClientRequest(omRequest);
+
+      final OMException ex = assertThrows(OMException.class, () -> 
omClientRequest.preExecute(ozoneManager));
+      assertEquals(OMException.ResultCodes.INVALID_REQUEST, ex.getResult());
+      assertTrue(ex.getMessage().contains("session token"));
+    } finally {
+      OzoneManager.setStsTokenIdentifier(null);
+    }
+  }
+
+  private static final class DummyOMClientRequest extends OMClientRequest {
+    private DummyOMClientRequest(OMRequest omRequest) {
+      super(omRequest);
+    }
+
+    @Override
+    public OzoneManagerProtocolProtos.UserInfo getUserIfNotExists(OzoneManager 
ozoneManager) {
+      return OzoneManagerProtocolProtos.UserInfo.newBuilder()
+          .setUserName("test-user")
+          .setHostName("localhost")
+          .setRemoteAddress("127.0.0.1")
+          .build();
+    }
+
+    @Override
+    public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager, 
ExecutionContext context) {
+      return null;
+    }
+  }
+
 }
diff --git 
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/s3/security/TestS3GetSecretRequest.java
 
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/s3/security/TestS3GetSecretRequest.java
index 0067b2b3804..5f23bfb14e2 100644
--- 
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/s3/security/TestS3GetSecretRequest.java
+++ 
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/s3/security/TestS3GetSecretRequest.java
@@ -179,8 +179,12 @@ public void setUp() throws Exception {
 
   @AfterEach
   public void tearDown() throws Exception {
+    if (omMetadataManager != null) {
+      omMetadataManager.close();
+    }
     omMetrics.unRegister();
     framework().clearInlineMocks();
+    Server.getCurCall().remove();
   }
 
   private OMRequest createTenantRequest(String tenantNameStr) {
diff --git 
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/security/TestSTSSecurityUtil.java
 
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/security/TestSTSSecurityUtil.java
index c93df8a4900..8decf4fd316 100644
--- 
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/security/TestSTSSecurityUtil.java
+++ 
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/security/TestSTSSecurityUtil.java
@@ -35,7 +35,10 @@
 import org.apache.hadoop.hdds.security.symmetric.SecretKeyClient;
 import org.apache.hadoop.io.Text;
 import org.apache.hadoop.ozone.om.exceptions.OMException;
+import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRequest;
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMTokenProto;
+import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.S3Authentication;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Type;
 import org.apache.hadoop.security.token.SecretManager;
 import org.apache.hadoop.security.token.Token;
 import org.apache.ozone.test.TestClock;
@@ -374,4 +377,76 @@ public void 
testEnsureEssentialFieldsArePresentInTokenMissingSecretAccessKey() {
         .isInstanceOf(SecretManager.InvalidToken.class)
         .hasMessage("Invalid STS token - secretAccessKey is null/empty");
   }
+
+  @Test
+  public void testEnsureResolvedStsFieldsInvariantsSuccess() throws Exception {
+    final String tokenString = tokenSecretManager.createSTSTokenString(
+        TEMP_ACCESS_KEY, ORIGINAL_ACCESS_KEY, ROLE_ARN, DURATION_SECONDS, 
SECRET_ACCESS_KEY, SESSION_POLICY, clock);
+
+    final S3Authentication s3Auth = S3Authentication.newBuilder()
+        .setSessionToken(tokenString)
+        .setResolvedStsSessionPolicy(SESSION_POLICY)
+        .setResolvedStsRoleArn(ROLE_ARN)
+        .setResolvedStsOriginalAccessKeyId(ORIGINAL_ACCESS_KEY)
+        .setResolvedStsTempAccessKeyId(TEMP_ACCESS_KEY)
+        .setResolvedStsSecretKeyId(secretKeyId.toString())
+        .build();
+
+    final OMRequest request = OMRequest.newBuilder()
+        .setCmdType(Type.CreateBucket)
+        .setClientId("client-id")
+        .setS3Authentication(s3Auth)
+        .build();
+
+    STSSecurityUtil.ensureResolvedStsFieldsInvariants(request);
+  }
+
+  @Test
+  public void testEnsureResolvedStsFieldsInvariantsMissingSessionToken() {
+    final S3Authentication s3Auth = S3Authentication.newBuilder()
+        .setResolvedStsSessionPolicy(SESSION_POLICY)
+        .build();
+
+    final OMRequest request = OMRequest.newBuilder()
+        .setCmdType(Type.CreateBucket)
+        .setClientId("client-id")
+        .setS3Authentication(s3Auth)
+        .build();
+
+    assertThatThrownBy(() -> 
STSSecurityUtil.ensureResolvedStsFieldsInvariants(request))
+        .isInstanceOf(OMException.class)
+        .hasMessageContaining("Resolved STS fields must be empty when 
sessionToken is not present");
+  }
+
+  @Test
+  public void testEnsureResolvedStsFieldsInvariantsMissingResolvedFields() 
throws Exception {
+    final String tokenString = tokenSecretManager.createSTSTokenString(
+        TEMP_ACCESS_KEY, ORIGINAL_ACCESS_KEY, ROLE_ARN, DURATION_SECONDS,
+        SECRET_ACCESS_KEY, SESSION_POLICY, clock);
+
+    final S3Authentication s3Auth = S3Authentication.newBuilder()
+        .setSessionToken(tokenString)
+        .build();
+
+    final OMRequest request = OMRequest.newBuilder()
+        .setCmdType(Type.CreateBucket)
+        .setClientId("client-id")
+        .setS3Authentication(s3Auth)
+        .build();
+
+    assertThatThrownBy(() -> 
STSSecurityUtil.ensureResolvedStsFieldsInvariants(request))
+        .isInstanceOf(OMException.class)
+        .hasMessageContaining("Resolved STS fields must be present when 
sessionToken is present");
+  }
+
+  @Test
+  public void testEnsureResolvedStsFieldsInvariantsNoS3Auth() throws Exception 
{
+    final OMRequest request = OMRequest.newBuilder()
+        .setCmdType(Type.CreateBucket)
+        .setClientId("client-id")
+        .build();
+
+    // Should not throw
+    STSSecurityUtil.ensureResolvedStsFieldsInvariants(request);
+  }
 }


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

Reply via email to