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

sodonnell 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 56da3888204 HDDS-14150. [STS] Connect STS Endpoint to Backend 
Processing (#9673)
56da3888204 is described below

commit 56da3888204cbd9ce8e701cfc0f330a92d378a45
Author: fmorg-git <[email protected]>
AuthorDate: Tue Jan 27 13:55:15 2026 -0800

    HDDS-14150. [STS] Connect STS Endpoint to Backend Processing (#9673)
---
 .../org/apache/hadoop/ozone/OzoneConfigKeys.java   |   4 +
 .../org/apache/hadoop/ozone/om/OzoneManager.java   |  28 ++++
 .../om/ratis/utils/OzoneManagerRatisUtils.java     |   8 +
 .../om/ratis/TestOzoneManagerRatisRequest.java     |  58 +++++++
 .../apache/hadoop/ozone/om/ratis/package-info.java |  21 +++
 .../hadoop/ozone/s3/endpoint/EndpointBase.java     |   4 +
 .../ozone/s3/signature/AWSSignatureProcessor.java  |  39 +++++
 .../hadoop/ozone/s3/signature/SignatureInfo.java   |  25 ++-
 .../ozone/s3sts/S3AssumeRoleResponseXml.java       | 179 ++++++++++++++++++++
 .../apache/hadoop/ozone/s3sts/S3STSConfigKeys.java |   4 +-
 .../apache/hadoop/ozone/s3sts/S3STSEndpoint.java   | 180 ++++++++++++---------
 .../hadoop/ozone/s3sts/S3STSEndpointBase.java      |   5 +
 .../s3sts/{TestSTS.java => TestS3STSEndpoint.java} |  92 +++++++++--
 .../apache/hadoop/ozone/s3sts/package-info.java    |  21 +++
 14 files changed, 575 insertions(+), 93 deletions(-)

diff --git 
a/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/OzoneConfigKeys.java 
b/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/OzoneConfigKeys.java
index ceca7d0c882..7aa3a6bdab6 100644
--- 
a/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/OzoneConfigKeys.java
+++ 
b/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/OzoneConfigKeys.java
@@ -693,6 +693,10 @@ public final class OzoneConfigKeys {
   public static final String OZONE_CLIENT_ELASTIC_BYTE_BUFFER_POOL_MAX_SIZE =
       "ozone.client.elastic.byte.buffer.pool.max.size";
   public static final String 
OZONE_CLIENT_ELASTIC_BYTE_BUFFER_POOL_MAX_SIZE_DEFAULT = "16GB";
+  
+  public static final String OZONE_S3G_STS_HTTP_ENABLED_KEY =
+      "ozone.s3g.sts.http.enabled";
+  public static final boolean OZONE_S3G_STS_HTTP_ENABLED_DEFAULT = false;
 
   /**
    * There is no need to instantiate this class.
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java
index 7917130950e..cda7c76b38b 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java
@@ -476,6 +476,7 @@ public final class OzoneManager extends 
ServiceRuntimeInfoImpl
 
   private final boolean isS3MultiTenancyEnabled;
   private final boolean isStrictS3;
+  private final boolean isS3STSEnabled;
   private ExitManager exitManager;
 
   private OzoneManagerPrepareState prepareState;
@@ -685,6 +686,11 @@ private OzoneManager(OzoneConfiguration conf, 
StartupOption startupOption)
     this.isS3MultiTenancyEnabled =
         OMMultiTenantManager.checkAndEnableMultiTenancy(this, conf);
 
+    // Enable S3 STS if config key is set
+    this.isS3STSEnabled = conf.getBoolean(
+        OzoneConfigKeys.OZONE_S3G_STS_HTTP_ENABLED_KEY,
+        OzoneConfigKeys.OZONE_S3G_STS_HTTP_ENABLED_DEFAULT);
+
     metrics = OMMetrics.create();
     omSnapshotIntMetrics = OmSnapshotInternalMetrics.create();
     perfMetrics = OMPerformanceMetrics.register();
@@ -1137,6 +1143,13 @@ public boolean isStrictS3() {
     return isStrictS3;
   }
 
+  /**
+   * Returns true if S3 STS is enabled; false otherwise.
+   */
+  public boolean isS3STSEnabled() {
+    return isS3STSEnabled;
+  }
+
   /**
    * Throws OMException FEATURE_NOT_ENABLED if S3 multi-tenancy is not enabled.
    */
@@ -1150,6 +1163,21 @@ public void checkS3MultiTenancyEnabled() throws 
OMException {
         FEATURE_NOT_ENABLED);
   }
 
+  /**
+   * Throws OMException FEATURE_NOT_ENABLED if S3 STS (AssumeRole) is not 
enabled.
+   */
+  public void checkS3STSEnabled() throws OMException {
+    if (isS3STSEnabled()) {
+      if (getAccessAuthorizer().isNative()) {
+        throw new OMException("S3 STS is not enabled for Ozone Native 
Authorizer", FEATURE_NOT_ENABLED);
+      }
+      return;
+    }
+
+    throw new OMException("S3 STS is not enabled. Please set " + 
OzoneConfigKeys.OZONE_S3G_STS_HTTP_ENABLED_KEY +
+        " to true and restart all OMs.", FEATURE_NOT_ENABLED);
+  }
+
   /**
    * Return config value of {@link OzoneConfigKeys#OZONE_SECURITY_ENABLED_KEY}.
    */
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis/utils/OzoneManagerRatisUtils.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis/utils/OzoneManagerRatisUtils.java
index 4f1b2fc952d..bacd0b65258 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis/utils/OzoneManagerRatisUtils.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis/utils/OzoneManagerRatisUtils.java
@@ -30,6 +30,8 @@
 import java.nio.file.InvalidPathException;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.time.Clock;
+import java.time.ZoneOffset;
 import org.apache.hadoop.hdds.conf.ConfigurationSource;
 import org.apache.hadoop.hdds.conf.OzoneConfiguration;
 import org.apache.hadoop.hdds.security.SecurityConfig;
@@ -68,6 +70,7 @@
 import org.apache.hadoop.ozone.om.request.key.acl.prefix.OMPrefixSetAclRequest;
 import 
org.apache.hadoop.ozone.om.request.s3.multipart.S3ExpiredMultipartUploadsAbortRequest;
 import org.apache.hadoop.ozone.om.request.s3.security.OMSetSecretRequest;
+import org.apache.hadoop.ozone.om.request.s3.security.S3AssumeRoleRequest;
 import 
org.apache.hadoop.ozone.om.request.s3.security.S3DeleteRevokedSTSTokensRequest;
 import org.apache.hadoop.ozone.om.request.s3.security.S3GetSecretRequest;
 import org.apache.hadoop.ozone.om.request.s3.security.S3RevokeSTSTokenRequest;
@@ -119,6 +122,8 @@ public final class OzoneManagerRatisUtils {
   private static final Logger LOG = LoggerFactory
       .getLogger(OzoneManagerRatisUtils.class);
 
+  private static final Clock CLOCK = Clock.system(ZoneOffset.UTC);
+
   private OzoneManagerRatisUtils() {
   }
 
@@ -198,6 +203,9 @@ public static OMClientRequest createClientRequest(OMRequest 
omRequest,
       return new OMSetSecretRequest(omRequest);
     case RevokeS3Secret:
       return new S3RevokeSecretRequest(omRequest);
+    case AssumeRole:
+      ozoneManager.checkS3STSEnabled();
+      return new S3AssumeRoleRequest(omRequest, CLOCK);
     case RevokeSTSToken:
       return new S3RevokeSTSTokenRequest(omRequest);
     case DeleteRevokedSTSTokens:
diff --git 
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/ratis/TestOzoneManagerRatisRequest.java
 
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/ratis/TestOzoneManagerRatisRequest.java
index fdc9e0f008d..4d3bdef38e3 100644
--- 
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/ratis/TestOzoneManagerRatisRequest.java
+++ 
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/ratis/TestOzoneManagerRatisRequest.java
@@ -18,8 +18,10 @@
 package org.apache.hadoop.ozone.om.ratis;
 
 import static 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Status.INVALID_REQUEST;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.CALLS_REAL_METHODS;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
@@ -44,6 +46,8 @@
 import org.apache.hadoop.ozone.om.request.OMRequestTestUtils;
 import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos;
 import 
org.apache.hadoop.ozone.protocolPB.OzoneManagerProtocolServerSideTranslatorPB;
+import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer;
+import org.apache.ratis.protocol.ClientId;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.io.TempDir;
 
@@ -136,4 +140,58 @@ public void testUnknownRequestHandling()
 
     assertEquals(expectedResponse, actualResponse);
   }
+
+  @Test
+  public void testAssumeRoleRejectedWhenStsDisabled() {
+    ozoneManager = mock(OzoneManager.class, CALLS_REAL_METHODS);
+    when(ozoneManager.isS3STSEnabled()).thenReturn(false);
+
+    final OzoneManagerProtocolProtos.OMRequest omRequest =
+        OzoneManagerProtocolProtos.OMRequest.newBuilder()
+            .setCmdType(OzoneManagerProtocolProtos.Type.AssumeRole)
+            .setClientId(ClientId.randomId().toString())
+            .build();
+
+    final OMException omException = assertThrows(OMException.class,
+        () -> OzoneManagerRatisUtils.createClientRequest(omRequest, 
ozoneManager));
+    assertEquals(OMException.ResultCodes.FEATURE_NOT_ENABLED, 
omException.getResult());
+  }
+
+  @Test
+  public void testAssumeRoleRejectedWhenStsEnabledButNativeAuthorizerUsed() {
+    ozoneManager = mock(OzoneManager.class, CALLS_REAL_METHODS);
+    when(ozoneManager.isS3STSEnabled()).thenReturn(true);
+
+    final IAccessAuthorizer authorizer = mock(IAccessAuthorizer.class);
+    when(authorizer.isNative()).thenReturn(true);
+    when(ozoneManager.getAccessAuthorizer()).thenReturn(authorizer);
+
+    final OzoneManagerProtocolProtos.OMRequest omRequest =
+        OzoneManagerProtocolProtos.OMRequest.newBuilder()
+            .setCmdType(OzoneManagerProtocolProtos.Type.AssumeRole)
+            .setClientId(ClientId.randomId().toString())
+            .build();
+
+    final OMException omException = assertThrows(OMException.class,
+        () -> OzoneManagerRatisUtils.createClientRequest(omRequest, 
ozoneManager));
+    assertEquals(OMException.ResultCodes.FEATURE_NOT_ENABLED, 
omException.getResult());
+  }
+
+  @Test
+  public void testAssumeRoleAllowedWhenStsEnabledAndNativeAuthorizerNotUsed() {
+    ozoneManager = mock(OzoneManager.class, CALLS_REAL_METHODS);
+    when(ozoneManager.isS3STSEnabled()).thenReturn(true);
+
+    final IAccessAuthorizer authorizer = mock(IAccessAuthorizer.class);
+    when(authorizer.isNative()).thenReturn(false);
+    when(ozoneManager.getAccessAuthorizer()).thenReturn(authorizer);
+
+    final OzoneManagerProtocolProtos.OMRequest omRequest =
+        OzoneManagerProtocolProtos.OMRequest.newBuilder()
+            .setCmdType(OzoneManagerProtocolProtos.Type.AssumeRole)
+            .setClientId(ClientId.randomId().toString())
+            .build();
+
+    assertDoesNotThrow(() -> 
OzoneManagerRatisUtils.createClientRequest(omRequest, ozoneManager));
+  }
 }
diff --git 
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/ratis/package-info.java
 
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/ratis/package-info.java
new file mode 100644
index 00000000000..3dea7af810c
--- /dev/null
+++ 
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/ratis/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Package contains test classes for OM Ratis server implementation.
+ */
+package org.apache.hadoop.ozone.om.ratis;
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 a7ef000c672..1f8e0532db8 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
@@ -139,6 +139,10 @@ public void initialization() {
     s3Auth = new S3Auth(signatureInfo.getStringToSign(),
         signatureInfo.getSignature(),
         signatureInfo.getAwsAccessId(), signatureInfo.getAwsAccessId());
+    if (signatureInfo.getSessionToken() != null &&
+        !signatureInfo.getSessionToken().isEmpty()) {
+      s3Auth.setSessionToken(signatureInfo.getSessionToken());
+    }
     LOG.debug("S3 access id: {}", s3Auth.getAccessID());
     ClientProtocol clientProtocol =
         getClient().getObjectStore().getClientProxy();
diff --git 
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/signature/AWSSignatureProcessor.java
 
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/signature/AWSSignatureProcessor.java
index 9abf2fc227d..92c2f102c90 100644
--- 
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/signature/AWSSignatureProcessor.java
+++ 
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/signature/AWSSignatureProcessor.java
@@ -25,6 +25,7 @@
 import static 
org.apache.hadoop.ozone.s3sts.S3STSConfigKeys.OZONE_S3G_STS_PAYLOAD_HASH_MAX_VALUE;
 
 import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Strings;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
@@ -68,6 +69,8 @@ public class AWSSignatureProcessor implements 
SignatureProcessor {
   private static final AuditLogger AUDIT =
       new AuditLogger(AuditLoggerType.S3GLOGGER);
 
+  private static final String X_AMZ_SECURITY_TOKEN = "x-amz-security-token";
+
   @Context
   private ContainerRequestContext context;
 
@@ -103,6 +106,15 @@ public SignatureInfo parseSignature() throws OS3Exception, 
IOException, NoSuchAl
     if (signatureInfo == null) {
       signatureInfo = new 
SignatureInfo.Builder(Version.NONE).setService("s3").build();
     }
+
+    // Capture STS session token if present (header-based or query-based).
+    // - Header-based SigV4: x-amz-security-token
+    // - Query-based (for presigned URLs): X-Amz-Security-Token
+    final String sessionToken = extractSessionToken(headers);
+    if (sessionToken != null && !sessionToken.isEmpty()) {
+      signatureInfo.setSessionToken(sessionToken);
+    }
+
     String payloadHash = getPayloadHash(headers, signatureInfo);
     signatureInfo.setPayloadHash(payloadHash);
     signatureInfo.setUnfilteredURI(
@@ -110,6 +122,33 @@ public SignatureInfo parseSignature() throws OS3Exception, 
IOException, NoSuchAl
     return signatureInfo;
   }
 
+  private String extractSessionToken(LowerCaseKeyStringMap headers) {
+    // Header-based token
+    final String headerToken = headers.get(X_AMZ_SECURITY_TOKEN);
+    if (headerToken != null && !headerToken.isEmpty()) {
+      return headerToken;
+    }
+
+    // Query-based token - this would be used for presigned URLs
+    final MultivaluedMap<String, String> queryParams = 
context.getUriInfo().getQueryParameters();
+    if (queryParams == null) {
+      return null;
+    }
+    for (Map.Entry<String, List<String>> entry : queryParams.entrySet()) {
+      final String key = entry.getKey();
+      if (Strings.isNullOrEmpty(key)) {
+        continue;
+      }
+      if (key.compareToIgnoreCase(X_AMZ_SECURITY_TOKEN) == 0) {
+        final List<String> values = entry.getValue();
+        if (values != null && !values.isEmpty()) {
+          return values.get(0);
+        }
+      }
+    }
+    return null;
+  }
+
   private String getPayloadHash(Map<String, String> headers, SignatureInfo 
signatureInfo)
       throws OS3Exception, NoSuchAlgorithmException, IOException {
     if (signatureInfo.getVersion() == Version.V2) {
diff --git 
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/signature/SignatureInfo.java
 
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/signature/SignatureInfo.java
index ffe8a8dddd6..52c7b00ccd0 100644
--- 
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/signature/SignatureInfo.java
+++ 
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/signature/SignatureInfo.java
@@ -59,6 +59,13 @@ public class SignatureInfo {
 
   private String service = null;
 
+  /**
+   * Optional AWS session token (x-amz-security-token / X-Amz-Security-Token).
+   * <p>
+   * This is required for STS temporary credentials when calling S3 APIs.
+   */
+  private String sessionToken = null;
+
   public SignatureInfo() { }
 
   private SignatureInfo(Builder b) {
@@ -78,7 +85,8 @@ public void initialize(SignatureInfo signatureInfo) {
         .setUnfilteredURI(signatureInfo.getUnfilteredURI())
         .setStringToSign(signatureInfo.getStringToSign())
         .setPayloadHash(signatureInfo.getPayloadHash())
-        .setService(signatureInfo.getService()));
+        .setService(signatureInfo.getService())
+        .setSessionToken(signatureInfo.getSessionToken()));
   }
 
   private void initialize(Builder b) {
@@ -95,6 +103,7 @@ private void initialize(Builder b) {
     this.stringToSign = b.stringToSign;
     this.payloadHash = b.payloadHash;
     this.service = b.service;
+    this.sessionToken = b.sessionToken;
   }
 
   public String getAwsAccessId() {
@@ -165,6 +174,14 @@ public void setService(String service) {
     this.service = service;
   }
 
+  public String getSessionToken() {
+    return sessionToken;
+  }
+
+  public void setSessionToken(String sessionToken) {
+    this.sessionToken = sessionToken;
+  }
+
   /**
    * Signature version.
    */
@@ -189,6 +206,7 @@ public static class Builder {
     private String stringToSign = null;
     private String payloadHash = null;
     private String service = null;
+    private String sessionToken = null;
 
     public Builder(Version version) {
       this.version = version;
@@ -254,6 +272,11 @@ public Builder setService(String service) {
       return this;
     }
 
+    public Builder setSessionToken(String sessionToken) {
+      this.sessionToken = sessionToken;
+      return this;
+    }
+
     public SignatureInfo build() {
       return new SignatureInfo(this);
     }
diff --git 
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3sts/S3AssumeRoleResponseXml.java
 
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3sts/S3AssumeRoleResponseXml.java
new file mode 100644
index 00000000000..bd4be9a7eaf
--- /dev/null
+++ 
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3sts/S3AssumeRoleResponseXml.java
@@ -0,0 +1,179 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.ozone.s3sts;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ * JAXB model for AWS STS AssumeRoleResponse.
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlRootElement(name = "AssumeRoleResponse", namespace = 
"https://sts.amazonaws.com/doc/2011-06-15/";)
+public class S3AssumeRoleResponseXml {
+
+  @XmlElement(name = "AssumeRoleResult")
+  private AssumeRoleResult assumeRoleResult;
+
+  @XmlElement(name = "ResponseMetadata")
+  private ResponseMetadata responseMetadata;
+
+  public AssumeRoleResult getAssumeRoleResult() {
+    return assumeRoleResult;
+  }
+
+  public void setAssumeRoleResult(AssumeRoleResult assumeRoleResult) {
+    this.assumeRoleResult = assumeRoleResult;
+  }
+
+  public ResponseMetadata getResponseMetadata() {
+    return responseMetadata;
+  }
+
+  public void setResponseMetadata(ResponseMetadata responseMetadata) {
+    this.responseMetadata = responseMetadata;
+  }
+
+  /**
+   * AssumeRoleResult element.
+   */
+  @XmlAccessorType(XmlAccessType.FIELD)
+  public static class AssumeRoleResult {
+    @XmlElement(name = "Credentials")
+    private Credentials credentials;
+
+    @XmlElement(name = "AssumedRoleUser")
+    private AssumedRoleUser assumedRoleUser;
+
+    public Credentials getCredentials() {
+      return credentials;
+    }
+
+    public void setCredentials(Credentials credentials) {
+      this.credentials = credentials;
+    }
+
+    public AssumedRoleUser getAssumedRoleUser() {
+      return assumedRoleUser;
+    }
+
+    public void setAssumedRoleUser(AssumedRoleUser assumedRoleUser) {
+      this.assumedRoleUser = assumedRoleUser;
+    }
+  }
+
+  /**
+   * Credentials element.
+   */
+  @XmlAccessorType(XmlAccessType.FIELD)
+  public static class Credentials {
+    @XmlElement(name = "AccessKeyId")
+
+    private String accessKeyId;
+    @XmlElement(name = "SecretAccessKey")
+
+    private String secretAccessKey;
+    @XmlElement(name = "SessionToken")
+
+    private String sessionToken;
+    @XmlElement(name = "Expiration")
+
+    private String expiration;
+
+    public String getAccessKeyId() {
+      return accessKeyId;
+    }
+
+    public void setAccessKeyId(String accessKeyId) {
+      this.accessKeyId = accessKeyId;
+    }
+
+    public String getSecretAccessKey() {
+      return secretAccessKey;
+    }
+
+    public void setSecretAccessKey(String secretAccessKey) {
+      this.secretAccessKey = secretAccessKey;
+    }
+
+    public String getSessionToken() {
+      return sessionToken;
+    }
+
+    public void setSessionToken(String sessionToken) {
+      this.sessionToken = sessionToken;
+    }
+
+    public String getExpiration() {
+      return expiration;
+    }
+
+    public void setExpiration(String expiration) {
+      this.expiration = expiration;
+    }
+  }
+
+  /**
+   * AssumedRoleId element.
+   */
+  @XmlAccessorType(XmlAccessType.FIELD)
+  public static class AssumedRoleUser {
+    @XmlElement(name = "AssumedRoleId")
+    private String assumedRoleId;
+
+    @XmlElement(name = "Arn")
+    private String arn;
+
+    public String getAssumedRoleId() {
+      return assumedRoleId;
+    }
+
+    public void setAssumedRoleId(String assumedRoleId) {
+      this.assumedRoleId = assumedRoleId;
+    }
+
+    public String getArn() {
+      return arn;
+    }
+
+    public void setArn(String arn) {
+      this.arn = arn;
+    }
+  }
+
+  /**
+   * ResponseMetadata element.
+   */
+  @XmlAccessorType(XmlAccessType.FIELD)
+  public static class ResponseMetadata {
+    @XmlElement(name = "RequestId")
+    private String requestId;
+
+    public String getRequestId() {
+      return requestId;
+    }
+
+    public void setRequestId(String requestId) {
+      this.requestId = requestId;
+    }
+  }
+}
+
+
diff --git 
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3sts/S3STSConfigKeys.java
 
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3sts/S3STSConfigKeys.java
index 1512d3fc3c4..aca0cbd470b 100644
--- 
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3sts/S3STSConfigKeys.java
+++ 
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3sts/S3STSConfigKeys.java
@@ -17,13 +17,15 @@
 
 package org.apache.hadoop.ozone.s3sts;
 
+import org.apache.hadoop.ozone.OzoneConfigKeys;
+
 /**
  * This class contains constants for configuration keys used
  * in S3 STS endpoint.
  */
 public final class S3STSConfigKeys {
   public static final String OZONE_S3G_STS_HTTP_ENABLED_KEY =
-      "ozone.s3g.sts.http.enabled";
+      OzoneConfigKeys.OZONE_S3G_STS_HTTP_ENABLED_KEY;
   public static final String OZONE_S3G_STS_HTTP_BIND_HOST_KEY =
       "ozone.s3g.sts.http-bind-host";
   public static final String OZONE_S3G_STS_HTTPS_BIND_HOST_KEY =
diff --git 
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3sts/S3STSEndpoint.java
 
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3sts/S3STSEndpoint.java
index 124581c6f26..e33e9f80552 100644
--- 
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3sts/S3STSEndpoint.java
+++ 
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3sts/S3STSEndpoint.java
@@ -17,11 +17,12 @@
 
 package org.apache.hadoop.ozone.s3sts;
 
+import com.google.common.base.Strings;
 import java.io.IOException;
+import java.io.StringWriter;
 import java.time.Instant;
+import java.time.ZoneOffset;
 import java.time.format.DateTimeFormatter;
-import java.util.Base64;
-import java.util.Random;
 import java.util.UUID;
 import javax.ws.rs.FormParam;
 import javax.ws.rs.GET;
@@ -31,6 +32,10 @@
 import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import org.apache.hadoop.ozone.om.helpers.AssumeRoleResponseInfo;
 import org.apache.hadoop.ozone.s3.exception.OS3Exception;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -65,9 +70,11 @@ public class S3STSEndpoint extends S3STSEndpointBase {
   private static final String GET_ACCESS_KEY_INFO_ACTION = "GetAccessKeyInfo";
 
   // Default token duration (in seconds) - AWS default is 3600 (1 hour)
+  // TODO - add these constants and also validations in a common place that 
both endpoint and backend can use
   private static final int DEFAULT_DURATION_SECONDS = 3600;
   private static final int MAX_DURATION_SECONDS = 43200; // 12 hours
   private static final int MIN_DURATION_SECONDS = 900;   // 15 minutes
+  private static final int MAX_SESSION_POLICY_SIZE = 2048;
 
   /**
    * STS endpoint that handles GET requests with query parameters.
@@ -87,9 +94,10 @@ public Response get(
       @QueryParam("RoleArn") String roleArn,
       @QueryParam("RoleSessionName") String roleSessionName,
       @QueryParam("DurationSeconds") Integer durationSeconds,
-      @QueryParam("Version") String version) throws OS3Exception {
+      @QueryParam("Version") String version,
+      @QueryParam("Policy") String awsIamSessionPolicy) throws OS3Exception {
 
-    return handleSTSRequest(action, roleArn, roleSessionName, durationSeconds, 
version);
+    return handleSTSRequest(action, roleArn, roleSessionName, durationSeconds, 
version, awsIamSessionPolicy);
   }
 
   /**
@@ -110,13 +118,14 @@ public Response post(
       @FormParam("RoleArn") String roleArn,
       @FormParam("RoleSessionName") String roleSessionName,
       @FormParam("DurationSeconds") Integer durationSeconds,
-      @FormParam("Version") String version) throws OS3Exception {
+      @FormParam("Version") String version,
+      @FormParam("Policy") String awsIamSessionPolicy) throws OS3Exception {
 
-    return handleSTSRequest(action, roleArn, roleSessionName, durationSeconds, 
version);
+    return handleSTSRequest(action, roleArn, roleSessionName, durationSeconds, 
version, awsIamSessionPolicy);
   }
 
   private Response handleSTSRequest(String action, String roleArn, String 
roleSessionName,
-      Integer durationSeconds, String version) throws OS3Exception {
+      Integer durationSeconds, String version, String awsIamSessionPolicy) 
throws OS3Exception {
     try {
       if (action == null) {
         return Response.status(Response.Status.BAD_REQUEST)
@@ -140,7 +149,7 @@ private Response handleSTSRequest(String action, String 
roleArn, String roleSess
 
       switch (action) {
       case ASSUME_ROLE_ACTION:
-        return handleAssumeRole(roleArn, roleSessionName, duration);
+        return handleAssumeRole(roleArn, roleSessionName, duration, 
awsIamSessionPolicy);
       // These operations are not supported yet
       case GET_SESSION_TOKEN_ACTION:
       case ASSUME_ROLE_WITH_SAML_ACTION:
@@ -180,9 +189,9 @@ private int validateDuration(Integer durationSeconds) 
throws IllegalArgumentExce
     return durationSeconds;
   }
 
-  private Response handleAssumeRole(String roleArn, String roleSessionName, 
int duration)
+  private Response handleAssumeRole(String roleArn, String roleSessionName, 
int duration, String awsIamSessionPolicy)
       throws IOException, OS3Exception {
-    // Validate required parameters for AssumeRole. RoleArn is required to 
pass the
+    // Validate required parameters for AssumeRole. RoleArn is required
     if (roleArn == null || roleArn.isEmpty()) {
       return Response.status(Response.Status.BAD_REQUEST)
           .entity("Missing required parameter: " + ROLE_ARN_PARAM)
@@ -203,11 +212,27 @@ private Response handleAssumeRole(String roleArn, String 
roleSessionName, int du
           .build();
     }
 
-    // TODO: Integrate with Ozone Manager to get actual temporary credentials
-    // String dummyCredentials = 
getClient().getObjectStore().getS3StsToken(userNameFromRequest());
-    // Generate AssumeRole response
-    String responseXml = generateAssumeRoleResponse(roleArn, roleSessionName, 
duration);
+    // Check Policy size if available
+    if (awsIamSessionPolicy != null && awsIamSessionPolicy.length() > 
MAX_SESSION_POLICY_SIZE) {
+      return Response.status(Response.Status.BAD_REQUEST)
+          .entity("Policy length exceeded maximum allowed length of " + 
MAX_SESSION_POLICY_SIZE)
+          .build();
+    }
+
+    final String assumedRoleUserArn;
+    try {
+      assumedRoleUserArn = toAssumedRoleUserArn(roleArn, roleSessionName);
+    } catch (IllegalArgumentException e) {
+      return Response.status(Response.Status.BAD_REQUEST)
+          .entity(e.getMessage())
+          .build();
+    }
 
+    final AssumeRoleResponseInfo responseInfo = getClient()
+        .getObjectStore()
+        .assumeRole(roleArn, roleSessionName, duration, awsIamSessionPolicy);
+    // Generate AssumeRole response
+    final String responseXml = generateAssumeRoleResponse(assumedRoleUserArn, 
responseInfo);
     return Response.ok(responseXml)
         .header("Content-Type", "text/xml")
         .build();
@@ -222,78 +247,75 @@ private boolean isValidRoleSessionName(String 
roleSessionName) {
     return roleSessionName.matches("[a-zA-Z0-9+=,.@\\-]+");
   }
 
-  // TODO: replace mock implementation with actual logic to generate new 
credentials
-  private String generateAssumeRoleResponse(String roleArn, String 
roleSessionName, int duration) {
-    // Generate realistic-looking temporary credentials
-    String accessKeyId = "ASIA" + generateRandomAlphanumeric(16); // AWS temp 
keys start with ASIA
-    String secretAccessKey = generateRandomBase64(40);
-    String sessionToken = generateSessionToken();
-    String expiration = getExpirationTime(duration);
-
-    // Generate AssumedRoleId (format: AROLEID:RoleSessionName)
-    String roleId = "AROA" + generateRandomAlphanumeric(16);
-    String assumedRoleId = roleId + ":" + roleSessionName;
-
-    String requestId = UUID.randomUUID().toString();
-
-    return String.format(
-        "<?xml version=\"1.0\" encoding=\"UTF-8\"?>%n" +
-            "<AssumeRoleResponse 
xmlns=\"https://sts.amazonaws.com/doc/2011-06-15/\";>%n" +
-            "  <AssumeRoleResult>%n" +
-            "    <Credentials>%n" +
-            "      <AccessKeyId>%s</AccessKeyId>%n" +
-            "      <SecretAccessKey>%s</SecretAccessKey>%n" +
-            "      <SessionToken>%s</SessionToken>%n" +
-            "      <Expiration>%s</Expiration>%n" +
-            "    </Credentials>%n" +
-            "    <AssumedRoleUser>%n" +
-            "      <AssumedRoleId>%s</AssumedRoleId>%n" +
-            "      <Arn>%s</Arn>%n" +
-            "    </AssumedRoleUser>%n" +
-            "  </AssumeRoleResult>%n" +
-            "  <ResponseMetadata>%n" +
-            "    <RequestId>%s</RequestId>%n" +
-            "  </ResponseMetadata>%n" +
-            "</AssumeRoleResponse>",
-        accessKeyId, secretAccessKey, sessionToken, expiration,
-        assumedRoleId, roleArn, requestId);
-  }
+  private String generateAssumeRoleResponse(String assumedRoleUserArn, 
AssumeRoleResponseInfo responseInfo)
+      throws IOException {
+    final String accessKeyId = responseInfo.getAccessKeyId();
+    final String secretAccessKey = responseInfo.getSecretAccessKey();
+    final String sessionToken = responseInfo.getSessionToken();
+    final String assumedRoleId = responseInfo.getAssumedRoleId();
+
+    final String expiration = DateTimeFormatter.ISO_INSTANT.format(
+        
Instant.ofEpochSecond(responseInfo.getExpirationEpochSeconds()).atOffset(ZoneOffset.UTC).toInstant());
 
-  // TODO: this method should be removed once actual credential response from 
OM is implemented and used in the endpoint
-  private String generateRandomAlphanumeric(int length) {
-    String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
-    StringBuilder sb = new StringBuilder();
-    Random random = new Random();
-    for (int i = 0; i < length; i++) {
-      sb.append(chars.charAt(random.nextInt(chars.length())));
+    final String requestId = UUID.randomUUID().toString();
+
+    try {
+      final S3AssumeRoleResponseXml response = new S3AssumeRoleResponseXml();
+      final S3AssumeRoleResponseXml.AssumeRoleResult result = new 
S3AssumeRoleResponseXml.AssumeRoleResult();
+      final S3AssumeRoleResponseXml.Credentials credentials = new 
S3AssumeRoleResponseXml.Credentials();
+      credentials.setAccessKeyId(accessKeyId);
+      credentials.setSecretAccessKey(secretAccessKey);
+      credentials.setSessionToken(sessionToken);
+      credentials.setExpiration(expiration);
+      result.setCredentials(credentials);
+      final S3AssumeRoleResponseXml.AssumedRoleUser user = new 
S3AssumeRoleResponseXml.AssumedRoleUser();
+      user.setAssumedRoleId(assumedRoleId);
+      user.setArn(assumedRoleUserArn);
+      result.setAssumedRoleUser(user);
+      response.setAssumeRoleResult(result);
+      final S3AssumeRoleResponseXml.ResponseMetadata meta = new 
S3AssumeRoleResponseXml.ResponseMetadata();
+      meta.setRequestId(requestId);
+      response.setResponseMetadata(meta);
+
+      final JAXBContext jaxbContext = 
JAXBContext.newInstance(S3AssumeRoleResponseXml.class);
+      final Marshaller marshaller = jaxbContext.createMarshaller();
+      marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
+      final StringWriter stringWriter = new StringWriter();
+      marshaller.marshal(response, stringWriter);
+      return stringWriter.toString();
+    } catch (JAXBException e) {
+      throw new IOException("Failed to marshal AssumeRole response", e);
     }
-    return sb.toString();
   }
 
-  // TODO: this method should be removed once actual credential response from 
OM is implemented and used in the endpoint
-  private String generateRandomBase64(int length) {
-    String chars = 
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-    StringBuilder sb = new StringBuilder();
-    Random random = new Random();
-    for (int i = 0; i < length; i++) {
-      sb.append(chars.charAt((random.nextInt(chars.length()))));
+  private String toAssumedRoleUserArn(String roleArn, String roleSessionName) {
+    // RoleArn format: arn:aws:iam::<account-id>:role/<role-name>
+    // Assumed role user arn format: 
arn:aws:sts::<account-id>:assumed-role/<role-name>/<role-session-name>
+    // TODO - refactor and reuse AwsRoleArnValidator for validation in future 
PR
+    final String errMsg = "Invalid RoleArn: must be in the format 
arn:aws:iam::<account-id>:role/<role-name>";
+    final String[] parts = roleArn.split(":", 6);
+    if (parts.length != 6 || !"arn".equals(parts[0]) || parts[1].isEmpty() || 
!"iam".equals(parts[2])) {
+      throw new IllegalArgumentException(errMsg);
     }
-    return sb.toString();
-  }
 
-  // TODO: this method should be removed once actual credential response from 
OM is implemented and used in the endpoint
-  private String generateSessionToken() {
-    byte[] tokenBytes = new byte[128];
-    Random random = new Random();
-    for (int i = 0; i < tokenBytes.length; i++) {
-      tokenBytes[i] = (byte) random.nextInt(256);
+    final String partition = parts[1];
+    final String accountId = parts[4];
+    final String resource = parts[5]; // role/<name>
+
+    if (Strings.isNullOrEmpty(accountId) || Strings.isNullOrEmpty(resource) || 
!resource.startsWith("role/") ||
+        resource.length() == "role/".length()) {
+      throw new IllegalArgumentException(errMsg);
     }
-    return Base64.getEncoder().encodeToString(tokenBytes);
-  }
 
-  // TODO: this method should be removed once actual credential response from 
OM is implemented and used in the endpoint
-  private String getExpirationTime(int durationSeconds) {
-    Instant expiration = Instant.now().plusSeconds(durationSeconds);
-    return DateTimeFormatter.ISO_INSTANT.format(expiration);
+    final String roleName = resource.substring("role/".length());
+    final StringBuilder stringBuilder = new StringBuilder("arn:");
+    stringBuilder.append(partition);
+    stringBuilder.append(":sts::");
+    stringBuilder.append(accountId);
+    stringBuilder.append(":assumed-role/");
+    stringBuilder.append(roleName);
+    stringBuilder.append('/');
+    stringBuilder.append(roleSessionName);
+    return stringBuilder.toString();
   }
 }
diff --git 
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3sts/S3STSEndpointBase.java
 
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3sts/S3STSEndpointBase.java
index ef753410f94..0de5e6c1374 100644
--- 
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3sts/S3STSEndpointBase.java
+++ 
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3sts/S3STSEndpointBase.java
@@ -56,8 +56,13 @@ public void initialization() {
     S3Auth s3Auth = new S3Auth(signatureInfo.getStringToSign(),
         signatureInfo.getSignature(),
         signatureInfo.getAwsAccessId(), signatureInfo.getAwsAccessId());
+    if (signatureInfo.getSessionToken() != null &&
+        !signatureInfo.getSessionToken().isEmpty()) {
+      s3Auth.setSessionToken(signatureInfo.getSessionToken());
+    }
     ClientProtocol clientProtocol = 
getClient().getObjectStore().getClientProxy();
     clientProtocol.setThreadLocalS3Auth(s3Auth);
+    clientProtocol.setIsS3Request(true);
   }
 
   private AuditMessage.Builder auditMessageBaseBuilder(AuditAction op,
diff --git 
a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3sts/TestSTS.java
 
b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3sts/TestS3STSEndpoint.java
similarity index 51%
rename from 
hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3sts/TestSTS.java
rename to 
hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3sts/TestS3STSEndpoint.java
index 7696bd4d3ed..a78c2c394e5 100644
--- 
a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3sts/TestSTS.java
+++ 
b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3sts/TestS3STSEndpoint.java
@@ -21,25 +21,42 @@
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
 
+import java.io.StringReader;
+import java.time.Instant;
 import javax.ws.rs.container.ContainerRequestContext;
 import javax.ws.rs.core.Response;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import org.apache.commons.lang3.RandomStringUtils;
 import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+import org.apache.hadoop.ozone.client.ObjectStore;
 import org.apache.hadoop.ozone.client.OzoneClient;
 import org.apache.hadoop.ozone.client.OzoneClientStub;
+import org.apache.hadoop.ozone.om.helpers.AssumeRoleResponseInfo;
 import org.apache.hadoop.ozone.s3.OzoneConfigurationHolder;
 import org.apache.hadoop.ozone.s3.signature.SignatureInfo;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.mockito.Mock;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.xml.sax.InputSource;
 
 /**
  * Test for S3 STS endpoint.
  */
-public class TestSTS {
+public class TestS3STSEndpoint {
   private S3STSEndpoint endpoint;
   private static final String ROLE_ARN = 
"arn:aws:iam::123456789012:role/test-role";
   private static final String ROLE_SESSION_NAME = "test-session";
+  private static final String ROLE_USER_ARN = 
"arn:aws:sts::123456789012:assumed-role/test-role/" + ROLE_SESSION_NAME;
 
   @Mock
   private ContainerRequestContext context;
@@ -49,7 +66,19 @@ public void setup() throws Exception {
     OzoneConfiguration config = new OzoneConfiguration();
     config.set(OZONE_S3_ADMINISTRATORS, "test-user");
     OzoneConfigurationHolder.setConfiguration(config);
-    OzoneClient clientStub = new OzoneClientStub();
+    OzoneClient clientStub = spy(new OzoneClientStub());
+
+    // Stub assumeRole to return deterministic credentials.
+    ObjectStore objectStore = mock(ObjectStore.class);
+    when(objectStore.assumeRole(anyString(), anyString(), anyInt(), any()))
+        .thenReturn(new AssumeRoleResponseInfo(
+            "ASIA1234567890123456",
+            "mySecretAccessKey",
+            "session-token",
+            Instant.now().plusSeconds(3600).getEpochSecond(),
+            "AROA1234567890123456:test-session"));
+    when(clientStub.getObjectStore()).thenReturn(objectStore);
+
     endpoint = new S3STSEndpoint();
     endpoint.setClient(clientStub);
     endpoint.setContext(context);
@@ -64,24 +93,39 @@ public void setup() throws Exception {
   @Test
   public void testStsAssumeRole() throws Exception {
     Response response = endpoint.get(
-        "AssumeRole", ROLE_ARN, ROLE_SESSION_NAME, 3600, "2011-06-15");
+        "AssumeRole", ROLE_ARN, ROLE_SESSION_NAME, 3600, "2011-06-15", null);
 
     assertEquals(200, response.getStatus());
 
     String responseXml = (String) response.getEntity();
     assertNotNull(responseXml);
-    assertTrue(responseXml.contains("AssumeRoleResponse"));
-    assertTrue(responseXml.contains("AccessKeyId"));
-    assertTrue(responseXml.contains("SecretAccessKey"));
-    assertTrue(responseXml.contains("SessionToken"));
-    assertTrue(responseXml.contains("AssumedRoleUser"));
-    assertTrue(responseXml.contains(ROLE_ARN));
+
+    // Parse response XML and verify values
+    final DocumentBuilderFactory documentBuilderFactory = 
DocumentBuilderFactory.newInstance();
+    documentBuilderFactory.setNamespaceAware(true);
+    final DocumentBuilder documentBuilder = 
documentBuilderFactory.newDocumentBuilder();
+    final Document doc = documentBuilder.parse(new InputSource(new 
StringReader(responseXml)));
+
+    final Element root = doc.getDocumentElement();
+    assertEquals("AssumeRoleResponse", root.getLocalName());
+
+    final String accessKeyId = 
doc.getElementsByTagName("AccessKeyId").item(0).getTextContent();
+    assertEquals("ASIA1234567890123456", accessKeyId);
+
+    final String secretAccessKey = 
doc.getElementsByTagName("SecretAccessKey").item(0).getTextContent();
+    assertEquals("mySecretAccessKey", secretAccessKey);
+
+    final String sessionToken = 
doc.getElementsByTagName("SessionToken").item(0).getTextContent();
+    assertEquals("session-token", sessionToken);
+
+    final String arn = 
doc.getElementsByTagName("Arn").item(0).getTextContent();
+    assertEquals(ROLE_USER_ARN, arn);
   }
 
   @Test
   public void testStsInvalidDuration() throws Exception {
     Response response = endpoint.get(
-        "AssumeRole", ROLE_ARN, ROLE_SESSION_NAME, -1, "2011-06-15");
+        "AssumeRole", ROLE_ARN, ROLE_SESSION_NAME, -1, "2011-06-15", null);
 
     assertEquals(400, response.getStatus());
     String errorMessage = (String) response.getEntity();
@@ -91,7 +135,7 @@ public void testStsInvalidDuration() throws Exception {
   @Test
   public void testStsUnsupportedAction() throws Exception {
     Response response = endpoint.get(
-        "UnsupportedAction", ROLE_ARN, ROLE_SESSION_NAME, 3600, "2011-06-15");
+        "UnsupportedAction", ROLE_ARN, ROLE_SESSION_NAME, 3600, "2011-06-15", 
null);
 
     assertEquals(400, response.getStatus());
     String errorMessage = (String) response.getEntity();
@@ -101,10 +145,34 @@ public void testStsUnsupportedAction() throws Exception {
   @Test
   public void testStsInvalidVersion() throws Exception {
     Response response = endpoint.get(
-        "AssumeRole", ROLE_ARN, ROLE_SESSION_NAME, 3600, "2000-01-01");
+        "AssumeRole", ROLE_ARN, ROLE_SESSION_NAME, 3600, "2000-01-01", null);
 
     assertEquals(400, response.getStatus());
     String errorMessage = (String) response.getEntity();
     assertTrue(errorMessage.contains("Invalid or missing Version parameter. 
Supported version is 2011-06-15."));
   }
+
+  @Test
+  public void testStsPolicyTooLarge() throws Exception {
+    final String tooLargePolicy = 
RandomStringUtils.insecure().nextAlphanumeric(2049);
+
+    final Response response = endpoint.get(
+        "AssumeRole", ROLE_ARN, ROLE_SESSION_NAME, 3600, "2011-06-15", 
tooLargePolicy);
+
+    assertEquals(400, response.getStatus());
+    final String errorMessage = (String) response.getEntity();
+    assertTrue(errorMessage.contains("Policy length exceeded maximum allowed 
length of 2048"));
+  }
+
+  @Test
+  public void testStsInvalidRoleArn() throws Exception {
+    final String invalidRoleArn = 
"arn:awsNotValid::123456789012:role/test-role";
+    final Response response = endpoint.get(
+        "AssumeRole", invalidRoleArn, ROLE_SESSION_NAME, 3600, "2011-06-15", 
null);
+
+    assertEquals(400, response.getStatus());
+    final String errorMessage = (String) response.getEntity();
+    assertTrue(
+        errorMessage.contains("Invalid RoleArn: must be in the format 
arn:aws:iam::<account-id>:role/<role-name>"));
+  }
 }
diff --git 
a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3sts/package-info.java
 
b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3sts/package-info.java
new file mode 100644
index 00000000000..27318a15520
--- /dev/null
+++ 
b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3sts/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Unit tests for the s3 sts endpoint.
+ */
+package org.apache.hadoop.ozone.s3sts;


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


Reply via email to